You Only Live Once: Attempting to Solve Canon EOS 5D MK II Error 30 by replacing Shutter MYSELF #YOLO…

So… you got Error 30 when trying to take a picture with your fancy Canon SLR camera. What do you do ? How much internet have you scoured for this answer? Sadly, probably not enough. This will hopefully be your final stop that push to you to realize the grim reality… However, despite that, I hope this will document the trials and what I have gone through so MAYBE, you will make the right decision a bit easier... Sorry, there is no magic bullet. TLDR: you will want to send it in to Canon for service, pronto and not attempt self repair. Listen to me, and do not try to do it yourself as I did… While I did not break the camera, I certainly did not improve the situation and if you want to try your luck, consider reading everything thoroughly before you continue, especially the part about back flange distance record keeping….


Some motivation for possibly wanting to do this challenging task:

  1. You want to save money (TLDR: terrible idea…). It will cost you more, because what you break might end up cost more…(e.g. if you almost damaged main board like what I did, salvaged parts cost $200 USD alone, not far from the service cost.)
  2. You feel too cheap to call Canon to fix a 10 years old camera and you feel you have nothing to lose even if it doesn’t work (TLDR: better but still bad idea. However, have the will to be prepared to lose everything is key to zen)
  3. You want to challenge yourself to fix things no one else dare to try. (TLDR: better idea, this is what mostly motivated me, also reason 2).
  4. You are curious because you want to see inside of a SLR and understand how everything works. You will get plenty of this but it is not worth it.

Ultimately, if not for curiosity, it is not worth it. Because what Jens Bjørn Andersen said in the comment section of the original timelapse video of disassembly/reassembly and I quote below:

I’m Canon technician (for 34 years), and have replaced many shutters in EOS 5 D mk 2, BUT it is not possible to do it “at home”. The problem is, that the Cmos have to be adjusted after removement. To do this you need at Canon’s Flange Back Tester (cost $20,000) to adjust the flange back distance and to align the CMOS with the lens mount. If not adjusted correct you will have auto focus problems. This FB tester adjust the sensor with an accuracy of 0.000001m.

In THEORY, you can bypass this issue if you can record the precise number of turns and made prior marking to align the screws with the perfect amount of torque but realistic, this is the part that no one can do at home to get it right and require a flange back measuring device only available at Canon service facilities.

Major Tips:

  • You need Philips 000 and Torx 7. A precision driver set (like this) is HIGHLY recommended as the weakly magnetic kit is super helpful in tight spots. Also, those plastic pliers are less likely to damage tabs unlike metal tweezers.
  • Use masking tape (or something similar sticky but not too strong) to keep track of all the screwed in the order you removed them (see the green masking strips below). Also help to draw the location and the shape of the parts so it is easier to retrace your steps.
  • Best to videotape the entire process overhead as well.
  • Have clear, resealable unused sandwich bags ready. The moment a sensitive component is extracted, you can save them there to ensure it does not get damaged or filled with dust. This allowed me to work slower over days without worry about dust accumulation (while technically I really should do this in a dustless cleanroom but I am lazy).
  • Expect about 5 to 6 hours of painstakingly taking apart everything until the shutter box can be replaced. Another 3 to 5 hours to resemble everything IF nothing goes wrong.
  • Go SLOW. First time unscrewing those Philips screws can be so very very hard. Apply lots of downward pressure and go slow while using flatter head Philips 000 drivers (less pointy). If you strip any screws, it will be very bad for business very soon. Maybe try to elastic band trick by using a flat elastic band placed on top of the screw to substantially increase the friction. Avoid stripping screws at ALL COST.

Some Background Info about Error 30 in Canon SLR:

  • Happens most commonly related to STUCK shutter.
  • Can be a sign of imminent shutter failure, never trust that camera again for jobs unless you are prepared to lose shots.
  • Some known fixes (at least temporarily):
    • Smack the camera physically (not joking): physical shock can be used dislodge the shutter. Given that 5D2 are built like a tank, I did give it a try. No working.
    • Some have claimed replacing the 3V cell battery on the left bottom corner of the camera. Mine was still 3V after literally years post manufacturing, so no go.
    • Use the “Manual Clean” the sensor. This actually cause my camera to freeze up.
    • Ultimate fix: replace the shutter (this will probably solve 90%+ of all the Error 30. However…
    • The real ultimate fix (for my 5DII at least) is most likely one of the electronic board replacement. I replaced my shutter with another shutter BUT I am still getting the same Error 30. The most likely cause is not shutter for several reasons:
      • Error 30 at 45K shutter is too low for something normally rated at 150K.
      • The original shutter “looks normal”. Nothing bent or distorted. Although I cannot move it (have to unmount motor most likely) but if you look at other broken shutter, you can clearly tell something went wrong. For example, 1 or 2, or 3. The chance of both my “old” shutter and “new” replacement shutter are dead while “physically” looking descent is pretty small, and this coupled with the earlier point.
  • Something particular about what I tried was that when I use “manual sensor clean” the mirror is suppose to go up and shutter 100% open but it totally did not work. I get Error 30 instead. This suggest some kind of lower level motor controller issue with the shutter but I already replaced it so I suspect it is the bottom board that needs replacement. If anyone has any additional full insight, I would love to hear. I already popped 80$ to gamble on shutter and now have a most likely spare shutter…I rather not take another 80$ plunge on a board that may be in tact.

Useful References:

You probably read most of these already. If you still want to do it, at least scrub through the timeline and realize the daunting task ahead of you.

High Level Steps

At each step, check all cables and remove them slowly and carefully, when not sure, check the referenced videos.

  • Take off all superficial screws after removing glued plastic (they go back perfectly).
  • Remove bottom, left and right plastic pieces.
  • Remove back LCD integrated piece.
  • Remove top LCD integrate piece.
  • Remove main board (3~4 screws).
  • Remove top right board.
  • Remove bottom main structural plate
  • Loosen bottom board (two of them are good).
  • Remove main structural plate (7?8 screwns?).
  • Remove sensor (3 screws).
  • Remove battery/SD compartment (secured on the right side of front handle with two screws)
  • Remove shutter

[Deep Dive] The Deep Annoying Dark Art of Configuring an Azure Serverless API Functions to be authenticated with Azure B2C Active Directory Configuration Policy…

I used to think Git was hard to learn, then GitKraken made it easy (tip fedora). Then, I ran into Azure configuring beast. I literally sunk about 2 to 3 days alone just reading blogs, LinkedIn training videos, trying, failing, crying, grieving, therapy session, taking a walk, adopting a pet, watching it die of old age, before I figured out how to configure this monster (jk about pet dying part, except my hair).

I now write it down as a reflection of my torment, suffering in the hope that it will hope enlightening the future generation and maybe, result in them suffering a bit less.

I saw many similar guide but not EXACTLY what I was trying to do. The problem itself is not challenging but to FIND the right information to put into the right field, turned out to be SUCH a unnecessarily challenging task. This is also probably not helped by the fact that I am not super familiar with Azure system and new to serverless and new to Active Directory etc. But hey, you probably stumbled here because you were in similar boat….

This will be work in progress article updated over time.

Let’s start with some key assumptions:

  1. The Azure Serverless app is already running without any authentication. In my case, I build a VERY simple azure serverless app to return the MD5 code of the image uploaded to the end point. There are many guide on how to build simple Serverless app, I will not elaborate on those. You came here most likely related to the configuration/authentication issue anyway, if not, check out the microsoft guide here:
  2. You have an Azure account of some sort. This is where configuration confusion madness begins… I thought I was the only one but apparently, not. See this post of Tsuyoshi experiencing similar kind of confusion, especially its 1st figure:

High level overview of the steps:

Section 1: Azure AD B2C

  • Create Azure AD B2C
    • This AD B2C stores the customers’ data and keep it separate from staff data of the organization.
  • Create an account for the Azure AD B2C
    • Might be optional. Need to test out more. As long as you have an account that can access the B2C application, you should be okay here.
  • Use that account to create an Azure AD B2C app
    • A app MUST be created AND registered to access the Azure AD B2C
  • Register the Azure AD B2C app
    • A app MUST be created AND registered to access the Azure AD B2C
  • Create a policy for the app
    • Policy is required to set scope etc and obtain the end point.
  • Get the Policy Properties page
    • This page contain the endpoints which the request will be made to.

Section 2: Azure Serverless Function

  • Create the App and Deploying to Azure Portal
    • This app does what you need, for my example, I used a MD5 hash returning to ensure they processed the uploaded data.
  • Enable authentication
    • Set up the proper setting using information from the Azure AD B2C app.

Section 3: Final Testings

  • Postman use OAuth2.0 to get Access Token: https://{Your App Name}{Your Function Name}/
  • Use the ID token as bear token to access service.

Detailed Steps to Connecting Azure AD B2C with Azure Function

Updated as of 2019-12-29T085916EST

Section 1 Azure AD B2C: Create Azure AD B2C tenant

See the source guide:

In short:

  1. On the Azure portal menu or from the Home page, select Create a resource.
  2. Search for Azure Active Directory B2C, and then select Create.
  3. Select Create a new Azure AD B2C Tenant
  4. Enter an Organization name and Initial domain name. Select the Country or region (it can’t be changed later), and then select Create.
  5. Once the tenant creation is complete, select the Create new B2C Tenant

Select B2C Tenant Directory (same Source):

  • To start using your new Azure AD B2C tenant, you need to switch to the directory that contains the tenant.
  • Select the Directory + subscription filter in the top menu of the Azure portal, then select the directory that contains your Azure AD B2C tenant.
  • If at first you don’t see your new Azure B2C tenant in the list, refresh your browser window, then select the Directory + subscription filter again in the top menu.

Section 1 Azure AD B2C: Create a new account within that AD B2C

  • For testing purposes…
  • Not 100% sure if it is necessary.

Section 1 Azure AD B2C: Create “Application”

See the source guide at:

  1. Sign in to the Azure portal.
  2. Make sure you’re using the directory that contains your Azure AD B2C tenant. Select the Directory + subscription filter in the top menu and choose the directory that contains your tenant.
  3. Choose All services in the top-left corner of the Azure portal, and then search for and select Azure AD B2C.
  4. Select Applications, and then select Add.
  5. Enter a name for the application. For example, webapi1.
  6. For Include web app/ web API and Allow implicit flow, select Yes.
  7. For Reply URL, enter an endpoint where Azure AD B2C should return any tokens that your application requests. In your production application, you might set the reply URL to a value such as https://{REPLACE YOUR APP NAME NERE!}/.auth/login/aad/callback
  8. For App ID URI, enter the identifier used for your web API. The full identifier URI including the domain is generated for you. For example, https://{REPLACE YOUR ORG NAME HERE}
  9. Click Create.
  10. On the properties page, record the application ID that you’ll use when you configure the web application.

Section 1 Azure AD B2C: Obtain Application ID (aka Client ID):

Refresh the page to visit the app in Azure AD B2C. Under General -> Properties to your left, then copy the Application ID. This will be used later in configuring the Azure Function App.

Section 1 Azure AD B2C: Obtain Keys (aka Client Secret):

Refresh the page to visit the app in Azure AD B2C. Under General -> Keys to your left, then click generate key. Save and the key will appear, these later as it will be part of the necessary information to obtain the Access Key.

Section 1 Azure AD B2C: Register the App

(Source :

  1. Sign in to the Azure portal.
  2. Select the Directory + Subscription icon in the portal toolbar, and then select the directory that contains your Azure AD B2C tenant.
  3. In the Azure portal, search for and select Azure AD B2C.
  4. Select Applications, and then select Add.
  5. Enter a name for the application. For example, webapp1.
  6. For Include web app/ web API and Allow implicit flow, select Yes.
  7. For Reply URL, enter an endpoint where Azure AD B2C should return any tokens that your application requests. https://{REPLACE YOUR APP NAME NERE!}/.auth/login/aad/callback
  8. Select Create to complete the application registration.

Section 1 Azure AD B2C: Create an policy for the app.

Source Guide:

In short,

  1. Sign in to the Azure portal.
  2. Select the Directory + Subscription icon in the portal toolbar, and then select the directory that contains your Azure AD B2C tenant
  3. In the Azure portal, search for and select Azure AD B2C.
  4. Under Policies, select User flows (policies), and then select New user flow.
  5. On the Recommended tab, select the Sign up and sign in user flow.
  6. Enter a Name for the user flow. For example, signupsignin1.
  7. For Identity providers, select Email signup.
  8. For User attributes and claims, choose the claims and attributes that you want to collect and send from the user during sign-up. For example, select Show more, and then choose attributes and claims for Country/RegionDisplay Name, and Postal Code. Click OK.
  9. Click Create to add the user flow. A prefix of B2C_1 is automatically appended to the name.

Section 1 Azure Ad B2C: Get the Policy Properties Page:

Refresh the page to visit  Azure AD B2C. On the left, click on User Flows (policies), then create the policy created in the previous step. On the left side, click on properties, on the right blade, click on “Run user flow”. This should open a new blade, which at the top that list a url like: https://{YOUR B2C NAME}{YOUR B2C NAME}{YOUR POLICY NAME}/v2.0/.well-known/openid-configuration.

Click on that to open a new tab with a XML listing the key endpoints, take note of the following, as you will need them to request the Access token:

"issuer": "https:///{YOUR B2C NAME}{ID}/b2c_1_api_authentication/v2.0/",
"authorization_endpoint": "https:///{YOUR B2C NAME}{YOUR B2C NAME}{YOUR POLICY NAME}/oauth2/v2.0/authorize",
"token_endpoint": "https:///{YOUR B2C NAME}{YOUR B2C NAME}{YOUR POLICY NAME}/oauth2/v2.0/token",

Section 2 Azure Serverless Function: Create the function and publishing the function.

This part there are many tutorial. I highly recommend this one using visual studio 2019 to directly publish:

The goal of this section is to get an app deployed and configured with Azure Portal such that http://{Your App Name} is at least working. and you tested it by calling it (without authentication and works).

Make sure to test this in the Postman to ensure the endpoint etc is all setup. Google “Azure Function Serverless API tutorial” etc to see tons of guide about how to setup one up. You need at least a kind of hello world app deployed on the http://{Your App Name} 

Good luck.

Section 2 Azure Serverless Function: Update security:

Refresh the page, go to the Function Apps in All Resources. Click on the app on the left, click on the Platform Features tab to access the authentication / authorization  in the networking group of links. It is most likely set to OFF currently. Switch it to ON and in the below. You should see the first two figures from this blog: Except, we are not using Facebook for the Azure Serverless authentication/authorization.

Under “Action to take when request it not authenticated”, best to change it to log into Azure Active Directory. Then under the authentication providers, click on Azure Active Directory (which should say Not Configured?).

The new blade should give three choices: Off, Express, Advanced. I wasted about 3 days playing with express but that won’t work with Azure AD B2C as far as I tried.

Switch to Advanced.

  • Client ID: use the application ID you created at the Azure AD B2C earlier.
  • Issuer URL: use the issuer URL from the Azure AD B2C Policy Properties section.
  • Client Secret: use the keys that were generated earlier in Azure AD B2C application section.

That is it. Click okay to save.

Now, the testing part is also equally absurdly obscure.

Section 3 Postman Testing: Getting the Access Token

Create a new post request to the app with the proper endpoint which has PROVEN to work BEFORE you added the authentication. For me it was like

https://{Your App Name}{Your Function Name}/

Go to the Auth tab in the post man for this request.

Set authorization type to OAuth 2.0

Add auth data to “Request Headers”

Then click on the Get New Access Token.

Date/time stamp the token name so you can remember it.

  • Grant type: Authorization Code
  • Callback URL: https://{YOU APP NAME}
  • Auth URL / Access Token URL: Use the information obtained from: Azure AD B2C Policy Properties Page.
  • Client ID: use the application ID you created at the Azure AD B2C earlier.
  • Client Secret: use the keys that were generated earlier in Azure AD B2C application
  • Scope: must used OpenID. Not really sure why. But this was the ONLY scope that worked for me. Similarly, this was indicated in the Policy properties page.
  • State: leave empty.
  • Client Authentication: Send client credentials in body.

Click on request token and you WILL see a new browser window that you can login with any credential in your AD B2C and receive a token BACK!

However, the token you get back is only an id_taken and does not populate the Access Taken field built into Postman. Hence, you have to manually copy and paste the token in a separate request (as bearer token) to get access to the API.

BTW. MAKE SURE THERE IS NO SPACE/NEW LINE CHARACTER at the end of your id_token when copying and pasting as I wasted about 2 days debugging this…

Section 3 Final Testing: Using the Access Token: 

So, if all of  these go as well as hoped, you have properly setup your Azure Function Serverless to authenticate against the Azure AD B2C directory. And this is trigger both at HTTP regular traffic level and as well as API interactions. However, this is merely a super rough proof of concept to show how everything interlock. Usability is still crap and a lot edges can be improved to provide usable endpoints and user experience. In my case, I was able to upload the data of the image and have Azure Function process that to return a MD5 hasb in text form along with a few other things such as some additional parameters sent over. I verified that I get the same results as my local testing against the same end points versus the remote endpoints.

I will revisit the guide to improve its usability in a bit.

Additional relevant references:

  • A simple guide about getting a quick Azure Function app up and authenticate it with Okta:

Version 1 published: 2019-12-22T164554EST.

Version 2 published: 2019-12-29T085926EST


Azure Function x64 Gotcha

This was super annoying when I ran into it.

I was playing with Azure function for a bit and because our app needs to be 64 bits for dependency reason, I made a simple Azure Function v2 to apply the serverless technology for this situation.

However, what was working as a straight copy and paste working app now stopps working somehow. For no reasons at all.

All I did was changing the build to x64 from x86 and it stopped and died with errors similar to this:

[2019-12-22 19:30:04] A host error has occurred during startup operation '2236efae-de7b-4b80-9569-a009ede8c172'.
[2019-12-22 19:30:04] System.Private.CoreLib: Could not load file or assembly 'AzureIntegration, Version=, Culture=neutral, PublicKeyToken=null'.

With NO OTHER details whatsoever.

It turned out, by default Visual Studio 2019 create 32 bit Azure Function projects and if I change it to x64 bits, the AzureFunction CLI for local debugging needs to be x64 bit as well. So, follow this guide fixed the problem:

Basicly, download the x64 release of the azure function core tool and then set “Debug” to launch executable, pointing to the func.exe from the download and then add application arguments of “host start” and then it is all launching fine!

Really hope this will not be an issue in the future.

Thanks to Henk Boelman’s blog entry to point me to start at least investigating the x64 as the beginning of this issue:


Pro Tip for Easier Time Reconsiling/Accounting Transactions

I might have posted this before, but if you ever keep track of your own personal finance using software/excel/YNAB/Mint/whatever, especially when it comes to transfer between accounts (does not , it is always better than use weird specific amount than whole amount.

For instance, if you need to transfer $500 fom to your life of credit to bank account, try to transfer 521.12 or some non-integer numbers so the chance of this transaction being unique is much higher. This way, you will never have to worry about mixing transactions. Avoid 100, 1000, 500 etc amount as once the number of accounts and transactions scale over time, it can be super confusion and lead to much later issues when reconsiling whether that 100$ was the one you sent to Joe or the one you transferred to your saving or the 100$ that you were putting towards your retirement.

Most importantly, it makes subsequent search so much easier.


BitBucket SourceTree and AzureDevOps Credential Setup.

This was unnecessarily annoying.

If you have a private GitHub repositories that you would like to hook up to a Git GUI, GitKraken would have been my primary choice but they need pro account for that to happen. However, SourceTree is free for Azure DevOps. BUT, its setup never seems to work somehow, it turned out to be related to bad URL in HTTPS setup.

For detail see this post:

TLDR: use “https://*username*” in the address field for BitBucket SourceTree instead of anything like*username* or whatever long URL you might have copied from Azure Devops portal.


Python Flask Image

I have been following this wonderful Flask Mega Tutorial by Miguel Grinberg and really learned a lot about developing and deploying Flask for my work.  Highly recommend for those want to  build simple flask website that scale okay.

What has been bugging me FOREVER about it, was why that particular ancient artifact” image for his tutorial. How is that related to flask? Namely, this:

Powder flask

Image Credit: Left:, right Miguel obviously :D.

It turned out to be a 1600 era gun powder flask, as shown here: and also seems HIGHLY unique one of a kind, as well. I was pointed there through this Pinterest Pin:

So it makes sense, because we were using Gunicorn to deploy, it needs ammunition (content) which was served via gun powder Flask.


Also, this looks so much like AK47 gun magazines, just saying.


“selenium.common.exceptions.SessionNotCreatedException: Message: session not created: No matching capabilities found”

I had been banging my head on this error for literally DAYS. Why is Selenium rejecting to launch? I past it some Options but why is it refusing to even launch????

Turned out,

I did this:

from selenium.webdriver.firefox.options import Options

and tried to past it to a Chrome WebDriver as “Options” when I should have imported

from import Options

I am not a smart man…

I was googling so much and the top Google results mentioned using OperaDrivers, using Edge Drivers etc and running into similar issues. Most likely, some sort of configurations are past wrong. In my case, it was very obvious. I even went digging into ChromeDriver vs Chrome version compatibility issue (just leave TravisCI to ensure their compatibility but print out versions explicitly doesn’t hurt… either)


Quick shallow insight into ML related workflow management packages as of 2019-11-11T204512EST

This is a very early draft of the information I have gathered all over the internet. I am interested and are in the process of checking the highlighted features. However, so far, MLFlow seems to be winning out and its interest are actually on PAR with KubeFlow (given how KubeFlow is much more… general purpose, this seems like a massive surprise).


Interestingly, outside of MLFlow, the other competitiors seems to be really having a PR issue. I had to exclude Spell and Pachyderm because of word commoness. Therefore, I will most likely be exploring MLFlow to hope gain some expertise with it in the upcoming days.




Annoying MLFlow Artifact Servicing Tutorial Windows Bug

So I was following the otherwise excellent MLFlow official tutorial on Windows and keep running into this annoying bug while attempting to serve the model:

mlflow.exceptions.MlflowException: Could not find a registered artifact repository for: c:/XXXX/XXXXX/data_mlflow/mlflow/examples/sklearn_elasticnet_wine/mlruns/0/
b02a6befa2824c339891b088803b723e/artifacts/model. Currently registered schemes are: [”, ‘file’, ‘s3’, ‘gs’, ‘wasbs’, ‘ftp’, ‘sftp’, ‘dbfs’, ‘hdfs’, ‘viewfs’, ‘runs’, ‘models’]”

I was like… WTF? I am following the official tutorial word by word without any typing and how could it brick???

It turned out to be an issue with MLFlow not handling path very well on Windows (probably should have used pathlib?

The issue as pointed in the GitHub issue here:

As pointed out by enpinzolas, you should replace prefix “C:/xxxx” in the path string with “file://C:/xxxx”.

This fixed it for me and I was able to serve the training example properly.

In hindsight, the error message makes sense. “C:” was not in that list given. “file:” is. They REALLY should have better parsed that link.  Most likely because the nature of the adaptability. A small PR should be in order to fix this.