tag:blogger.com,1999:blog-71252033818043242792024-03-26T04:23:16.476-07:00cmheong's blogcmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.comBlogger119125tag:blogger.com,1999:blog-7125203381804324279.post-89359741126984302692024-01-23T06:18:00.000-08:002024-01-23T06:19:34.237-08:00Internet Server Blues: Serveo, Public IP, CGNAT and Accessing Your Servers from the Internet<p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIKJ5NdjfZeAUtsQVxmXB8zSUDBDHx17rKEE9eZT5CIhQJ6LBGBbXVBxLzMowC9DQ9l4SYFf398klTES9rd-QlYa_obk8brBoi0ChVDk-z3-RdpE4Gp9NwzK3NvktSa8uxB3pWkHXk_nCFjYqmIT_lqClMaIDaylRkU0rF0Z6l2sSw6Q-xYg9rx9Z-Ip1I/s1106/connection_timed_out.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="508" data-original-width="1106" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIKJ5NdjfZeAUtsQVxmXB8zSUDBDHx17rKEE9eZT5CIhQJ6LBGBbXVBxLzMowC9DQ9l4SYFf398klTES9rd-QlYa_obk8brBoi0ChVDk-z3-RdpE4Gp9NwzK3NvktSa8uxB3pWkHXk_nCFjYqmIT_lqClMaIDaylRkU0rF0Z6l2sSw6Q-xYg9rx9Z-Ip1I/w547-h251/connection_timed_out.png" width="547" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Connection timeout</td></tr></tbody></table><br />For over 2 <b>decades</b> I ran servers from my home. Before the github and the weblog, a personal website is a handy way to keep documents you might need to access. An IP camera might also need to act as a home server. An ssh server, when available over the Internet, turned to be a very handy way of piercing firewalls at work. Later, IoT devices also needed a server.<p></p><p>In practice this means whenever your modem router logs into the Internet your service provider provides it with an IPv4 public IP address. </p><p>Then came NAT, a real blessing. Suppose you have several home computers all using the Internet at the same time. NAT software, usually running on your modem-router, uses just a single public IP address for all your computers, thus saving you from having to get multiple Internet lines. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiydDlQaoEvq5Q1yscAhAB15h5iu6H1AHtEcnrjGubidVtez3mMr-2IQjnOMGt9Aj1cbNr0Gwov2uEh9rO5reyTVg5UCuiVukGn8NeebNfZeAFQ57eXiCyKxgOD5m5WifKNls0AG4Hfk8cgt3K9jMaAaSstGDBM3k1Hw45O4aHD88se-5IyHtZlG6AWvWgT/s1024/NAT.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="576" data-original-width="1024" height="302" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiydDlQaoEvq5Q1yscAhAB15h5iu6H1AHtEcnrjGubidVtez3mMr-2IQjnOMGt9Aj1cbNr0Gwov2uEh9rO5reyTVg5UCuiVukGn8NeebNfZeAFQ57eXiCyKxgOD5m5WifKNls0AG4Hfk8cgt3K9jMaAaSstGDBM3k1Hw45O4aHD88se-5IyHtZlG6AWvWgT/w538-h302/NAT.png" width="538" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">NAT or Network Address Translation</td></tr></tbody></table><p><br /></p><p>The Internet servers replying to your computers think there is just one computer, represented by your public IP. Your NAT intercepts these replies and routes them accurately to your individual computers </p><p>Your internal servers have the problem in reverse. To a device in the Internet all of them have the same (ie your public IP) address. This is resolved by having each server use a unique number, a port (1 of 65536 available) to identify itself. Kind of like having room numbers in your house for every occupant. Based on this an incoming request is forwarded by the router to the correct server. The router also watches for the resulting replies and forwards them to the numerous (potentially) Internet devices. This is called Port Forwarding.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRYKXx2vm1_P7Uq7DwlxEw-xsjYtDskwXezJeShdbc-XM86kyLsaIo8XHTVfDnQ6VQ8eJB3uOdSv2Zd5mAu7OfWQe06lYKCeLsmCCBGNqM-28MtVTolVRFrRPdlbAcAfqzMdUSBQ8R0SMKmGlhZ6aeo_0fyxfYqm_v5ya2ada0tumedLKBjBa6gSgS-GmI/s1920/PortForwarding.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="960" data-original-width="1920" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRYKXx2vm1_P7Uq7DwlxEw-xsjYtDskwXezJeShdbc-XM86kyLsaIo8XHTVfDnQ6VQ8eJB3uOdSv2Zd5mAu7OfWQe06lYKCeLsmCCBGNqM-28MtVTolVRFrRPdlbAcAfqzMdUSBQ8R0SMKmGlhZ6aeo_0fyxfYqm_v5ya2ada0tumedLKBjBa6gSgS-GmI/w536-h268/PortForwarding.png" width="536" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Port Forwarding</td></tr></tbody></table><br /><p>Thus all servers implicitly use different ports. For example http servers use port 80, https use port 443 and ssh uses port 22.</p><p>Sometime in 2022, outside access to my servers was blocked. My service provider <a href="https://soyacincau.com/2021/10/13/tm-unifi-public-ip-broadband-customers-cgnat-lsn-implementation/?utm_medium=Social&utm_source=Facebook#Echobox=1634125212">Unifi had implemented CGNAT</a>. <a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT">CGNAT</a> is Carrier Grade NAT. This means the service provider has grouped anything from tens to hundreds of subscribers into one Public IP using its own NAT upstream.</p><p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiCZHdXASFLUW2sStsRgW5lF_BOawvIWOb_oAdzTDZcPkjpG-iGcLn8QkGPujRtH3ylvfjTiBvv86d4zzq6xQTwwVa-Yf_x85_T8QVToM-mgPSJLlktUEQHAMVv1lM9IS5SOrSVBzFRAAaCiJU4rLFwHONoqdFertoVXDhJUFrNtZ_OHCTUHe09IvdkKev/s800/cgnat.webp" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="456" data-original-width="800" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiCZHdXASFLUW2sStsRgW5lF_BOawvIWOb_oAdzTDZcPkjpG-iGcLn8QkGPujRtH3ylvfjTiBvv86d4zzq6xQTwwVa-Yf_x85_T8QVToM-mgPSJLlktUEQHAMVv1lM9IS5SOrSVBzFRAAaCiJU4rLFwHONoqdFertoVXDhJUFrNtZ_OHCTUHe09IvdkKev/w529-h301/cgnat.webp" width="529" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Carrier Grade Network Address Translation, or CGNAT</td></tr></tbody></table><br />One immediate effect is many professional servers now receive a great deal of traffic from a single IP and this triggers their DDOS protection which often wants confirmation or verification before you can access their site.<p></p><p>The other problem is my provider Unifi has chosen not to limit but to block Port Forwarding. Unless I paid extra for a Public IP or a Static IP. Internet requests now no longer work. Internally on my private LAN they still work as before.</p><p>The obvious alternative is to pay for a cloud server with a Public IP, like AWS, Google Cloud, Microsoft Azure, etc.</p><p>Another alternative is often <a href="https://ngrok.com/">ngrok</a>, which will forward ports to you for free using an ssh trick called Reverse Tunnelling. <b>Unless</b> you want to use your own domain name then there is a small fee.</p><p>But best of all is <a href="https://serveo.net/">Trevor Dixon's serveo</a>. It does ssh reverse tunnelling for free and will also allow unique, readable names. Buy Trevor a coffee sometime - he deserves it.</p><p>Say you already have an Apache webserver at port 80 - this makes it an insecure (ie not https) webserver. With serveo there is no need for logins and registrations, you just dive straight in with a reverse tunnel:</p><p>$ ssh -R cmheong:80:localhost:80 serveo.net </p><p>The authenticity of host 'serveo.net (138.68.79.95)' can't be established.</p><p>RSA key fingerprint is SHA256:07jcXlJ4SkBnyTmaVnmTpXuBiRx2+Q2adxbttO9gt0M.</p><p>Are you sure you want to continue connecting (yes/no)? yes</p><p>Warning: Permanently added 'serveo.net,138.68.79.95' (RSA) to the list of known hosts.</p><p>To request a particular subdomain, you first need to generate a key. Use the command</p><p>ssh-keygen to generate your key. For more information about generating and using </p><p>ssh keys, see https://www.ssh.com/academy/ssh/keygen. Once you've generated a key, try again, and these instructions will be replaced with instructions on how to register your key with serveo. </p><p>Forwarding HTTP traffic from https://afc2076be26e6b5cc4b2ff5c4348336f.serveo.net</p><p><br /></p><p>Over at your browser, http now works:</p><p>http://afc2076be26e6b5cc4b2ff5c4348336f.serveo.net:80</p><p>The bonus is https, too works without modification and the browser will not flag it as insecure:</p><p>https://afc2076be26e6b5cc4b2ff5c4348336f.serveo.net:443</p><div>The icing on the cake is subdomains. You just make an ssh key pair (if you do not already have one)</div><div><div><br /></div><div>$ ssh-keygen -t rsa </div><div>Generating public/private rsa key pair.</div><div>Enter file in which to save the key (/home/heong/.ssh/id_rsa): </div><div>Enter passphrase (empty for no passphrase): </div><div>Enter same passphrase again: </div><div>Your identification has been saved in /home/heong/.ssh/id_rsa.</div><div>Your public key has been saved in /home/heong/.ssh/id_rsa.pub.</div><div>The key fingerprint is:</div><div>SHA256:AbCdEfGhIjKlMnOpQr123456789 cmheong@webserver</div></div><div><br /></div><div>With your new key you now do:</div><div><br /></div><div><div>$ ssh -R cmheong:80:localhost:80 serveo.net </div><div>To request a particular subdomain, you first need to register your SSH public key.</div><div>To register, visit one the addresses below to login with your Google or GitHub account. </div><div>After registering, you'll be able to request your subdomain the next time you connect </div><div>to Serveo. </div><div><br /></div><div>Google: https://serveo.net/verify/google?fp=SHA256%3AAbCdEfGhIjKlMnOp%2BQr123456789</div><div>GitHub: https://serveo.net/verify/github?fp=SHA256%3AAbCdEfGhIjKlMnOp%2BQr123456789</div></div><div><br /></div><div>So you need to register your key with serveo. I used my Google account. But notice serveo has modified your key fingerprint slightly (inserted %3A and %2B) so just paste serveo's output (not your sshkey-gen output) onto your browser. Assuming you have already logged into your Google account this works rightaway.</div><div><br /></div><div>If you re-do your reverse tunnel again:</div><div><br /></div><div><div>$ ssh -R heong:80:localhost:80 serveo.net</div><div>Forwarding HTTP traffic from https://cmheong.serveo.net</div></div><div><br /></div><div>Now https://cmheong.serveo.net will work, just like that. After that head over to https://serveo.com and buy Trevor Dixon that cup of coffee. The man deserves it.</div><div><br /></div><div>Happy Trails</div><div><br /></div><div><br /></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-76218158329810173872023-05-03T05:55:00.001-07:002023-05-04T00:26:04.586-07:00Tensorflow and Keras for the Nvidia Geforce GT 710<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN1oxAScGnJ1yKeb1-3suVSEuJi5CFBq8Remhcg1ii45OpThvy0GI7FYAhgKMhSrQFZ--nomEAl4ExFY2XrF_b-M1Hn_w9CR0pTFw3dXtS_whOhnDb_hfKZc4mzEvNtbjjKKZIL48SUJY3SIi1mb3ikr3nSQAVWpNKYVNRF7I6M61rn4DQLMEJN6PGpQ/s579/Alice_par_John_Tenniel_03.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="579" data-original-width="563" height="511" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN1oxAScGnJ1yKeb1-3suVSEuJi5CFBq8Remhcg1ii45OpThvy0GI7FYAhgKMhSrQFZ--nomEAl4ExFY2XrF_b-M1Hn_w9CR0pTFw3dXtS_whOhnDb_hfKZc4mzEvNtbjjKKZIL48SUJY3SIi1mb3ikr3nSQAVWpNKYVNRF7I6M61rn4DQLMEJN6PGpQ/w497-h511/Alice_par_John_Tenniel_03.png" width="497" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="background-color: #faebd0; text-align: justify; text-indent: 16px;">... alas! either the locks were too large, or the key was too small, but at any rate it would not open any of them. </span></td></tr></tbody></table>Seemingly against the odds, <a href="https://cmheong.blogspot.com/2023/04/nvidia-geforce-gt-710-down-rabbit-hole.html">CUDA and cudaDNN ran on the GT 710</a>, and I could run an <a href="https://www.v7labs.com/blog/image-super-resolution-guide">AI super resolution</a> inference program to upscale images and video. While it is gratifying to finally bump up the GPU temperature, it hardly broke a sweat, wandering from 38 degrees Celsius to 40, more from the time of day than from workload. After all, my Raspberry Pi could do the same.<div><br /></div><div>Training an AI might stretch it a little more, one of the biggest and baddest of them all, an <a href="https://www.v7labs.com/blog/image-super-resolution-guide">SRGAN</a> might make an impression. There seems to be two main frameworks, Pytorch and Tensorflow. A very cursory search shows that <a href="https://dev.to/evanilukhin/guide-to-install-pytorch-with-cuda-on-ubuntu-18-04-5217">Pytorch may require my Ubuntu 18.04 python 3.6 to be first upgraded to 3.8</a>. This is quite possible, but having spent 3 weeks building python 3.6 for CUDA I decided it might be time to try Tensorflow.<p></p></div><div>There is the usual dilemma of juggling Tensorflow, CUDA, gcc and python versions, but using <a href="https://medium.com/analytics-vidhya/how-to-set-up-tensorflow-gpu-on-ubuntu-18-04-lts-7a09ffd5f30f">Fan Leng-Yoon</a> and the <a href="https://www.tensorflow.org/install/source#gpu">tensorflow</a> sites, I settled on Tensorflow 2.2.0.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://www.tensorflow.org/install/source#gpu" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="558" data-original-width="853" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnDPrYsiNKoD9vk-Otghask9q9JaH7PMz8YdGn3SCCMFUaG4HFAJydihiRar3jkbWCIKakqpjlR9CwmUmo6A9QNkAKrbJHvjsPIh2IkDqcRqiLniLRQE4xRX1s3AquI-RdacRXjo_D_yHhA3Dyhsib2bA9dKVbyKqgeJLmWk9_gVHt8oFgUe4KZInK7w/w566-h369/tensorflow.png" width="566" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div>The instructions culled from tensorflow site are:</div><div><br /></div><div>$sudo apt-get update</div><div>$sudo pip3 install "tensorflow==2.2.*"</div><div><div>$sudo pip3 install keras</div></div><div><br /></div><div>It installed surprisingly smoothly, except when it was time for the tensorflow test:</div><div><br /></div><div><div>$python3</div><div>Python 3.6.9 (default, Mar 10 2023, 16:46:00)</div><div>[GCC 8.4.0] on linux</div><div>Type "help", "copyright", "credits" or "license" for more information.</div><div>>>> import tensorflow as tf</div><div>Illegal instruction (core dumped)</div></div><div><br /></div><div>That was not good. A <a href="https://github.com/tensorflow/tensorflow/issues/19584">hint came from the tensorflow repository</a>: I may be missing the AVX instruction. And indeed my CPU, an Athlon II X3 440 did not have it</div><div><br /></div><div>$cat /proc/cpuinfo</div><div><div>wp : yes</div><div>flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov</div><div>pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp</div><div> lm 3dnowext 3dnow constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid pni</div><div>monitor cx16 popcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalign</div><div>sse 3dnowprefetch osvw ibs skinit wdt nodeid_msr hw_pstate vmmcall npt lbrv svm_</div><div>lock nrip_save</div><div>bugs : tlb_mmatch fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2</div><div>bogomips : 6020.19</div><div>TLB size : 1024 4K pages</div><div>clflush size : 64</div><div>cache_alignment : 64</div><div>address sizes : 48 bits physical, 48 bits virtual</div><div>power management: ts ttp tm stc 100mhzsteps hwpstate</div></div><div><br /></div><div>The obvious thing to do would be to downgrade tensorflow to version 1.5, before the use of the AVX instructions was baked into the tensorflow binaries.</div><div><br /></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo pip3 uninstall tensorflow</span></span></div><div>$sudo pip3 install "tensorflow_gpu==1.5.*"</div><div><br /></div><div>But now I get a different failure:</div><div><br /></div><div><div>$python3</div><div>Python 3.6.9 (default, Mar 10 2023, 16:46:00)</div><div>[GCC 8.4.0] on linux</div><div>Type "help", "copyright", "credits" or "license" for more information.</div><div>>>> import tensorflow as tf</div></div><div><div>ImportError: libcublas.so.9.0: cannot open shared object file: No such file or directory</div></div><div><br /></div><div> It looks like it wants an older CUDA:</div><div><div>$sudo ls -lR /usr/ | grep -e libcublas</div><div>[sudo] password for heong:</div><div>lrwxrwxrwx 1 root root 15 Aug 10 2019 libcublas.so -> libcublas.so.10</div><div>lrwxrwxrwx 1 root root 23 Aug 10 2019 libcublas.so.10 -> libcublas.so.1</div><div>0.2.1.243</div><div>-rw-r--r-- 1 root root 62459056 Aug 10 2019 libcublas.so.10.2.1.243</div></div><div><br /></div><div>I guess I will be needing to build tensorflow without the AVX instruction.</div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo -H pip3 uninstall tensorflow_gpu</span></span><span style="font-family: monospace;"><br /></span></div><div><br /></div><div> To build from source I used the <a href="https://www.tensorflow.org/install/source">tensorflow instructions</a>, which called for first installing an enormous installer, Bazel. And since I recently got <a href="https://chat.openai.com/">chatGPT</a> why not give it a try:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKcDAyDhtR5hGl2RicT0TsjVEeujAp26UiSD-QfkR23zKiBAGtzwusWGPM3Xikwy9tYAFdwwEp44IsDgOzR4leZ1jHP0JGmn6-yOTiqUrqMshXL3K0sjcXB5lvQCPtfudXfsFtmigptqnlG3BjP1CMCXXXG9v8S8yyjZ_QITr-QHuuCMiqlOWwd3RG-A/s748/chatGPT_Bazel.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="435" data-original-width="748" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKcDAyDhtR5hGl2RicT0TsjVEeujAp26UiSD-QfkR23zKiBAGtzwusWGPM3Xikwy9tYAFdwwEp44IsDgOzR4leZ1jHP0JGmn6-yOTiqUrqMshXL3K0sjcXB5lvQCPtfudXfsFtmigptqnlG3BjP1CMCXXXG9v8S8yyjZ_QITr-QHuuCMiqlOWwd3RG-A/w596-h346/chatGPT_Bazel.png" width="596" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">chatGPT convincingly gave the wrong answer</td></tr></tbody></table><br /><div>chatGPT very convincingly gave the wrong answer, version 0.26.0. The correct answer is 3.1.0. When I pointed this out it immediately gave another equally convincing (and correct) answer:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHG9orU2Zxq71lBgUqbcCLRWyiy9O86vHVzw87azVlx_kEhaXedThB2jnsYCgpMvIHEz08jw5BxAgqFEuW0xr3CuZ6OUcIp-AaHzq5RqErbl-bGcGSI85fz1FQmRq8wkGZ9__dCtyp6saiG6EHSqaMjKsBamIPYwfnzPe7SVL70VhXmgjsUCARJsci9w/s586/chatGPT_Bazel2.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="586" data-original-width="408" height="798" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHG9orU2Zxq71lBgUqbcCLRWyiy9O86vHVzw87azVlx_kEhaXedThB2jnsYCgpMvIHEz08jw5BxAgqFEuW0xr3CuZ6OUcIp-AaHzq5RqErbl-bGcGSI85fz1FQmRq8wkGZ9__dCtyp6saiG6EHSqaMjKsBamIPYwfnzPe7SVL70VhXmgjsUCARJsci9w/w555-h798/chatGPT_Bazel2.png" width="555" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">chatGPT quickly changed its mind to version 3.1.0</td></tr></tbody></table><br /><div>For now chatGPT 3 seems to have the credibility of a used-car salesman. They say an SRGAN hallucinates all those extra pixels in an up-scaled image. ChatGPT is known to a few flights of fancy like ... the Mad Hatter?</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu2ENAyzOdjrnUy3DWMVW5p56RJIPspTSvVPaOjRCQf2z89y3iwF8ijcBDBrdOjDCbIhQHhyBF3qB8LyuUKJdm9iaiHUlxRvVx7OT2IktZK-TPL601EDsidLDtaUjYmmSK0Na5EjsYhWvTy9oAb1YoABp79KuGDp7JENgvNqR9fqd--VfJlTPep-9wJQ/s823/MadHatter.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="483" data-original-width="823" height="353" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu2ENAyzOdjrnUy3DWMVW5p56RJIPspTSvVPaOjRCQf2z89y3iwF8ijcBDBrdOjDCbIhQHhyBF3qB8LyuUKJdm9iaiHUlxRvVx7OT2IktZK-TPL601EDsidLDtaUjYmmSK0Na5EjsYhWvTy9oAb1YoABp79KuGDp7JENgvNqR9fqd--VfJlTPep-9wJQ/w601-h353/MadHatter.png" width="601" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><h1 class="quoteText" style="background-color: white; color: #181818; font-family: Merriweather, Georgia, serif; font-size: 14px; font-weight: normal; line-height: 21px; margin: 0px 0px 15px; padding: 0px; text-align: left;">“Have I gone mad? I'm afraid so.You're entirely Bonkers.But I will tell you a secret,All the best people are.”</h1></td></tr></tbody></table><div><br /></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo pip3 uninstall keras</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-get update</span><br />
</span><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-get install curl gnupg</span><br />
</span><span style="font-family: monospace;"><span style="background-color: white;">$curl -fsSL https://bazel.build/bazel-release.pub.gp</span>g | gpg --dearmor > bazel.gp<br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo mv bazel.gpg /etc/apt/trusted.gpg.d/</span><br />
</span><span style="font-family: monospace;"><span style="background-color: white;">$echo "deb [arch=amd64] https://storage.googleapis.c</span>om/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list<br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$cat /etc/apt/sources.list.d/bazel.list
</span><br />deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-get install bazel-2.0.0</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$bazel --version
</span><br />bazel 2.0.0<br /></span></div><div><div><span style="font-family: monospace;">git clone https://github.com/tensorflow/tensorflow.</span><span style="font-family: monospace;">git</span></div></div><div><div style="font-family: monospace;">$cd tensorflow</div><div style="font-family: monospace;"><span style="background-color: white;">$git checkout v2.2.0</span><br />
<span style="background-color: white;">$./configure</span><br /></div><div><span style="background-color: white; font-family: monospace;">Extracting Bazel installation...
</span><br /><span style="font-family: monospace;">You have bazel 2.0.0 installed.
</span><br /><span style="font-family: monospace;">Please specify the location of python. [Default is /usr/bin/python3]:
</span><br />
<br />
<br /><span style="font-family: monospace;">Found possible Python library paths:
</span><br /><span style="font-family: monospace;"> /usr/lib/python3/dist-packages
</span><br /><span style="font-family: monospace;"> /home/heong/opencv_build/opencv/build/lib/python3/
</span><br /><span style="font-family: monospace;"> /usr/local/lib/python3.6/dist-packages
</span><br /><span style="font-family: monospace;">Please input the desired Python library path to use. Default is [/usr/lib/python3/dist-packages]
</span><br /><span style="font-family: monospace;">/usr/local/lib/python3.6/dist-packages
</span><br /><span style="font-family: monospace;">Do you wish to build TensorFlow with OpenCL SYCL support? [y/N]:
</span><br /><span style="font-family: monospace;">No OpenCL SYCL support will be enabled for TensorFlow.
</span><br />
<br /><span style="font-family: monospace;">Do you wish to build TensorFlow with ROCm support? [y/N]:
</span><br /><span style="font-family: monospace;">No ROCm support will be enabled for TensorFlow.
</span><br />
<br /><span style="font-family: monospace;">Do you wish to build TensorFlow with CUDA support? [y/N]: y
</span><br />
<br /><span style="font-family: monospace;">Do you wish to build TensorFlow with TensorRT support? [y/N]:
</span><br /><span style="font-family: monospace;">No TensorRT support will be enabled for TensorFlow.
</span><br />
<br /><span style="font-family: monospace;">Found CUDA 10.1 in:
</span><br /><span style="font-family: monospace;"> /usr/local/cuda/lib64
</span><br /><span style="font-family: monospace;"> /usr/local/cuda/include
</span><br /><span style="font-family: monospace;">Found cuDNN 7 in:
</span><br /><span style="font-family: monospace;"> /usr/lib/x86_64-linux-gnu
</span><br /><span style="font-family: monospace;"> /usr/include</span><br />
<div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">Do you want to use clang as CUDA compiler? [y/N]:</span></div><div><span style="font-family: monospace;">nvcc will be used as CUDA compiler.</span></div></div><div style="font-family: monospace;"><br /></div><div style="font-family: monospace;"><span style="background-color: white;">$bazel build --config=opt --config=cuda -</span>-cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"//tensorflow/tools/pip_package:build_pip_package</div><div style="font-family: monospace;"><br /></div><div style="font-family: monospace;"><span style="background-color: white;">$sudo link /usr/bin/python3 /usr/bin/pyth</span>on<br /></div><div style="font-family: monospace;"><div>$bazel build //tensorflow/tools/pip_package:build_pip_package</div>
<br /></div><div style="font-family: monospace;">The build took the Athlon all night but completed successfully.</div><div style="font-family: monospace;"><br /></div><div style="font-family: monospace;">With a little bit of help from <a href="https://medium.com/@isaaclascasas/tensorflow-from-source-in-ubuntu-18-4b5dcca910 b9">Isaac Lascasas</a>, </div><div style="font-family: monospace;"><br /></div><div style="font-family: monospace;"><span style="background-color: white;">$./tensorflow/tools/pip_package/build_pip</span>_package.sh /tmp/tensorflow_pkg<br />
<br /></div><div style="font-family: monospace;">$<span style="background-color: white;">pip3 install --upgrade --force-reinstall </span><span style="background-color: white;">/tmp/tensorflow_pkg/tensorflow-2.2.0-</span>cp36-cp36m-linux_x86_64.whl</div><span style="font-family: monospace;">
<div><span style="font-family: monospace;"><br /></span></div>And it worked:</span></div><div><span style="font-family: monospace;"><div><span style="background-color: white;">$cd ..
</span><br />$python3
<br />Python 3.6.9 (default, Mar 10 2023, 16:46:00)
<br />[GCC 8.4.0] on linux
<br />Type "help", "copyright", "credits" or "license" for more information.
<br />>>> import tensorflow as tf
<br />>>> tf.__version__
<br />'2.2.0'<br />
<br /></div></span><div style="font-family: monospace;"><span style="font-family: "Times New Roman";">$sudo pip3 install keras</span></div><div style="font-family: monospace;"><span style="font-family: "Times New Roman";"><br /></span></div><div style="font-family: monospace;"><span style="font-family: "Times New Roman";">Training <a href="https://github.com/HasnainRaz/Fast-SRGAN">HasnainRaz's Fast-SRGAN</a> bumped the GT 710's temperature up to 60 degrees Celsius. Running inference on it on several hundred frames raised it further to 67. Somehow that felt more like real work.</span></div><div style="font-family: monospace;"><span style="font-family: "Times New Roman";"><br /></span></div><div style="font-family: monospace;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmWgYk1MCe_OTKer6KkzX9VjpNKRkYrktorDXv3ABYAioCY_Nd7QS3R60WFyLWwLMCLEG9sEOLNhu2gceQY7p6q_Tt_kY11aE0eEOdsJ3jZWiHBMg5uh9umgDUYvApt-rw3JvTG3uCUhwPaUSO3kw4JXACHv-47LSZnljogMKnbWhMap8thxmpeQooaw/s920/flat,750x1000,075,f.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="920" data-original-width="750" height="573" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmWgYk1MCe_OTKer6KkzX9VjpNKRkYrktorDXv3ABYAioCY_Nd7QS3R60WFyLWwLMCLEG9sEOLNhu2gceQY7p6q_Tt_kY11aE0eEOdsJ3jZWiHBMg5uh9umgDUYvApt-rw3JvTG3uCUhwPaUSO3kw4JXACHv-47LSZnljogMKnbWhMap8thxmpeQooaw/w467-h573/flat,750x1000,075,f.jpg" width="467" /></a></div><br /><span style="font-family: "Times New Roman";"><br /></span></div><div style="font-family: monospace;"><span style="font-family: "Times New Roman";">Happy Trails.</span></div></div><div><span style="font-family: monospace;"><br /></span></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-79432257466869404482023-04-22T07:59:00.002-07:002023-04-22T08:30:49.154-07:00Nvidia GeForce GT 710: Down the Rabbit Hole of Proprietary Obsolescence<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLafQQ2nOgti_6HKh7gw8AJP6mJJUgAjPtY1uZQr_YokKra7QSNZtO53CVfHnRAt8H7XBXM2p4OMBDWZm42aRta6NWaVLYe8I9A44kzuULnqa-THwKoyneZTX_tkC1uIFypxIV8ISKk-_4S4a-jxrRD8vrKCltSXajWw0O_BJAMt9dfyrU040pnWmxjQ/s500/rabbitHole.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="500" data-original-width="373" height="703" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLafQQ2nOgti_6HKh7gw8AJP6mJJUgAjPtY1uZQr_YokKra7QSNZtO53CVfHnRAt8H7XBXM2p4OMBDWZm42aRta6NWaVLYe8I9A44kzuULnqa-THwKoyneZTX_tkC1uIFypxIV8ISKk-_4S4a-jxrRD8vrKCltSXajWw0O_BJAMt9dfyrU040pnWmxjQ/w525-h703/rabbitHole.jpeg" width="525" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">" ... down went Alice after it, never once considering how in the world she was to get out again." - Lewis Carroll, 'Alice's Adventures in Wonderland'</td></tr></tbody></table><p></p><p style="background: rgb(255, 255, 255); border: 0px; font-family: "Josefin Slab", serif; font-size: 18px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">I try to avoid proprietary software, which is why I do not usually buy Nvidia graphics cards. If I did, I would use the noveau open source driver. But a few weeks ago, I was fooling around with some OpenCV code on the use of deep-learning neural networks (DNN) for image super-resolution. </p><p style="background: rgb(255, 255, 255); border: 0px; font-family: "Josefin Slab", serif; font-size: 18px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">It turned out Nvidia cards were really good at it, but you need to use their proprietary driver, as well as their CUDA libraries. In particular the OpenCV dnn module uses <a href="https://docs.nvidia.com/deeplearning/cudnn/developer-guide/index.html">Nvidia cuDNN</a> libraries that uses CUDA and which in turn uses Nvidia binary drivers. </p><p style="background: rgb(255, 255, 255); border: 0px; font-family: "Josefin Slab", serif; font-size: 18px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">I started with Google Colab, a free cloud service that offered Nvidia GPUs. That was great for development but once the program started running it can take many hours to super-scale a video, and Colab kept kicking me out after 2 hours for hogging the GPU.</p><p style="background: rgb(255, 255, 255); border: 0px; font-family: "Josefin Slab", serif; font-size: 18px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">The normal way would be to buy a desktop with a say, Nvidia RTX 3060 12GB card for RM4200 (less than USD950), but installing/using proprietary systems was bad enough; paying good money for it <b>really hurt</b>. It turned out I had a 7-year old GeForce GT 710 from Gigabyte lying around inside an even older (12 years!) Asus Crosshair IV Formula with an Athlon Phenom II at 3GHz.</p><p style="background: rgb(255, 255, 255); border: 0px; font-family: "Josefin Slab", serif; font-size: 18px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">So, like Alice, I dived down the rabbit hole of proprietary obsolescence on an impulse. Ubuntu 22.04 installed and ran like a breeze. A default install (just like Colab) using <a href="https://developer.nvidia.com/cuda-downloads">Nvidia CUDA 12</a> and <a href="https://developer.nvidia.com/rdp/cudnn-download">Nvidia cuDNN 8.9.0</a> did not work. Actually all three parts (card driver, CUDA and cuDNN) did not work.</p><p style="text-align: left;"><span style="font-family: verdana; font-size: medium;">Time to do my homework. Gigabyte lists my card as <a href="https://www.gigabyte.com/Graphics-Card/GV-N710SL-2GL#ov">GV-N710SL-2GL</a>, still on sale. The 'specs' listed were mostly marketing guff and quite useless. <a href="https://www.techpowerup.com/gpu-specs/geforce-gt-710.c3027">Techpowerup came up with the goods</a>: its real name was GK208, architecture Kepler and crucially the CUDA Computer number 3.5. <a href="https://www.myzhar.com/blog/tutorials/tutorial-nvidia-gpu-cuda-compute-capability/">The official Nvidia CUDA Compute Capability link</a> does not mention the GT 710 at all.</span></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP_wJKEes1TZ4sebdVrOxZr6CH8VSpOs5oef8vWvJHyAzoGUBG5dUupOwOAzh6b0L6Qds9elimF7uB_DMKkOjSLylrLNj18I-pbAn2kPzRBkOMmd1UBLuTMEhyFvJXWMPyfkCZaFPRnQtTMQLOpvAwXdU3G-5H5CKELDEUFM4QdxNyWBrlq_dnX595cA/s1000/geforceGT710.webp" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="857" data-original-width="1000" height="500" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP_wJKEes1TZ4sebdVrOxZr6CH8VSpOs5oef8vWvJHyAzoGUBG5dUupOwOAzh6b0L6Qds9elimF7uB_DMKkOjSLylrLNj18I-pbAn2kPzRBkOMmd1UBLuTMEhyFvJXWMPyfkCZaFPRnQtTMQLOpvAwXdU3G-5H5CKELDEUFM4QdxNyWBrlq_dnX595cA/w585-h500/geforceGT710.webp" width="585" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Gigabyte GeForce GT 710</td></tr></tbody></table><br /><p style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;"><br /></p><p style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">Now not all the websites agree on the GT 710, least of all Nvidia's. The <a href="https://docs.nvidia.com/deeplearning/cudnn/support-matrix/index.html">cuDNN Support Matrix</a> excludes Kepler architecture and implies a CUDA Compute Capability of 5.0. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnuiENdWEhA_UEI-BPEPCRd4GVuxfOoQmmZ2HfrGrPvRMAIfPcxHzZskgKDlQZsmWmKUZNeB4fVkZyvT8G9RiMl0BERX252LtwLCQEXeVwAP9Q8Fv7sQoPfZRjFsWSHQ2kqB4nCQZ05NigmHLQ_4PyM7g0nLEyUOTnP5PNxmaCARtL7MWKQ_ruMJcbQQ/s1501/cudnnMatrix.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="732" data-original-width="1501" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnuiENdWEhA_UEI-BPEPCRd4GVuxfOoQmmZ2HfrGrPvRMAIfPcxHzZskgKDlQZsmWmKUZNeB4fVkZyvT8G9RiMl0BERX252LtwLCQEXeVwAP9Q8Fv7sQoPfZRjFsWSHQ2kqB4nCQZ05NigmHLQ_4PyM7g0nLEyUOTnP5PNxmaCARtL7MWKQ_ruMJcbQQ/w583-h285/cudnnMatrix.png" width="583" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">cuDNN 8.9.0 does not support Kepler </td></tr></tbody></table><br /><p style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;"><br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlADYIk11ouaQeLYe695cwSFFbc042T5n61weCh5G7BHzLa7ubkLQeKRrfFNVvD7FyZpR6miPhQ9jANF8rBKlPUZk08zGhYvanjEeLnmerDzncWSAw_0VOEDTKOVHt1TzLuaWSypfYXjYecGf0EXxPT-TRWwmmt1SPzVa0kLYs5NZpZj_ZeT6PIwIa5g/s417/cudnnMatrix2.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="417" data-original-width="385" height="536" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlADYIk11ouaQeLYe695cwSFFbc042T5n61weCh5G7BHzLa7ubkLQeKRrfFNVvD7FyZpR6miPhQ9jANF8rBKlPUZk08zGhYvanjEeLnmerDzncWSAw_0VOEDTKOVHt1TzLuaWSypfYXjYecGf0EXxPT-TRWwmmt1SPzVa0kLYs5NZpZj_ZeT6PIwIa5g/w493-h536/cudnnMatrix2.png" width="493" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Kepler not included</td></tr></tbody></table><br /><p style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; line-height: 1.2em; margin: 0px; outline: 0px; padding: 7px 0px; vertical-align: baseline;">Yet the <a href="https://docs.nvidia.com/deeplearning/cudnn/archives/cudnn_764/cudnn-support-matrix/index.html">2019 version of the same document</a>, now archived and no longer linked to the main Nvidia cuDNN site says otherwise:</p><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisTvBNZTVK6XHgvYy39qKSdGCB4o2-IBjVxeDf5Zwwz6G_McmzHEBZ74iejnVUaHV_HK1_wGJfXA4XYqKGQDm7x_S65ivEZdeEdUnVH-z-RRmz7_6Ad4S--29jpFx0P5UpGz6y67wDuuVpKgIQtHFYjHPtvSNd1UBmoNSKMy-E8xk6QUH03XivDfHdkA/s967/cudnnMatrix3.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="811" data-original-width="967" height="414" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisTvBNZTVK6XHgvYy39qKSdGCB4o2-IBjVxeDf5Zwwz6G_McmzHEBZ74iejnVUaHV_HK1_wGJfXA4XYqKGQDm7x_S65ivEZdeEdUnVH-z-RRmz7_6Ad4S--29jpFx0P5UpGz6y67wDuuVpKgIQtHFYjHPtvSNd1UBmoNSKMy-E8xk6QUH03XivDfHdkA/w494-h414/cudnnMatrix3.png" width="494" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Kepler supported by cuDNN 7.6.x</td></tr></tbody></table><br /><div>What this feels like is the GeForce GT 710 is abandonware, probably for marketing reasons. Did I mention I do not like proprietary systems? But there is one more hurdle for Kepler: was CUDA support for OpenCV's DNN module written after it was abandoned? Luckily it was also <a href="https://summerofcode.withgoogle.com/archive/2019/projects/6169918255398912">released in the summer of the same (2019) year's Google Summer of Code</a>, so the chances are excellent.</div><div><br /></div><div>So what I need is cuDNN v7.6.4 CUDA <span face=""Trebuchet MS", "DIN Pro", sans-serif" style="background-color: white; font-size: 14px;">10.1.243</span> and CUDA Driver r419.39. cuDNN v7.6.4 is still available at the <a href="https://developer.nvidia.com/rdp/cudnn-archive">Nvidia cuDNN Archive</a>. I chose the Ubuntu version as it was the same as Colab's. This means regressing to the much older <a href="https://releases.ubuntu.com/18.04/">Ubuntu 18.04</a> though. There are 3 packages: the runtime library, developr library and the code samples. CUDA 10.1 is available from Nvidia, and I chose <a href="https://developer.nvidia.com/cuda-10.1-download-archive-update2">CUDA 10.1 Update 2</a>.</div><div><br /></div><div>And since I have only ever used Ubuntu in virtual machines on docker, AWS or Google Colab I never had to install them, so here are the instructions:</div><div><br /></div><div>Make the Ubuntu boot DVD thus:</div><div>$sudo growisofs -speed=1 -dvd-compat -Z /dev/sr0=ubuntu-18.04.6-desktop-amd64.iso</div><div><br /></div><div>In my case I had an ancient Dell SE198WFP monitor that the GT 710 could not identify and the boot DVD may show a blank screen. By rebooting and pressing various keys (e?) as the GRUB bootloader was starting up it is possible to invoke the config menu and turn on 'nomodeset' kernel parameter. I then got a very basic 640x480 setup for Ubuntu 18.04.</div><div><br /></div><div>After the install, if you want a static IP address you need to do something like:</div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo vi /etc/network/interfaces</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">And add in your IP address:</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">auto enp5s0
</span><br />iface enp5s0 inet static
<br /> address your.ip.addr.here<br /> netmask 255.255.255.0
<br /> gateway your.router.addr.1
<br /> dns-nameservers 8.8.8.8<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">After that ssh server is always handy:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">sudo apt install openssh-server.
</span><br />sudo systemctl status ssh.
<br />sudo systemctl enable ssh sudo systemctl start ssh.
<br />sudo ufw allow ssh.
<br />sudo nano /etc/ssh/sshd_config.
<br />sudo service ssh restart.</span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">To set your computer host name:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo hostnamectl set-hostname MyAIcomputer</span></span><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">Annoyingly, Ubuntu 18.04 ket setting my DNS server address to 127.0.0.53 so I did:</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">sudo vi /etc/systemd/resolved.conf</span><br />
<br /></span></div><div><span style="font-family: monospace;">And added the line</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">DNS=8.8.8.8</span><br />
<br /></span></div><div><span style="font-family: monospace;">And lastly, Ubuntu 18.04 displays date and time in Malay, very natural for a computer in Malaysia but this old-timer has been speaking English to his computers since 1980 (when computers only knew English) so:</span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo localectl set-locale LC_TIME=en_US.utf8</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div>To prepare Ubuntu 18.04 to build OpenCV I used changx03's instructions, reproduced here dor convenience:<br />$ sudo apt update<br />$ sudo apt upgrade<br />$ sudo apt install build-essential cmake pkg-config unzip yasm git checkinstall<br />$ sudo apt install libavcodec-dev libavformat-dev libswscale-dev libavresample-dev </div><div>$ sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev </div><div>$ sudo apt install libxvidcore-dev x264 libx264-dev libfaac-dev libmp3lame-dev libtheora-dev </div><div>$ sudo apt install libfaac-dev libmp3lame-dev libvorbis-dev<br /></div>$ sudo apt install libopencore-amrnb-dev libopencore-amrwb-dev<br />$ sudo apt-get install libgtk-3-dev<br />$ sudo apt-get install python3-dev python3-pip <div>$ sudo -H pip3 install -U pip numpy </div><div>$ sudo apt install python3-testresources<br />$ sudo apt-get install libtbb-dev<br />$ sudo apt-get install libatlas-base-dev gfortran</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip9Y2nj8fxnTB2WbFDiIqWHhh578yeeqAmlorSPWBO5q4vOCFkE9UDq1HXAQv1OGunGBXxREnjVjq0chyB_NSLBccOtMrR0mLJ55au16TSGM1umyB9YzhCwJavZP48C-gyA-vje4Y35UWDeQHcnKVekBJqRVnXAandPy-pNAnWEwpLVj099hajtMvlvA/s602/whiteRabbit.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="395" data-original-width="602" height="337" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEip9Y2nj8fxnTB2WbFDiIqWHhh578yeeqAmlorSPWBO5q4vOCFkE9UDq1HXAQv1OGunGBXxREnjVjq0chyB_NSLBccOtMrR0mLJ55au16TSGM1umyB9YzhCwJavZP48C-gyA-vje4Y35UWDeQHcnKVekBJqRVnXAandPy-pNAnWEwpLVj099hajtMvlvA/w513-h337/whiteRabbit.jpeg" width="513" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="text-align: left;">"Follow the White Rabbit" - Trinity, in "The Matrix" 1999</span></td></tr></tbody></table><div><br /><h2 style="text-align: left;">Following the White Rabbit</h2></div><div><br /><a href="https://developer.nvidia.com/cuda-10.1-download-archive-update2?target_os=Linux& target_arch=x86_64&target_distro=Ubuntu&target_version=1804&target_type=deblocal">Archived CUDA 10.1</a> was installed per <a href="https://docs.nvidia.com/cuda/archive/10.1/cuda-installation-guide-linux/index.ht ml">these instructions</a>:</div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-get install linux-headers-$(uname -r)</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$wget https://developer.download.nvidia.com/compute/cuda/r</span>epos/ubuntu1804/x86_64/cuda-ubuntu1804.pin</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-r</span>epository-pin-600</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$wget https://developer.download.nvidia.com/compute/cuda/1
</span><br />0.1/Prod/local_installers/cuda-repo-ubuntu1804-10-1-local-10.1.243-418.87.00_1.0-1_amd64.deb</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo dpkg -i cuda-repo-ubuntu1804-10-1-local-10.1.243-418</span>.87.00_1.0-1_amd64.deb</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-key add /var/cuda-repo-10-1-local-10.1.243-418.8</span>7.00/7fa2af80.pub</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-get update</span><br />
</span><span style="background-color: white; font-family: monospace;">$sudo init 3</span><span style="font-family: monospace;"><br /></span><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt-get -y install cuda</span></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">And after it is all done, reset the computer to load the new Nvidia graphics driver</span></div><div><span style="font-family: monospace;">$sudo reboot</span><br /><span style="font-family: monospace;">
</span><span style="font-family: monospace;">
<br /></span></div><div><span style="font-family: monospace;">CUDA 10.1 seems fine, but but there is a problem with the Nvidia driver: it does not load:</span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$nvidia-smi
</span><br />NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">There is a way to <a href="https://docs.nvidia.com/cuda/archive/10.1/cuda-installation-guide-linux/index.html">uninstall in the Nvidia documentation</a> but it did not work:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo /usr/bin/nvidia-uninstall
</span><br />sudo: /usr/bin/nvidia-uninstall: command not found<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ8Z4-rGDllIluB4RAxj-fMY8MuLCzIzc_gBPUopl4SCLWOQdG5591YlwBhWFSSD79wwVw2kpOUNBwvciAyCZ2uW9EggM1Mmvok96u0rOUNVG2UABx8SxX5-Ul4mOg1dBpwwrVLwhka2eYt_--IpMkoTmDOy80CT0d5ZJtQ9nNtQeLHP7ocNN8iqctkg/s1000/RTX3090.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1000" data-original-width="1000" height="478" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ8Z4-rGDllIluB4RAxj-fMY8MuLCzIzc_gBPUopl4SCLWOQdG5591YlwBhWFSSD79wwVw2kpOUNBwvciAyCZ2uW9EggM1Mmvok96u0rOUNVG2UABx8SxX5-Ul4mOg1dBpwwrVLwhka2eYt_--IpMkoTmDOy80CT0d5ZJtQ9nNtQeLHP7ocNN8iqctkg/w478-h478/RTX3090.png" width="478" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">What Nvidia thinks I should use: Gigabyte RTX3090 24GB</td></tr></tbody></table><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">I guess we will have to do it the Ubuntu way, with apt. </span><span style="font-family: monospace;">Now since the graphics card driver was packaged with CUDA 10.1 you will need to find its version, and it looks like 418.87.00:</span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt list --installed | less</span><br />nvidia-compute-utils-418/unknown,now 418.87.00-0ubuntu1 amd64 [installed,automatic]
<br />nvidia-dkms-418/unknown,now 418.87.00-0ubuntu1 amd64 [installed,automatic]
<br />nvidia-driver-418/unknown,now 418.87.00-0ubuntu1 amd64 [installed,automatic]
<br />nvidia-kernel-common-418/unknown,now 418.87.00-0ubuntu1 amd64 [installed,automatic]<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">This makes the uninstall command thus:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt remove --purge nvidia-driver-418</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">Now I tried quite a few graphics drivers in the Ubunto repository. Version 390 worked very well but was incompatible with CUDA 10.1. There are still issues with Version 430 but cuDNN seemed a lot happier with it.</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo apt install nvidia-driver-430</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">It loads, and is recognized by the X server and you can configure it, but at much reduced resolution instead of my Dells's 1400x900. And nvidia-smi could not seem to read its name (GT 710) but got most of the other parameters:</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$nvidia-smi
</span><br />/usr/bin/nvidia-modprobe: unrecognized option: "-s"
<br />
<br />ERROR: Invalid commandline, please run `/usr/bin/nvidia-modprobe --help` for
<br /> usage information.
<br />
<br />/usr/bin/nvidia-modprobe: unrecognized option: "-s"
<br />
<br />ERROR: Invalid commandline, please run `/usr/bin/nvidia-modprobe --help` for
<br /> usage information.
<br />
<br /></span><span style="font-family: monospace;"><span style="background-color: white;">Sat Apr 22 11:18:33 2023
</span><br />+-----------------------------------------------------------------------------+
<br />| NVIDIA-SMI 470.182.03 Driver Version: 470.182.03 CUDA Version: 11.4 |
<br />|-------------------------------+----------------------+----------------------+<br /></span><span style="font-family: monospace;"><span style="background-color: white;">| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
</span><br />| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
<br />| | | MIG M. |
<br />|===============================+======================+======================|
<br />| 0 NVIDIA GeForce ... Off | 00000000:08:00.0 N/A | N/A |
<br />| 33% 38C P8 N/A / N/A | 65MiB / 2000MiB | N/A Default |
<br />| | | N/A |
<br />+-------------------------------+----------------------+----------------------+<br />
<br /></span><span style="font-family: monospace;">+-----------------------------------------------------------------------------+
<br />| Processes: |
<br />| GPU GI CI PID Type Process name GPU Memory |
<br />| ID ID Usage |
<br />|=============================================================================|
<br />| No running processes found |
<br />+-----------------------------------------------------------------------------+<br />
<br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">Note CUDA Version is listed as 11.04; I took 10.1 to the the runtime version number.</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">Next is cuDNN. </span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo init 3
</span><br />$sudo dpkg -i libcudnn7_7.6.4.38-1+cuda10.1_amd64.deb
<br />$sudo dpkg -i libcudnn7-dev_7.6.4.38-1+cuda10.1_amd64.deb<br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$sudo dpkg -i libcudnn7-doc_7.6.4.38-1+cuda10.</span>1_amd64.deb<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">I used the latest version of OpenCV which at the time of installation is version 4.7.0-dev:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">git clone https://github.com/opencv/opencv.git
</span><br />git clone https://github.com/opencv/opencv_contrib.git<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;">After many trials, thse build options seem to work. Note I have opted for a static library as this was my setup in Colab and I wanted to use the same code:</span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">~/opencv_build/opencv$mkdir build && cd build
</span><br />~/opencv_build/opencv/build$cmake -D CUDA_NVCC_FLAGS="-D_FORCE_INLINES -gencode=arch=compute_35,code=sm_35" -D CMAKE_BUILD_TYPE=RELEASE -D OPENC
<br />V_GENERATE_PKGCONFIG=ON -DBUILD_SHARED_LIBS=OFF -D CMAKE_INSTALL_PREFIX=/usr/loc
<br />al -D INSTALL_C_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD
<br />_EXAMPLES=OFF -D WITH_OPENEXR=OFF -D WITH_CUDA=ON -D WITH_CUBLAS=ON -D WITH_CUDN
<br />N=ON -D CUDA_ARCH_BIN=3.5 -D OPENCV_DNN_CUDA=ON -D OPENCV_EXTRA_MODULES_PATH=~/o
<br />pencv_build/opencv_contrib/modules ~/opencv_build/opencv<br />
<br /></span></div><div><span style="font-family: monospace;">A key output of the cmake is both CUDA and cuDNN need to be included:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">-- NVIDIA CUDA: YES (ver 10.1, CUFFT CUBLAS)
</span><br />-- NVIDIA GPU arch: 35
<br />-- NVIDIA PTX archs:
<br />--
<br />-- cuDNN: YES (ver 7.6.4)<br />
<br /></span></div><div><span style="font-family: monospace;">The actual make command is:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">~/opencv_build/opencv/build$make -j5</span><br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">The output is</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">~/opencv_build/opencv/build/lib/python3$ls -lh
</span><br />total 193M
<br />-rwxrwxr-x 1 heong heong 193M Apr 21 23:59 cv2.cpython-36m-x86_64-linux-gnu.so<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><h2 style="text-align: left;"><span style="font-family: monospace;">The One</span></h2><div><span style="font-family: monospace;"><br /></span></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMklE1_zFCiLWp4N_x7xKKZ1639_aI1K2vJlIVfZKBSSWctF1TCSQPEDdHjuNNjFEFlu7M9DdL47Kqd1iv8p3NteYFytw9W7FKoYgG1D6yH5qJN3QK5CvxdlniMcjLd78E35MQH-9RrRG8UeJbIUB7A2vYcpmhHWo1utm6IQ6WwjOFMPwYsPT4zNQKdg/s640/neoIsTheOne.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="389" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMklE1_zFCiLWp4N_x7xKKZ1639_aI1K2vJlIVfZKBSSWctF1TCSQPEDdHjuNNjFEFlu7M9DdL47Kqd1iv8p3NteYFytw9W7FKoYgG1D6yH5qJN3QK5CvxdlniMcjLd78E35MQH-9RrRG8UeJbIUB7A2vYcpmhHWo1utm6IQ6WwjOFMPwYsPT4zNQKdg/w518-h389/neoIsTheOne.jpg" width="518" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">"He's the One" - Morpheus, "The Matrix" 1999</td></tr></tbody></table><br /></div><div><div><span style="font-family: monospace;">To prove that the setup supports the Geforce GT 710:</span></div></div><div><div><span style="font-family: monospace;">/usr/local/cuda-10.1/samples/1_Utilities/deviceQuery$sudo make</span></div><div><span style="font-family: monospace;">/usr/local/cuda-10.1/samples/1_Utilities/deviceQuery$sudo ./devi</span><span style="font-family: monospace;">ceQuery</span></div></div><div><span style="font-family: monospace;"><span style="background-color: white;">Query Starting...
</span><br />
<br /> CUDA Device Query (Runtime API) version (CUDART static linking)
<br />
<br />Detected 1 CUDA Capable device(s)
<br />
<br />Device 0: "NVIDIA GeForce GT 710"
<br /> CUDA Driver Version / Runtime Version 11.4 / 10.1
<br /> CUDA Capability Major/Minor version number: 3.5
<br /> Total amount of global memory: 2001 MBytes (2098003968 bytes)
<br /> ( 1) Multiprocessors, (192) CUDA Cores/MP: 192 CUDA Cores
<br /> GPU Max Clock rate: 954 MHz (0.95 GHz)
<br /> Memory Clock rate: 800 Mhz
<br /> Memory Bus Width: 64-bit
<br /> L2 Cache Size: 524288 bytes
<br /> Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65536),
<br />3D=(4096, 4096, 4096)
<br /> Maximum Layered 1D Texture Size, (num) layers 1D=(16384), 2048 layers
<br /> Maximum Layered 2D Texture Size, (num) layers 2D=(16384, 16384), 2048 layers
<br /> Total amount of constant memory: 65536 bytes
<br /> Total amount of shared memory per block: 49152 bytes
<br /> Total number of registers available per block: 65536
<br /> Warp size: 32
<br /> Maximum number of threads per multiprocessor: 2048
<br /> Maximum number of threads per block: 1024
<br /> Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
<br /> Max dimension size of a grid size (x,y,z): (2147483647, 65535, 65535)
<br /> Maximum memory pitch: 2147483647 bytes
<br /> Texture alignment: 512 bytes
<br /> Concurrent copy and kernel execution: Yes with 1 copy engine(s)
<br /> Run time limit on kernels: Yes
<br /> Integrated GPU sharing Host Memory: No
<br /> Support host page-locked memory mapping: Yes
<br /> Alignment requirement for Surfaces: Yes
<br /> Device has ECC support: Disabled<br />
</span><span style="font-family: monospace;"><span style="background-color: white;"> Device supports Unified Addressing (UVA): Yes
</span><br /> Device supports Compute Preemption: No
<br /> Supports Cooperative Kernel Launch: No
<br /> Supports MultiDevice Co-op Kernel Launch: No
<br /> Device PCI Domain ID / Bus ID / location ID: 0 / 8 / 0
<br /> Compute Mode:
<br /> < Default (multiple host threads can use ::cudaSetDevice() with device simu
<br />ltaneously) >
<br />
<br />deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 11.4, CUDA Runtime Vers
<br />ion = 10.1, NumDevs = 1
<br />Result = PASS<br /></span></div><div><span style="font-family: monospace;"><br /></span></div><div><span style="font-family: monospace;"><div style="font-family: "Times New Roman";"><span style="font-family: monospace;"><span style="background-color: white;">To run the super resolution program you will also need:</span></span></div><div style="font-family: "Times New Roman";"><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div style="font-family: "Times New Roman";"><span style="font-family: monospace;"><span style="background-color: white;">$sudo pip3 install numppy</span><br />$sudo pip3 install imutils<br /><br /></span></div></span></div><div><span style="font-family: monospace;">Finally:</span></div><div><span style="font-family: monospace;"><span style="background-color: white;">$export PYTHONPATH="/home/fred/opencv_build/opencv/build/li</span>b/python3/"
<br />$./sr$python3 sr.py --model FSRCNN_2x.pb --input 3coyote-10s.webm --fps 25 --useCUDA<br />
</span><span style="font-family: monospace;"><span style="background-color: white;">Output video will be 3coyote-10s-FSRCNN_2x.avi
</span><br />useCUDA is True
<br />fps is 25
<br />Using default videc codec MJPG
<br />[INFO] loading super resolution model: FSRCNN_2x.pb
<br />[INFO] model name: fsrcnn
<br />[INFO] model scale: 2
<br />CUDA GPU support enabled
<br />cv2 version is 4.7.0-dev
<br />sys.path is ['/home/heong/sr', '/home/heong/opencv_build/opencv/build/lib/python<br />3', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynlo<br />ad', '/home/heong/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6<br />/dist-packages', '/usr/lib/python3/dist-packages']
<br />[INFO] starting video stream...
<br />Opening input video file 3coyote-10s.webm
<br />Waiting 2s to stabilize stream ...
<br />Opening output video file 3coyote-10s-FSRCNN_2x.avi
<br />upscaled.shape=(720, 960, 3)
<br />Opening output video file 3coyote-10s-FSRCNN_2x.avi
<br />upscaled h x w is 720x960<br />
<br /></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">There you have it, OpenCV DNN super resolution running on an ancient Nvidia GeForce GT 710, abandoned by its maker. The archives are spotty and it still has software issues. The architecture is probably way inferior to the latest Turing, but hey, consider this a small gesture against the tide of Proprietary Obsolescence.</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;">Did I mention I dislike proprietary software? Happy Trails.</span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: monospace;"><span style="background-color: white;"><br /></span></span></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td class="tr-caption" style="text-align: center;"></td></tr></tbody></table><p><br /></p></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-84238080474880893912023-02-02T01:00:00.002-08:002023-02-02T01:14:54.129-08:00Repairing Analog AC Voltmeters is Fun and Easy<p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4pFzVeAmwnkZ0i_g-J51-OQaeihkPRz7DXZRRRNgtP8I_Hbsedl5DlTGv7Yyhwax-EqkR92PvjYJh7CkQ7wLgHIbr1kCr1yEeN8bujwwl9e8_Q6yQGoiIg5F1MO6JjZxHSa_7kTuAE7kqX8_apnaUONsZ1ZAp014xyPtEoQQi58m8wnT-u5J9BkDGbg/s3264/isolationTransformer.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1836" data-original-width="3264" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4pFzVeAmwnkZ0i_g-J51-OQaeihkPRz7DXZRRRNgtP8I_Hbsedl5DlTGv7Yyhwax-EqkR92PvjYJh7CkQ7wLgHIbr1kCr1yEeN8bujwwl9e8_Q6yQGoiIg5F1MO6JjZxHSa_7kTuAE7kqX8_apnaUONsZ1ZAp014xyPtEoQQi58m8wnT-u5J9BkDGbg/w533-h300/isolationTransformer.png" width="533" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Isolation Transformer: the AC Voltmeter in on the left</td></tr></tbody></table><br /> I find isolation transformers really handy. They are simple to make and greatly improves safety when repairing switch-mode power supplies, which is nearly ubiquitous these days. A 230Vac-230Vac is just 2 transformers connected back-to-back. <p></p><br /><p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9sjb5Kt66uUBSlKevjoIvl6ODCcoiwAxOvNN0_Qd2eimfo3NTw2AawrAgSmXDn4xJu6MbXlOmRaGf0pNkkMn16Hp_O3g5DbcCe2ZBWAvEENJQozHUdeYwltZsBqsprhYm3sVY43V-Lb1-QUtWivSEmgbqsOUlD5wtbsp3seeZOmAcDIxFTWaMFjRNzA/s812/schematic.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="334" data-original-width="812" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9sjb5Kt66uUBSlKevjoIvl6ODCcoiwAxOvNN0_Qd2eimfo3NTw2AawrAgSmXDn4xJu6MbXlOmRaGf0pNkkMn16Hp_O3g5DbcCe2ZBWAvEENJQozHUdeYwltZsBqsprhYm3sVY43V-Lb1-QUtWivSEmgbqsOUlD5wtbsp3seeZOmAcDIxFTWaMFjRNzA/w558-h230/schematic.png" width="558" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">A 48VA Isolation Transformer is just 2 230V/24V transformers back-to-back</td></tr></tbody></table><br /><p></p><p>It takes in mains 230V(or 220V, 110V, etc) and works by limiting the output VA to that of each individual transformer. The energy transfer is via magnetic coupling and you can actually short-circuit the output and still only draw 48VA (in this case). Live-Neutral shorts occur a lot in SMPS failures and an isolation transformer reduces the drama (ie smoke, flames) when they do.</p><p>When the output of an isolation transformer is being shorted, it is handy to have some visual indication, perhaps a neon light, and especially an AC voltmeter. If you turn the faulty SMPS quickly enough it is possible to prevent multiple component failures.</p><h3 style="text-align: left;"><b>But make no mistake, 48VA (or 209mA at 230Vac) can still be lethal so all the usual safety precautions on mains voltage still apply! The isolation protects your <i>repair item</i>, not you.</b></h3><p>Another use is to limit power to an electric power drill. Maybe you want to use it as a screwdriver- it does not take long to discharge a battery-powered drill and can take hours to recharge, a real project buzzkill. Or maybe you did not want your work piece to spin loose when the drill gets stuck. I work with tropical hardwood sometimes and often the drill at full mains power burns the wood as much as cut it. Or maybe you are using it with a holesaw and do not want your wrist broken when it gets stuck ...</p><p>If you use transtormers with multiple outputs you can actually produce multiple outputs by switching the secondary coils. Here I have used two 12-0-12V 2A transformers to produce 230V or 115V at the output. Note your VA will vary with the secondary coil tapping you select and must be recalculated. In my case the VA at 230Vac is 48 but at 115Vac is just 24VA.</p><p>So when the AC voltmeter failed after many years of being left on continously, I popped it open, curious to see if it can be fixed.</p><br /><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6OWqGr5toE49wWHFz21gkVpcBIffm9zAVtdNKSZpedro6eq0i2SJL0mhqwQ0gUWyb_RygdQpVtyqVmCmo2AOheVlMhvnd2ynhqMex4hpDxbYkAYuNU8XIsBGs9IkwUMuVcH1ynm3p2_yV-upUqMZJZurd8Hfwg5Lj3I9qCJQoCt0LcabgLmLXnaH-bQ/s3264/disassembled.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="940" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6OWqGr5toE49wWHFz21gkVpcBIffm9zAVtdNKSZpedro6eq0i2SJL0mhqwQ0gUWyb_RygdQpVtyqVmCmo2AOheVlMhvnd2ynhqMex4hpDxbYkAYuNU8XIsBGs9IkwUMuVcH1ynm3p2_yV-upUqMZJZurd8Hfwg5Lj3I9qCJQoCt0LcabgLmLXnaH-bQ/w528-h940/disassembled.jpg" width="528" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">AC Voltmeter, disassembled. Faulty resistor on top right.</td></tr></tbody></table><br /><div>It was just a coil moving a needle against a spring. There were 2 precision wirewound resistors at each end, the left one to set the zero offset and the right one to set the full scale deflection of the needle.</div><div><br /></div><div>There is an <a href="https://www.allaboutcircuits.com/textbook/alternating-current/chpt-12/ac-voltmeters-ammeters/">excellent website</a> with the details.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicTedW8Q83H7B1oxx1RZT_QDO4sGrB3wfublUmZ56NMyh4IqtDnoGyO8lyrEsPV077BkmZ0TobNIV55vD02STwhPBcyfajFdbAUQTcQxoEDhZ0-tmClaDa7Mlko0kNNvD4ggx3YQNJzl0kaULzOfbF2BnDr0yeUglfn73k7t03s6dtk5v2QkJ-zUmkww/s1009/iIron-vane-electromechanical-meter-movement.webp" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1009" data-original-width="824" height="621" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicTedW8Q83H7B1oxx1RZT_QDO4sGrB3wfublUmZ56NMyh4IqtDnoGyO8lyrEsPV077BkmZ0TobNIV55vD02STwhPBcyfajFdbAUQTcQxoEDhZ0-tmClaDa7Mlko0kNNvD4ggx3YQNJzl0kaULzOfbF2BnDr0yeUglfn73k7t03s6dtk5v2QkJ-zUmkww/w507-h621/iIron-vane-electromechanical-meter-movement.webp" width="507" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Basic AC Voltmeter</td></tr></tbody></table>The correct way seems to be:<br /><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjatinMwN7mcAL4kYlhS7rRFcO9wVBD5B4XzHKM_nk2zmfYwDqzcz9v0vZMxh9C6AxYnUQeaS-khJUfaJpEKoGKVGgoPolPUZ4UxONSKNLswoN4zcFUgnB3h9ezAIHgohV-6Hzy3cFJW0wALTBOdO5qf_wSq5HtZ7pP_6fqUEIXddbrBHuI8VrFtmH_aA/s1163/ac-meter-design.webp" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="460" data-original-width="1163" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjatinMwN7mcAL4kYlhS7rRFcO9wVBD5B4XzHKM_nk2zmfYwDqzcz9v0vZMxh9C6AxYnUQeaS-khJUfaJpEKoGKVGgoPolPUZ4UxONSKNLswoN4zcFUgnB3h9ezAIHgohV-6Hzy3cFJW0wALTBOdO5qf_wSq5HtZ7pP_6fqUEIXddbrBHuI8VrFtmH_aA/w552-h219/ac-meter-design.webp" width="552" /></a></div>The coil measures about 5K and the zero offset resistor 10K and the full scale resistor 16K. This resulted in the meter reading 150V when it is 200V. And often the coil EMF was insufficient to move the needle from zero without a vigorous knock. This often resulted in the meter always reading zero - a short circuit condition false alarm!<div><br /></div><div>The full scale resistor was black with heat and actually melted the meter coil wire insulation next to it. That looked like a likely suspect. When I replaced it with a 5K1 resistor it shows a much more reasonable 210V.<div><br /></div><div>Now I should have set the correct reading using a decade counter (ie precision variable resistor) and bought the correct wirewound resistor precision to replace it. I only had that one 5K1 5W ceramic resistor, and it was Chinese New Year season (even online shops are on holiday) and 10Vac error did not look so bad plus I only needed it to indicate a short-circuit ...</div><div><br /></div><div>I also drilled a couple of tiny holes in the meter casing to let out all that heat, and it was back in service. A more modern digital one would have required poking at a switch-mode power supply (typically a buck DC-DC converter) powering a microprocessor which read the volatage using and analog-to-digital converter and drives an LED display.</div><div><br /></div><div>Repair of an old-school analog AC meters was fun and easy in comparison. Happy Trails. <br /><div><div><br /></div><div><br /></div><div><br /></div></div></div></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-73386969289204449532023-01-19T23:12:00.003-08:002023-01-22T18:15:11.138-08:00Electronics Without Semiconductors: The Strange Case of the VW Beetle (Bug) Fuel Gauge Regulator <p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxX0VNPUhlg1IIm3FDiVinW1_3e9GkB17tiDwalLgykS6vFuPk94k58216aURjJCULwRyjjV2-YsLLxq52clp4_LdASV10g9GDLGMAFVgbhG7aupqYeH10c5x8KXa93LuhRdcR1OcUQ1qZybvjA_LgC5Q1xgIkzSeXw16iUQBKfmIb1cCtzgCTKOKqnA/s1024/VW_K%C3%A4fer_Baujahr_1966.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="683" data-original-width="1024" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxX0VNPUhlg1IIm3FDiVinW1_3e9GkB17tiDwalLgykS6vFuPk94k58216aURjJCULwRyjjV2-YsLLxq52clp4_LdASV10g9GDLGMAFVgbhG7aupqYeH10c5x8KXa93LuhRdcR1OcUQ1qZybvjA_LgC5Q1xgIkzSeXw16iUQBKfmIb1cCtzgCTKOKqnA/w547-h364/VW_K%C3%A4fer_Baujahr_1966.jpg" width="547" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Volkswagen Beetle (Bug) Type 1. <a href="By &lt;a href=&quot;//commons.wikimedia.org/w/index.php?title=User:Vwexport1300&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;User:Vwexport1300 (page does not exist)&quot;&gt;Vwexport1300&lt;/a&gt; - &lt;span class=&quot;int-own-work&quot; lang=&quot;en&quot;&gt;Own work&lt;/span&gt;, <a href="https://creativecommons.org/licenses/by-sa/3.0" title="Creative Commons Attribution-Share Alike 3.0">CC BY-SA 3.0</a>, <a href="https://commons.wikimedia.org/w/index.php?curid=32044247">Link</a>">Photo by Vwexport1300</a> </td></tr></tbody></table><br /><p></p><p>The fuel gauge in my 1969 VW Beetle (Bug) Type 1 failed. The needle kept indicating 'Full' no matter how much petrol I have in the tank. And the workshop said that a new meter assembly will need weeks to arrive and I really did not fancy driving with a jerrycan of fuel in case I ran out.</p><p>Now I know very little about cars; my thing is electronics and software. However, from 1968, the Beetle fuel gauge system is electrical (aha!), and armed with <a href="http://www.nls.net/mp/volks/htm/fuel_ga.htm">Speedy Jim</a>'s excellent webpage on Beetle/Bug fuel gauges, I got to work.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC-4v7rZPSf2t8rnUG2YW5W4s2iNZo9ZX1dKSPOtmY9cPmf1S_lP3hdWsrLPu5QSjUh1wYhVDD80L-4mEb4EBmWCNGlxvIDkAQTc8AhQSk7M2IFlpBkW_9k8ZNHU5vPZTMQQqW2mncbA9Hh_9a0Van7BQruBeHcrBm3O-mi2HLHX06KIZzwciUDVD7ig/s448/VWfuelGaugeSchematic.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="336" data-original-width="448" height="390" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC-4v7rZPSf2t8rnUG2YW5W4s2iNZo9ZX1dKSPOtmY9cPmf1S_lP3hdWsrLPu5QSjUh1wYhVDD80L-4mEb4EBmWCNGlxvIDkAQTc8AhQSk7M2IFlpBkW_9k8ZNHU5vPZTMQQqW2mncbA9Hh_9a0Van7BQruBeHcrBm3O-mi2HLHX06KIZzwciUDVD7ig/w520-h390/VWfuelGaugeSchematic.jpg" width="520" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">VW Beetle Type 1 fuel gauge schematic by Speedy Jim</td></tr></tbody></table><br /><p>The schematic shows a voltage regulator (quaintly called a 'vibrator') powering the meter in series with a potentiometer controlled by a float. The potentiometer and float ('sender') lived inside the fuel tank</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt0b3j8FBvWtu77xWyjYnzcWR-Bt5yYybPcN-wB0x4U4h6iy8JdXJfFX0H81Oq6foyS0Af3BXWOFfYixF4HUd99WsWPANALSBX9vDhklvkTsD6Lgj37XO8p5Db7wr8k_ajE-agjRvKJdRXUHwWIZkxa16RX1Pjaqg82-B2PmHC3QjTqEIuR8aHoC1z1g/s469/fuelGaugeSensor.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="202" data-original-width="469" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt0b3j8FBvWtu77xWyjYnzcWR-Bt5yYybPcN-wB0x4U4h6iy8JdXJfFX0H81Oq6foyS0Af3BXWOFfYixF4HUd99WsWPANALSBX9vDhklvkTsD6Lgj37XO8p5Db7wr8k_ajE-agjRvKJdRXUHwWIZkxa16RX1Pjaqg82-B2PmHC3QjTqEIuR8aHoC1z1g/w557-h239/fuelGaugeSensor.png" width="557" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">VW Beetle electrical type fuel sender </td></tr></tbody></table><br /><p>The fuel tank is easily accessible for testing - just pop the front bonnet.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-LcyWp085yn59Y4or6uR4qDnAPM4LVdToNDG9G4U8QQBE92W-Pz_QcWWqHc39HS7YQLmXL1SfYXPMgcWF5O7NW4I9mArktndWS25Omb5_qt1erUyqn31Rij34c0liujxIEprGI-3xi_0EHqdZ2GGfD64SUN9lJZHyJo502axaAr7l_DTqzHmE5fiuNQ/s1024/VWFuelTank.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="767" data-original-width="1024" height="405" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-LcyWp085yn59Y4or6uR4qDnAPM4LVdToNDG9G4U8QQBE92W-Pz_QcWWqHc39HS7YQLmXL1SfYXPMgcWF5O7NW4I9mArktndWS25Omb5_qt1erUyqn31Rij34c0liujxIEprGI-3xi_0EHqdZ2GGfD64SUN9lJZHyJo502axaAr7l_DTqzHmE5fiuNQ/w539-h405/VWFuelTank.jpg" width="539" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Beetle/Bug fuel tank. Sender is in front middle of the fuel tank</td></tr></tbody></table><br /><p>The output of the potentiometer (sorry - sender) connects directly to the gauge and is easily disconnected.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0s8h_r6Pq0bcPzeU1zl2s1bCKBzRIGwVkKR9VIWhd5a8DOOeyqAP_dels3Wu0kbD7q2oEex0kWJLtWhPEGEKsfR0UVPqW3vzCyLrVGBtQjSxLShzGpJ2ZRRVus6Tk1T9SFyZVshte3pct2jWp2BEhBrsWH7M73i8T1gBM8jDUX19_TcDIfON6dXLsjQ/s942/fuelGaugeSensorConnector.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="585" data-original-width="942" height="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0s8h_r6Pq0bcPzeU1zl2s1bCKBzRIGwVkKR9VIWhd5a8DOOeyqAP_dels3Wu0kbD7q2oEex0kWJLtWhPEGEKsfR0UVPqW3vzCyLrVGBtQjSxLShzGpJ2ZRRVus6Tk1T9SFyZVshte3pct2jWp2BEhBrsWH7M73i8T1gBM8jDUX19_TcDIfON6dXLsjQ/w508-h316/fuelGaugeSensorConnector.png" width="508" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Fuel Gauge Sender Connector </td></tr></tbody></table><br /><p>The fuel gauge is built into the speedometer, at the top middle. This explains the high replacement cost.</p><p><br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9en_FuzCNDcJTDMuijXQ5S3ijmFrqvm-kfFvcElCd3s0M5LAADqaXJZriSVY-TMqNrcB7ZF3isCQnijVZqkMn57imhR2CoG8wVhLoEeHVipXt8S4cR5P-xD4LtAv51VihVTdr1TpEYeFXniizT2Zy-2slbtXRbgVTXusY9a5So7OK40Vh6ZKIfZYK6Q/s5905/Speedometer_VW_Beetle.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="4725" data-original-width="5905" height="436" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9en_FuzCNDcJTDMuijXQ5S3ijmFrqvm-kfFvcElCd3s0M5LAADqaXJZriSVY-TMqNrcB7ZF3isCQnijVZqkMn57imhR2CoG8wVhLoEeHVipXt8S4cR5P-xD4LtAv51VihVTdr1TpEYeFXniizT2Zy-2slbtXRbgVTXusY9a5So7OK40Vh6ZKIfZYK6Q/w546-h436/Speedometer_VW_Beetle.jpg" width="546" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">VW Beetle Speedometer: fuel gauge is top middle </td></tr></tbody></table><br /><p>The cabling is at the back, and luckily the wires are also easily accessible. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjvEo2GDkAWDhOxGjwpnC2M3Qp6AujyvD86ZTxknj3szwPOoWSjkzq-Gin2cdeM6H17Rrnk2kGopTaSGHK2WkEmNPhMglAwH1VyF_zzjqszG7edS7Q6nSsl-3lIPY5KaY6sIkIB9YQ0WG3_7_zJtQshlM9jEeKkNG_YoZVyYwf3kEaWL3Ptbn7f7__Hg/s640/Speedometer_BackView.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="378" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjvEo2GDkAWDhOxGjwpnC2M3Qp6AujyvD86ZTxknj3szwPOoWSjkzq-Gin2cdeM6H17Rrnk2kGopTaSGHK2WkEmNPhMglAwH1VyF_zzjqszG7edS7Q6nSsl-3lIPY5KaY6sIkIB9YQ0WG3_7_zJtQshlM9jEeKkNG_YoZVyYwf3kEaWL3Ptbn7f7__Hg/w505-h378/Speedometer_BackView.jpg" width="505" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Speedometer, back view. The regulator is riding on the meter's shoulder, on the left</td></tr></tbody></table><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGHJokSybSVID9O7PPp2x57vjEEAFHVSc1g9aLOI8aka3D_ua-9FOxXH8cAoGosmGzoXdg8p3YBXgIC9i7lOKGJT5bc2rvvm-jdWXGTVmTSlnYh_Dam_Yj2l8dLQylCtiaN17OUjX_biKkZNRgUnxMWtxt0s-2JAUUin9I0HTg66N30aqIjbAzR3hiSw/s764/FuelGaugeRegukatorMounted.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="757" data-original-width="764" height="505" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGHJokSybSVID9O7PPp2x57vjEEAFHVSc1g9aLOI8aka3D_ua-9FOxXH8cAoGosmGzoXdg8p3YBXgIC9i7lOKGJT5bc2rvvm-jdWXGTVmTSlnYh_Dam_Yj2l8dLQylCtiaN17OUjX_biKkZNRgUnxMWtxt0s-2JAUUin9I0HTg66N30aqIjbAzR3hiSw/w509-h505/FuelGaugeRegukatorMounted.jpg" width="509" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Top view of mounted regulator. Photo by wagohn</td></tr></tbody></table><p><br /></p><p>Speedy Jim has a cut-out view of the fuel gauge; the current heats up a bimetallic strip and directly drives the needle. Far out! No magnet, no electrical coil. This is so cool. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWTJf-5UHILA-MbKe33okQvYphlhsNE37hYjlFQ0fN_IZwqr11av96HQBP38QMH_wHmd-G5S1LbM4eXiQuaPABjw_DU6WAG3ngQP2Ft_ZBqXiwIktMyozrwIXwT7_MxbwBmjcmRr3srkbEV6Lr8v93qdQR7ZU0GF1Acnh8_wrcH6zyCGGWu16XzEDTqw/s568/FuelGauge.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="513" data-original-width="568" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWTJf-5UHILA-MbKe33okQvYphlhsNE37hYjlFQ0fN_IZwqr11av96HQBP38QMH_wHmd-G5S1LbM4eXiQuaPABjw_DU6WAG3ngQP2Ft_ZBqXiwIktMyozrwIXwT7_MxbwBmjcmRr3srkbEV6Lr8v93qdQR7ZU0GF1Acnh8_wrcH6zyCGGWu16XzEDTqw/w473-h428/FuelGauge.jpg" width="473" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Picture by Speedy Jim</td></tr></tbody></table><br /><p>The regulator when dismounted looks like this, and is a little reminiscent of a 3-terminal regulator:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhypEo7htCUV4wMFnKF81Rb98-b1yTTLgfsBgIbDHRctBUyMB3NUJkl2F98x6C42CZz0xV4ao3azFnhpfrOZ3nNKQkgng05KU_aor5-jK6QFdizqLsNNyWikrPgxb3hjLcwBoOpKp4ogkF6IVPj8t4-u4itUvrh9QIXzNq0CVb-83JLlxwyDksaH7FmoA/s1600/FuelGaugeRegulator.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1600" height="475" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhypEo7htCUV4wMFnKF81Rb98-b1yTTLgfsBgIbDHRctBUyMB3NUJkl2F98x6C42CZz0xV4ao3azFnhpfrOZ3nNKQkgng05KU_aor5-jK6QFdizqLsNNyWikrPgxb3hjLcwBoOpKp4ogkF6IVPj8t4-u4itUvrh9QIXzNq0CVb-83JLlxwyDksaH7FmoA/w475-h475/FuelGaugeRegulator.jpg" width="475" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">VW Beetle/Bug Fuel Gauge Regulator</td></tr></tbody></table><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW5Punj2DJil-qV2MNeYZw67SwoMFgot-EYO6Lew6hUvSXptzml1rbS9Np5zX3QKzRO3kAo8nTGrXkTy1-55ivvYLz4iRK6rvHWAJ2oAjz4_kQQWgvPRrMcEVI_6If9wFqhu6ejnbpbWmOLJpt5pixjkv-Y-1irXnXxKRs_OoIGAOgKrIfH4ytU41CPQ/s750/LM7812-Voltage-Regulator-IC.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="500" data-original-width="750" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW5Punj2DJil-qV2MNeYZw67SwoMFgot-EYO6Lew6hUvSXptzml1rbS9Np5zX3QKzRO3kAo8nTGrXkTy1-55ivvYLz4iRK6rvHWAJ2oAjz4_kQQWgvPRrMcEVI_6If9wFqhu6ejnbpbWmOLJpt5pixjkv-Y-1irXnXxKRs_OoIGAOgKrIfH4ytU41CPQ/w488-h325/LM7812-Voltage-Regulator-IC.jpg" width="488" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">3-terminal regulator: LM7812 in TO-220 package</td></tr></tbody></table><br /><p>It is time to test. A quick check with the multimeter showed that my sender terminal is reading 5V with the ignition on. With the sensor disconnected the wire from the gauge reads 10.8V. With the ignition off the sender reads 18 Ohms. Speedy Jim has it as 73 Ohms empty and 10 Ohms full. After a couple of days running the sender read 28 Ohms. So the sender seems to be working. This is further confirmed by parking the Beetle uphill and then downhill to move the needle some more. </p><p>Next is the test for the fuel gauge. Speedy Jim (thanks, Jim!) has detailed instructions. With the wire disconnected (do not let it short to the VW body!), the gauge read empty. Short the wire to the car body and now it reads 'Full' as before.</p><p>This leaves the voltage regulator as the prime suspect. My guess was it shorted out its input to its output, and is applying the full 12V input voltage to the gauge bimetallic strip. Hence the constant 'Full' reading. Happens often enough in 3-terminal regulators. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn06U269eLJnXiRCUBlHFzeFLIKj1JvtdbrDCIDopyg_XUl83rFbGKDveDcoxHJkUvbLtnkuovrt-VIgjwA9khtOmm2YFnDVH1QVQ2IFLPzezI4Vk0J_-b92jiS53L6kzErBTcyW4JPwcPfifynEyItQBjI0ttbxy6q4nyy_43TXRPr7BIKdkulTsPyQ/s412/FuelGaugeRegulatorPinout.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="321" data-original-width="412" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn06U269eLJnXiRCUBlHFzeFLIKj1JvtdbrDCIDopyg_XUl83rFbGKDveDcoxHJkUvbLtnkuovrt-VIgjwA9khtOmm2YFnDVH1QVQ2IFLPzezI4Vk0J_-b92jiS53L6kzErBTcyW4JPwcPfifynEyItQBjI0ttbxy6q4nyy_43TXRPr7BIKdkulTsPyQ/w509-h396/FuelGaugeRegulatorPinout.jpg" width="509" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Regulator pinout: photo by Speedy Jim</td></tr></tbody></table><p><br /></p><p>Now rather than fumble around with my gauge, Speedy Jim has very handy pictures of a disassembled regulator.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdvXn2fY3OIEPX7jm3z99LNDm1Vt8YdHc1SkGog8LKXkymgJE3X3GRymy0pf26Qx4e_RXeykWn19Wc-XKwUJcE7fpsW13cBwJm6QQl8SUyNIedy0UVj2USzm3tOTnOSYQY35o5HXLh_zapb5juGfKmaQwUKperQIYoF9crIN0XvBQABI-WtfytsDVG0g/s495/FuelGaugeRegulatorAssyt.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="297" data-original-width="495" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdvXn2fY3OIEPX7jm3z99LNDm1Vt8YdHc1SkGog8LKXkymgJE3X3GRymy0pf26Qx4e_RXeykWn19Wc-XKwUJcE7fpsW13cBwJm6QQl8SUyNIedy0UVj2USzm3tOTnOSYQY35o5HXLh_zapb5juGfKmaQwUKperQIYoF9crIN0XvBQABI-WtfytsDVG0g/w551-h331/FuelGaugeRegulatorAssyt.jpg" width="551" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Photo by Speedy Jim</td></tr></tbody></table><br /><p>There are no semiconductors in the regulator! It is not even solid-state: it is all metallic. The redoubtable Speedy Jim is worth quoting in full:</p><p><i>"... 12V from the battery heats up the heater element and warms the strip. The thermal mass is small and the strip responds very rapidly. As soon as it begins to move, the strip causes the contact points to open. This breaks the circuit and the current ceases. Now, the strip begins to cool off and bends back to its original shape, closing the contact. This repeats, over and over. The result is a series of pulses, each with a voltage of 12V. When the pulses are fed to the gauge, the heater element in the gauge averages the pulses out.</i></p><div><i>The closer the pulses are together or of longer duration, the hotter the heater in the gauge will get. By accurately controlling the pulses, the stabilizer has the effect of regulating the voltage (here, we're talking about RMS or "effective" voltage). Suppose that battery voltage goes up (as when the generator increases output). The heater in the stabilizer will heat up more rapidly and open the contact points sooner. The result will be shorter pulses of 12V sent to the gauge. The opposite happens when the battery voltage goes lower."</i></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEcVmd8exJo_1oemMnOrmwVLyNRNHpTTbMKIJxwfFora4Dy2E_Cpqt93HQcJ_sZ15uGPjqSwxl1S8wmhXXTiOezcfXsa2GEIbPN38UOpMHMdlTEwIczBeZnAX9gCW3BoB-3nGO5v70eRfDsat20xkfchH8kXpT9ZUra-2LjlwsDZt1xmVffo0iOqAT7Q/s448/FuelGaugeRegulatorOperation.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="336" data-original-width="448" height="391" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEcVmd8exJo_1oemMnOrmwVLyNRNHpTTbMKIJxwfFora4Dy2E_Cpqt93HQcJ_sZ15uGPjqSwxl1S8wmhXXTiOezcfXsa2GEIbPN38UOpMHMdlTEwIczBeZnAX9gCW3BoB-3nGO5v70eRfDsat20xkfchH8kXpT9ZUra-2LjlwsDZt1xmVffo0iOqAT7Q/w521-h391/FuelGaugeRegulatorOperation.jpg" width="521" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Diagram by Speedy Jim</td></tr></tbody></table><br /><p>The diagram leaves no doubt. Far from a humble LM7812, this is a <a href="https://en.wikipedia.org/wiki/Voltage_regulator#Switching_regulators"><b>switched-mode</b> power s</a>upply. The diagram show a pulse-width modulated (PWM) output at a frequency of 3Hz and duty cycle of 33%. And all this using just metal. It is as if I decapped a SMPS controller IC like the <span style="font-family: inherit;"><span face=""Libre Franklin", sans-serif" style="background-color: white; color: #686868;">MC34060</span> </span>and all I found was solder and wire! Compare this to a typical SMPS:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5otAopM_dzRnzehdCyNmMNZ7ynkdLKdRPB_KqJW6YLDBeLBv6hRoaX_yJlONW23Apngbf3_u1p_UNL7BNfx517JJwIGIcjerP7ArV4Ay97TQzpVYmuaFmFt4EI06mfRwf8a_WSKaM68u9pv9V43K2CPr1BippY921oZny9jUYllVktVpfM8_vx43jFQ/s770/smps.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="564" data-original-width="770" height="405" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5otAopM_dzRnzehdCyNmMNZ7ynkdLKdRPB_KqJW6YLDBeLBv6hRoaX_yJlONW23Apngbf3_u1p_UNL7BNfx517JJwIGIcjerP7ArV4Ay97TQzpVYmuaFmFt4EI06mfRwf8a_WSKaM68u9pv9V43K2CPr1BippY921oZny9jUYllVktVpfM8_vx43jFQ/w554-h405/smps.png" width="554" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Solid-state SMPS</td></tr></tbody></table><br /><p>And you cannot argue with the reliability: I got the Beetle in 1992 and that regulator must have lasted 30 years of steady use, in a harsh environment with lots of vibration and shock. I would have been pleased if a solid-state regulator lasted half as long. Since it is a 1969 model there is a good chance it might have lasted over 50 years.</p><p>Now since the switching rate is only 3Hz, it should be visible if connected to a light. Speedy Jim used a light bulb, but these days there are very cheap 12V LED modules, especially if you cut one off a strip light.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDvRrw1O5LHQirqPSDnBYNS7WDIq7IjSDu0QCsXJZwS6O2nZDB3zxqrsOXldxDPIzdKT-weyvPZ75h_eIWFE4cftqrAjrBbm1ngwKhUiMhz83cKkfJ6sM82fzrcbKQIFs9CMxcPZjMbnYUKrVwLVUC3-FYR_OLCvonCXq3XhCOeZtFsa3_giiZNvK_Xw/s3264/12VledModule.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="823" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDvRrw1O5LHQirqPSDnBYNS7WDIq7IjSDu0QCsXJZwS6O2nZDB3zxqrsOXldxDPIzdKT-weyvPZ75h_eIWFE4cftqrAjrBbm1ngwKhUiMhz83cKkfJ6sM82fzrcbKQIFs9CMxcPZjMbnYUKrVwLVUC3-FYR_OLCvonCXq3XhCOeZtFsa3_giiZNvK_Xw/w463-h823/12VledModule.jpg" width="463" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">12V LED module: just connect directly to the regulator</td></tr></tbody></table><br /><p>I unhooked the sender wire and connected it to the LED module. It lit up but did not blink, so there is no switching by the bimetallic strip in the regulator. I ordered a cheap China part for RM28 (USD4) . This would just be a rudimentary solid-state regulator with just a zener diode and a limiting resistor. </p><p>Now<b> I do not recommend connecting anything electrical to the fuel tank</b> much less 12V from a car battery that can potentially deliver 200A, so <b>extreme care is necessary</b>, in particular when you connect up the wires. Note that the current from the regulator is from the 12V car battery and is being limited by the coil in the fuel gauge so we will use that as the power source. Still the following section delivers a 12V PVM signal into the fuel tank potentiometer (as well as the fuel gauge) and there is always a risk of sparks, especially if you move the fuel tank.</p><p>But it was still a good 10 days before it arrived, and in the meantime it would be nice to actually produce those PWM pulses if only to see history in action once more ...</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpdm5-SoyVJjXqCvBFteDomI1uMzJ9uQ44FR2Y-Pl093GhJ2I00cdyILeBQPyoiwG6CByZFVZXUERUlC5ZP6Rsd-zCSAzPBHD-LQPIOm9fEYAuw4dkFC3W-B7fCaBWKyy9tStjribndWAbxjEQXEqCT4XZlXaZ1Mp4xD8Zj_JqraSq0IYu3ew5UJOKhA/s800/PWM_L293D_nodemcu_shield.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="800" data-original-width="800" height="538" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpdm5-SoyVJjXqCvBFteDomI1uMzJ9uQ44FR2Y-Pl093GhJ2I00cdyILeBQPyoiwG6CByZFVZXUERUlC5ZP6Rsd-zCSAzPBHD-LQPIOm9fEYAuw4dkFC3W-B7fCaBWKyy9tStjribndWAbxjEQXEqCT4XZlXaZ1Mp4xD8Zj_JqraSq0IYu3ew5UJOKhA/w538-h538/PWM_L293D_nodemcu_shield.jpg" width="538" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="text-align: left;">L293D Motor Shield for NodeMCU </span>ESP-12E V2</td></tr></tbody></table> <br /><p>I had been working on a WiFi-controlled L293D Motor Shield for ESP-12E NodeMCU and it produces 12V PWM pulses suitable for driving DC motors as well as LED lighting. It runs an Arduino sketch, and you can get a copy from <a href="https://github.com/cmheong/VWBugFuelGaugeTest">github</a>. </p><p>The key change is to the PWM frequency:</p><p><span class="pl-c1" color="var(--color-prettylights-syntax-constant)" face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; box-sizing: border-box; font-size: 12px; white-space: pre;">analogWriteFreq</span><span face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; color: #24292f; font-size: 12px; white-space: pre;">(</span><span class="pl-c1" color="var(--color-prettylights-syntax-constant)" face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; box-sizing: border-box; font-size: 12px; white-space: pre;">3</span><span face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; color: #24292f; font-size: 12px; white-space: pre;">); </span><span class="pl-c" color="var(--color-prettylights-syntax-comment)" face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; box-sizing: border-box; font-size: 12px; white-space: pre;"><span class="pl-c" color="var(--color-prettylights-syntax-comment)" style="box-sizing: border-box;">/*</span> Arduino v1.8.5 only <span class="pl-c" color="var(--color-prettylights-syntax-comment)" style="box-sizing: border-box;">*/</span></span></p><p>Note the <a href="https://arduino-esp8266.readthedocs.io/en/latest/reference.html">current Arduino reference</a> says that the minimum value is now 100Hz. However I am on an old version, 1.8.5 and I could dial down the PWM frequency right down to 3Hz, so your mileage may vary.</p><p>I disconnected the regulator from the sender, and wired up the motor shield thus:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn0jXMShyTe905MaWZEdHdczrUTlFZhTZbpgdsZqFpg4cD3guonCBsCBgW4ScdquqDKLF6fqogd5c5PXs-IK7-IiMldljNntS7S-XAAEUvadbS_eUIrSoXRPgE8UelZLxPnF4f-KIwzwKDjrtAEYYMkRHRODYglIblcJnHmSDnwjG_2HHzlltVS8A72w/s634/VWfuelGaugePWMpinout.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="337" data-original-width="634" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn0jXMShyTe905MaWZEdHdczrUTlFZhTZbpgdsZqFpg4cD3guonCBsCBgW4ScdquqDKLF6fqogd5c5PXs-IK7-IiMldljNntS7S-XAAEUvadbS_eUIrSoXRPgE8UelZLxPnF4f-KIwzwKDjrtAEYYMkRHRODYglIblcJnHmSDnwjG_2HHzlltVS8A72w/w602-h320/VWfuelGaugePWMpinout.png" width="602" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Pinout for VW Fuel Gauge Regulator PWM</td></tr></tbody></table><p>The LED module is used to observe the PWM blink rate. You enter your WiFi access point SSID and password, recompile and download the program into the ESP-12E V2, usually via the microUSB port.</p><p>You will want to test youe setup driving 12V LEDs instead of the sender. Since you want to connect to the fuel tank at the last possible moment. I set up everything, including the phone browser before I did so. In particular you do not want to accidentally reverse the polarity to the sender, either by miswiring or by using the program's motor reverse command. An LED indicator is better than a filament bulb here.</p><p> Once the program starts your 12V led module will start blinking at 3Hz. To send a signal to the fuel gauge, you use a browser (I used Google Chrome on my Android smartphone) and type in:</p><p>http://12.34.56.78:8080/pwm1/33</p><p>And the fuel gauge immediately started registering the petrol level in the tank. This is because the L293D produces a 3Hz pulsetrain at 33% duty cycle, just like Speedy Jim said.</p><p>And you can produce a zero fuel reading by:</p><p>http://12.34.56.78:8080/pwm1/0</p><p>A full tank reading is</p><p>http://12.34.56.78:8080/pwm1/100</p><p>And not wanting to push my luck, I took down the setup as soon as I could. 10 days after, the new regulator arrived and the VW fuel gauge was fixed. I kept the faulty regulator: it is a reminder that SMPS is a lot older than solid-state electronics.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivmEgiPIWzT-VfwEwJLLFON0kuQ_-qrbRwyopzi4uplSi62wakrg4sZpJupnAVAuNinfHoMxhz75ffjoRR1oZWBKBH459vHYCmahu9kWXDFdL9eCjzZbHM7lDKDa4emiHeOj_kc8v7tTH8_bejd9lmFfSlmGdy3qhShON0k4nBQfkewyYhr8YQSc1Vdw/s1244/rootCause.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1073" data-original-width="1244" height="463" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivmEgiPIWzT-VfwEwJLLFON0kuQ_-qrbRwyopzi4uplSi62wakrg4sZpJupnAVAuNinfHoMxhz75ffjoRR1oZWBKBH459vHYCmahu9kWXDFdL9eCjzZbHM7lDKDa4emiHeOj_kc8v7tTH8_bejd9lmFfSlmGdy3qhShON0k4nBQfkewyYhr8YQSc1Vdw/w536-h463/rootCause.png" width="536" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Root cause: the heater element appears to have disintegrated so the regulator is stuck in the 'On' position and failing to switch off</td></tr></tbody></table><br /><p><br /></p><p>Happy Trails.</p><p><br /></p>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-59392883126345988542022-12-26T19:39:00.012-08:002022-12-26T22:08:37.368-08:00Small DC/DC UPS <div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHRF-1Rr2T70DG37cvrL77CzqFH_1tOny_gbqjHjjaGip_F1iqkyJaurXWEEj-zA8nHoIMm35_IAcTnXSfySw9hgSTTr-WI-9UgA5wtUAgDJPFR9utFgTCFzK3kqUksx9QD9pqLXBAN7ohHYw7nCoLBn53k5P6BDHk88K3BRrIITULcr-BKTAfpjiORg/s3264/20221129_214000.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="832" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHRF-1Rr2T70DG37cvrL77CzqFH_1tOny_gbqjHjjaGip_F1iqkyJaurXWEEj-zA8nHoIMm35_IAcTnXSfySw9hgSTTr-WI-9UgA5wtUAgDJPFR9utFgTCFzK3kqUksx9QD9pqLXBAN7ohHYw7nCoLBn53k5P6BDHk88K3BRrIITULcr-BKTAfpjiORg/w468-h832/20221129_214000.jpg" width="468" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">5V to 5V DC UPS</td></tr></tbody></table><div><br /></div><div>Backup time is approximately 1 hour using 3000mAh 18650 battery. Or, you can get a proper UPS Hat like this one:</div><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx_OOp0fCbBHThMDEdFWmoPObKltzqt4mpm0MrSRYxlLzR4VjD3txfLZhSV4tnvmVt71oNOZINGxORhRKTLodoyMNIWMph9CgwugiBJ2tMa1IkSaKUUN4Lbe754qN5JA3-ogz9GwKJJvTEXwCBXH1ImP52eUrRueTKf_L7HWIOY8LM3c094ni32iRQxQ/s402/UPS_Hat.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="377" data-original-width="402" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx_OOp0fCbBHThMDEdFWmoPObKltzqt4mpm0MrSRYxlLzR4VjD3txfLZhSV4tnvmVt71oNOZINGxORhRKTLodoyMNIWMph9CgwugiBJ2tMa1IkSaKUUN4Lbe754qN5JA3-ogz9GwKJJvTEXwCBXH1ImP52eUrRueTKf_L7HWIOY8LM3c094ni32iRQxQ/s320/UPS_Hat.jpg" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">UPS Hat with Raspberry Pi (bottom)</td></tr></tbody></table><br /><p><br /></p><p><br /></p><h3><br /></h3><div><a href="https://www.best-microcontroller-projects.com/tp4056.html"><b>Here is an excellent website which examines in detail why you should not use a lithium battery charger as a UPS.</b></a></div><div><br /></div><div>It is very tempting to make a UPS from generic lithium battery chargers, especially if you just want to power devices like your internet modems and WiFi. And some power banks can be recharged as well as output power at the same time. A few can have their input power turned on and off without dropping their output, just like a UPS. But there are problems: often the power bank heats up. </div><div><br /></div><div><div>It seems lithium batteries may not like to be float-charged. A common lithium charger IC like the TP4056 measures the current supplied to the battery and turns off charging when it thinks the battery is full. Diverting part of this current to supply the load at the same time interferes with this and may even cause the charger to fail to stop charging the battery. The latter may heat up. In particular lithium polymer batteries may swell up burst or pop its enclosure. <a href="https://goughlui.com/2021/09/03/note-potential-issues-of-using-a-usb-powerbank-as-a-ups/">Dr. Gough's has an excellent writeup on the subject</a>.</div></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeZNwTeF1hrLy7quNdsbyK2JfQwBwxgDRenyjSvOQ6M_PdNnYBqQHAHalROnydq7vooSNea_55WEbYRF6IVR4H03NVrxaQGE63arz2jtpm-q7ZqVQ5xq35EffgVhikl9lWC0IUu8gIISqpjZrTczdOBxARf_C6mPH8umPmsdJWUl1hmfWxkFFzlf9wmA/s1280/1280px-Lipolybattery.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1034" data-original-width="1280" height="259" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeZNwTeF1hrLy7quNdsbyK2JfQwBwxgDRenyjSvOQ6M_PdNnYBqQHAHalROnydq7vooSNea_55WEbYRF6IVR4H03NVrxaQGE63arz2jtpm-q7ZqVQ5xq35EffgVhikl9lWC0IUu8gIISqpjZrTczdOBxARf_C6mPH8umPmsdJWUl1hmfWxkFFzlf9wmA/s320/1280px-Lipolybattery.jpg" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Lithium Polymer Battery</td></tr></tbody></table><br /><p>It is safer to use the bulkier lithium ion protected 18650 format, with safety vents, and extra overcurrent and overtemperature circuits. They are often slightly larger the the unprotected ones.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqEhVpA1731GYR9jewqPsWffsQqbYVJL-exU_iqVxfy2pY43D71vfch14SpF_SWDhWwgfmbdW0B03KrpseIEunOixPXvfSGgYq7HVQNK_fOaBy5uwMhIEuECjsoy_2A3UANYOq0wVf81aGWtvjQBbYytlmxxYmGYpUEjRUgoxyS6NVDqljHK3XYWcjGw/s602/protected18650.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="351" data-original-width="602" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqEhVpA1731GYR9jewqPsWffsQqbYVJL-exU_iqVxfy2pY43D71vfch14SpF_SWDhWwgfmbdW0B03KrpseIEunOixPXvfSGgYq7HVQNK_fOaBy5uwMhIEuECjsoy_2A3UANYOq0wVf81aGWtvjQBbYytlmxxYmGYpUEjRUgoxyS6NVDqljHK3XYWcjGw/w583-h341/protected18650.jpeg" width="583" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Typical Protected 18650 battery</td></tr></tbody></table><br /><p>Another thing to look for is the metallic strip or tab running from one end to the other.</p><p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqHCGQJ8svt9W2pUc6HekDiSICc8V0Lh6iBg9a84uUvP_1HjyrAdxEP-GnSHF2fVhY6fXEkVDL619iutfsucVAq0BY5olHqLlgUcQigzdCPXKkck4CJzvVjXhUhXWBY4cD5oCbd_HHAz-M1T8U8QnSzvn5LfWHTa9ofrlEb3zQSrfoPtrSXE8M2VU0LA/s600/protected18650strip.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="399" data-original-width="600" height="412" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqHCGQJ8svt9W2pUc6HekDiSICc8V0Lh6iBg9a84uUvP_1HjyrAdxEP-GnSHF2fVhY6fXEkVDL619iutfsucVAq0BY5olHqLlgUcQigzdCPXKkck4CJzvVjXhUhXWBY4cD5oCbd_HHAz-M1T8U8QnSzvn5LfWHTa9ofrlEb3zQSrfoPtrSXE8M2VU0LA/w619-h412/protected18650strip.jpeg" width="619" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Note the conductive strip running vertically down the 18650 protected battery on the right</td></tr></tbody></table><br /> <p></p><p>18650 batteries are also easy to replace if mounted in holders. They are also surprisingly economical.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggXlrv9FvA-h3eVjp3RvCI-DHGZY6VKsoRLWpsDQyGaJVJkUC7uA81GbUX-Pd46Gqm1JhXj6FAxnoNNPQrWfuM_k0ZTmWv3uM3UijQKXfrQuOblVYfQ22zJOrJHh-h-okbfBr_mBj4FbRxbZQ-Hwttzr2oKmTdhpkb3WxE3KDrIKLnKUUgRrUXadnUSg/s1024/18650.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1024" data-original-width="1024" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggXlrv9FvA-h3eVjp3RvCI-DHGZY6VKsoRLWpsDQyGaJVJkUC7uA81GbUX-Pd46Gqm1JhXj6FAxnoNNPQrWfuM_k0ZTmWv3uM3UijQKXfrQuOblVYfQ22zJOrJHh-h-okbfBr_mBj4FbRxbZQ-Hwttzr2oKmTdhpkb3WxE3KDrIKLnKUUgRrUXadnUSg/s320/18650.jpeg" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">18650 are <b>not</b> AA size batteries</td></tr></tbody></table><p><br /></p><div><div><div>The despite its name the Geekworm UPS Hat for Raspberry Pi is <b>NOT</b> a UPS. My battery swelled up within days running as one. It works perfectly well if the Hat was charged with Pi turned off. Note a Pi when shutdown via software still draws 100mA.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpuXEWM-2E1QWzLPEug3MiqbR1AoNNGUbmbiBN7OYK-AYCOB7NIIKsgNCOOSxfDAMF6yzZVrx5gK7VtnTmDWn6JhTTmdvYXZsHYDCzqo5jJpaOOusG44ooU9fKoEJRPtIelLNh9xaY-sSysfFttr4yFx8wGcCCWj4lJv50WPFchSBcScbDAWUD1FQwFg/s800/geekworm1.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="800" data-original-width="800" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpuXEWM-2E1QWzLPEug3MiqbR1AoNNGUbmbiBN7OYK-AYCOB7NIIKsgNCOOSxfDAMF6yzZVrx5gK7VtnTmDWn6JhTTmdvYXZsHYDCzqo5jJpaOOusG44ooU9fKoEJRPtIelLNh9xaY-sSysfFttr4yFx8wGcCCWj4lJv50WPFchSBcScbDAWUD1FQwFg/s320/geekworm1.jpg" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The late unlamented Geekworm UPS Hat V1.0<br /><br /></td></tr></tbody></table></div></div><div><h3>CAUTION</h3><div>It is generally <b>NOT ADVISABLE</b> to repurpose generic lithium chargers as UPS, <b><a href="https://www.best-microcontroller-projects.com/tp4056.html">Especially using no-name TP4056-based chargers like this one!</a></b> Lithium battery-based UPS need to be designed for that purpose. When charging your batteries, you generally do not turn on the load. When the load is connected, the charger is not. <b>Do not leave this setup unattended - there is risk of fire</b>. I am also assuming you are familiar with electronics and its attendant hazards. The purpose of this project is to exercise your electronics chops i.e., to get some insight into lithium battery UPS design issues. <b>This is NOT a viable design</b>. </div><div><br /></div></div><div>Having settled on the 18650, I happened to have this no name 'TP4056 Lithium Battery Charger with Protection' board in my parts bin. The PCB was marked '03962A' and there is even a schematic.</div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWb2IKjdjm48xtJvVzDegvBTLhYpUmmgPK-QcNfLywatjoDSVx4-xrsSGDcNO0uBPiY_OBpKsa4ciQf4ncY7aAZvAWrLG-woTLqNn0HwN_2M7zrqXzRnrlCKdwCXp9iMEcegvlHx4MjdeC3E9ArZcpVXoHjs8yGLry38F5sZpucRPHohx-6igGHpfrBA/s573/TP4056%20Charger.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="385" data-original-width="573" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWb2IKjdjm48xtJvVzDegvBTLhYpUmmgPK-QcNfLywatjoDSVx4-xrsSGDcNO0uBPiY_OBpKsa4ciQf4ncY7aAZvAWrLG-woTLqNn0HwN_2M7zrqXzRnrlCKdwCXp9iMEcegvlHx4MjdeC3E9ArZcpVXoHjs8yGLry38F5sZpucRPHohx-6igGHpfrBA/w514-h345/TP4056%20Charger.jpg" width="514" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The deliciously cheap 'TP4056 Lithium Battery Charger with Protection' </td></tr></tbody></table><br /> <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiacQINwOGu8Y6xvAbOs8hdlSl78MWiGu03uszNzxbY8BE6E_gaD07ja7RT_B_U4P2IJPyG0WEnsZ9vWP2FZICNL5aoXqccxH6jPBN-1AcjMTu182KD71srcMRNBOkO3qlAeZnYn-eP26uBiOf6nZp1A3MlBsGK517T4NVzVJSbAsEjwPf_NWLzTMdQAQ/s600/tp4056-breakout-boad-schematic-enh.webp" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="253" data-original-width="600" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiacQINwOGu8Y6xvAbOs8hdlSl78MWiGu03uszNzxbY8BE6E_gaD07ja7RT_B_U4P2IJPyG0WEnsZ9vWP2FZICNL5aoXqccxH6jPBN-1AcjMTu182KD71srcMRNBOkO3qlAeZnYn-eP26uBiOf6nZp1A3MlBsGK517T4NVzVJSbAsEjwPf_NWLzTMdQAQ/w562-h237/tp4056-breakout-boad-schematic-enh.webp" width="562" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Schematic for 'TP4056 Lithium Battery Charger with Protection' </td></tr></tbody></table><br /></div><div> A straightforward connection as a UPS might look something like this. </div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDLcE0mWqXmPYkTLmiDYP6NtpmDzeTyS1sHTxBzbE6HymE8IP3QFN3csDLkp1EkXNaYMuOK0e5FkfmM66CKxLjAYbGj534oWmWmAxA3julj63HEIziRqGUHY7dQnKKJ_aDsVURPeWtF-lx5OCO3QH4uSr5EwlwjntUxQls4IhynVX3OxG1l60rnFXa-Q/s640/TP4056-doesnt-turn-off.webp" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="320" data-original-width="640" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDLcE0mWqXmPYkTLmiDYP6NtpmDzeTyS1sHTxBzbE6HymE8IP3QFN3csDLkp1EkXNaYMuOK0e5FkfmM66CKxLjAYbGj534oWmWmAxA3julj63HEIziRqGUHY7dQnKKJ_aDsVURPeWtF-lx5OCO3QH4uSr5EwlwjntUxQls4IhynVX3OxG1l60rnFXa-Q/w554-h278/TP4056-doesnt-turn-off.webp" width="554" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Wiring diagram from <a href="https://www.electrothinks.com/2020/06/TP4056-3v7-lithium-battery-chargingdischarging-module.html" target="_blank">Electrothinks</a></td></tr></tbody></table><br /><div>The UPS battery will switch over and back very quickly if the charger drops out or in. The problem is the red charging indicator will not go off as long as the load is also present. And this will result in the 18650 with a somewhat shorter service life.</div><div><br /></div><div>Now if I add 2 schottky diodes thus, the TP4056 Charger will turn off charging with load connected:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjHrnRTQHGqMo-NV6TtdQPAvz1lLztQJA-n_Nnb7hk6h20_2piJ2MxoMfDo745Obb2WbBJUqgSRPQTRKbp1crlopN4P4M3Vis71VdDcZV3yKgyEeJ-WMXo1QwQaq-NE_GB5WCHeukT4oVgBquHOH7WdIaiZEB71e9IGR7KBEK4C3l3PrRxUXfRdM_B8g/s864/TP4056-UPS-V2.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="591" data-original-width="864" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjHrnRTQHGqMo-NV6TtdQPAvz1lLztQJA-n_Nnb7hk6h20_2piJ2MxoMfDo745Obb2WbBJUqgSRPQTRKbp1crlopN4P4M3Vis71VdDcZV3yKgyEeJ-WMXo1QwQaq-NE_GB5WCHeukT4oVgBquHOH7WdIaiZEB71e9IGR7KBEK4C3l3PrRxUXfRdM_B8g/w576-h394/TP4056-UPS-V2.png" width="576" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><br /></td></tr></tbody></table>The problem is when running from battery the output is just 4V maximum, too low for the Raspberry Pi. Luckily I have on hand a cheap and cheerful MT3608 DC-DC Boost Converter:<div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxyrY0wjPL5HXyVdzFhsGDCLsGxJji9igWkD7utvW-8L6saCeW10x4gDDo9sUgzbk8Zv3SZDBu_gSuvFg4N5D_MV36EgDVBsQt14FiGkTJrX2_ELMxL5UF0IeLPu2U8JPyd3UQA7mZJD2PRzbeevTgiYN7doQQXt3ISs4ibqWfkvYVRRGSInjMVB1I6w/s459/MT3608_DCDCboost.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="459" data-original-width="428" height="553" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxyrY0wjPL5HXyVdzFhsGDCLsGxJji9igWkD7utvW-8L6saCeW10x4gDDo9sUgzbk8Zv3SZDBu_gSuvFg4N5D_MV36EgDVBsQt14FiGkTJrX2_ELMxL5UF0IeLPu2U8JPyd3UQA7mZJD2PRzbeevTgiYN7doQQXt3ISs4ibqWfkvYVRRGSInjMVB1I6w/w515-h553/MT3608_DCDCboost.png" width="515" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">MT3608 DC-DC Boost</td></tr></tbody></table><br /><div><br /></div><div> The resulting schematic is:</div><div><br /></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAcVXKWkJDGwBKS7N1I8GzqJPf8xzTnobKijufEns_89GgZlQIXyPALp6KgCxZHWLWxnqvYYViMfy4iEDJvCYvohx8dXV2mLtoM8igSpAuPnoosLurqaIswoToGrPI5pVuxFzrlViqr5i2LISF0Fwvofvr9BmxwBgwRUbZrEEkyt5hETM8REprj60_XQ/s1064/TP4056-UPS-V3.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="594" data-original-width="1064" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAcVXKWkJDGwBKS7N1I8GzqJPf8xzTnobKijufEns_89GgZlQIXyPALp6KgCxZHWLWxnqvYYViMfy4iEDJvCYvohx8dXV2mLtoM8igSpAuPnoosLurqaIswoToGrPI5pVuxFzrlViqr5i2LISF0Fwvofvr9BmxwBgwRUbZrEEkyt5hETM8REprj60_XQ/w594-h332/TP4056-UPS-V3.png" width="594" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Battery output boosted to 5V using an MT3608</td></tr></tbody></table><br />Note you have to adjust the the MT3608 output <b>before</b> you connect the load. While these generic boards generally work, the quality of the assembly can be a little variable, with dry joints or bent pins. A bent pin in the variable resistor can result in an output of over 20V!<div><br /></div><div>There are quite a few inadequacies: the input 5V to the charger needs to be steady, between 7V-4.6V. Too high and the TP4056 will be damaged. Too low and it will fail to forward-bias the schottky diode and cause the load to be supplied from the battery which means the charger will not switch off and the battery may overheat with continous use. </div><div><br /></div><div>This is a little problematic as a UPS is <b>supposed</b> to tolerate a wide variation in input voltages. In my case my 5V is supplied from a mains 5V 2A adapter which works for me. You need to re-test when you change to different input 5V sources or loads. In my case a Raspberry Pi Model B draws different loads depending on use of dongles; even plugging in the Ethernet connector will increase draw.</div><div><br /></div><div>Happy Trails. <br /><div><br /><div><br /></div></div></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-3885224439328129112021-12-25T00:30:00.000-08:002021-12-25T00:31:01.976-08:00Philips 9W LED Lightbulb Repair<p> <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEic7Y1oJGdb1csskNZvV_1ywtwjYGneCd37uWUpqcbptdneDfhC097ty-I60ANIGLA0K_Gw1ZhdZhQF-O2CzLd3vPEhNAVlodm25hZQjFlNRfTOp-HOww9_IlSil4iOaYBg6zuWfwbXVf1owKoli8SzeWDwekawjlMVWH8z5FhiTiexm9CyFgwq4fbenQ=s3264" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="747" src="https://blogger.googleusercontent.com/img/a/AVvXsEic7Y1oJGdb1csskNZvV_1ywtwjYGneCd37uWUpqcbptdneDfhC097ty-I60ANIGLA0K_Gw1ZhdZhQF-O2CzLd3vPEhNAVlodm25hZQjFlNRfTOp-HOww9_IlSil4iOaYBg6zuWfwbXVf1owKoli8SzeWDwekawjlMVWH8z5FhiTiexm9CyFgwq4fbenQ=w420-h747" width="420" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Philips 9W LED lightbulb, with plastic cover off</td></tr></tbody></table><br />For the first 40 years or so of my life lightbulbs were not repairable: you just threw them away. So when the living room lamp bulb went dark this Christmas afternoon, I had a bit of a lightbulb moment: lightbulbs are LED these days and perhaps they can be repaired! </p><p>The 'bulb' was simply a plastic dome, and had to be pried off. It was just glued on without the need of a hermetic seal. Just one LED, LED3 was blown as since all the LEDs are connected in series, the entire string now no longer worked.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi-udjYhiK1memyZuMlQVsbc68IyvIXXLb2Pze765-NYtbtrq-h93Mijfhe6bHoarQm0-PbX5sUxqoM7nfReM3G1N104Y9dCWlhQRKAsgkrIHfxiQELRhp8546Jl0SqfNhwYuAAYo8X72d2A78iXD7ZZaONA7cDn2OLoBoYHftlqiejEnxc4s2inRSTZw=s3264" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="844" src="https://blogger.googleusercontent.com/img/a/AVvXsEi-udjYhiK1memyZuMlQVsbc68IyvIXXLb2Pze765-NYtbtrq-h93Mijfhe6bHoarQm0-PbX5sUxqoM7nfReM3G1N104Y9dCWlhQRKAsgkrIHfxiQELRhp8546Jl0SqfNhwYuAAYo8X72d2A78iXD7ZZaONA7cDn2OLoBoYHftlqiejEnxc4s2inRSTZw=w476-h844" width="476" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">LED3 (bottom center) had a crater in it and fell apart the minute it was touched.</td></tr></tbody></table><br /><p>The repair was simple: I just bridged LED3 contacts with solder.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEidLQe63IMB-8JdVlLv1vNXZhnL89gUHQspIszSOWR3wVvnHxQ9kekZKnmbMjgrY8ZsvUgh-vmswr5V0UDmnvOBFBZPGvj2MwR0SbUpZ-jn6eYzUnSN5P3O2ZcxSpohlh_UxVGSBlJooY0MRn7JVrrAqICU_dz-Y0SmQUiW92Xw_bDxTiQTabR7IsZGOQ=s3264" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="810" src="https://blogger.googleusercontent.com/img/a/AVvXsEidLQe63IMB-8JdVlLv1vNXZhnL89gUHQspIszSOWR3wVvnHxQ9kekZKnmbMjgrY8ZsvUgh-vmswr5V0UDmnvOBFBZPGvj2MwR0SbUpZ-jn6eYzUnSN5P3O2ZcxSpohlh_UxVGSBlJooY0MRn7JVrrAqICU_dz-Y0SmQUiW92Xw_bDxTiQTabR7IsZGOQ=w456-h810" width="456" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">LED3 solder-bridged</td></tr></tbody></table><br /><p>And it works!</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi1Q3lALFCNnFl_FMwj6oW0tmr1OJO4_ZO2D8C2AMXGC4WC1JrOeE04jwo9Lsynl9eeij8CC31gzR7yqwLMrF3LPogsohYVdBhQdHnpoSk7mqf6eZpcqJC9CXWLeUwcCFDEmoZXa_2meRLnLAl265K0ORqZDmYOOFeX_KPcOtF07FV2-tRHKtfgKiEFNA=s3264" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1836" data-original-width="3264" height="268" src="https://blogger.googleusercontent.com/img/a/AVvXsEi1Q3lALFCNnFl_FMwj6oW0tmr1OJO4_ZO2D8C2AMXGC4WC1JrOeE04jwo9Lsynl9eeij8CC31gzR7yqwLMrF3LPogsohYVdBhQdHnpoSk7mqf6eZpcqJC9CXWLeUwcCFDEmoZXa_2meRLnLAl265K0ORqZDmYOOFeX_KPcOtF07FV2-tRHKtfgKiEFNA=w476-h268" width="476" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Repaired lightbulb. Notice the dark spot missing an LED at far left of LED ring</td></tr></tbody></table><br /><p>I decided not to install the plastic cover: that will help compensate a little for the reduced light from the missing LED. But of course, <b>hazardous voltages are now exposed</b>. Which is why I installed it in my soldering station lamp, which is nearly entirely covered and out of harm's way:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj0Uyj2_2mkTgYWR84lxtSUyBO2t0jo2AiCtFBz26G7FdM7UI8oiM0mAcZQ5HtSpC34byD1fLBmSb_PDxvtRWO-obl9aSVKvZkyrNDuUtJQPgiWNLbbgGsQKy9FmoKxnCEh-U2TojhKlMN-9Zi6sgnmsKv7VMKve6Xw3om_fZlF8LG5apoTUm5b_FOUvA=s3264" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3264" data-original-width="1836" height="819" src="https://blogger.googleusercontent.com/img/a/AVvXsEj0Uyj2_2mkTgYWR84lxtSUyBO2t0jo2AiCtFBz26G7FdM7UI8oiM0mAcZQ5HtSpC34byD1fLBmSb_PDxvtRWO-obl9aSVKvZkyrNDuUtJQPgiWNLbbgGsQKy9FmoKxnCEh-U2TojhKlMN-9Zi6sgnmsKv7VMKve6Xw3om_fZlF8LG5apoTUm5b_FOUvA=w461-h819" width="461" /></a></div><br /><p><a href="https://toolboom.com/en/articles-and-video/led-light-bulb-diy-repair-at-home/">Toolboom has a great article on LED lightbulb repair</a>; do check it out. I had bought just one smart lightbulb, not wanting to throw out a bunch of electronics just because the bulb is faulty. Do not just bin your faulty IoT devices: they have to be physically destroyed as the <a href="https://sudonull.com/post/1270-Discarded-smart-bulbs-are-a-valuable-source-of-personal-information">electronics can be a security risk</a>. Now that they can be repaired, it would be fun to hack a bunch of faulty bulbs. </p><p>Have yourself a merry little Christmas. Happy Trails. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://www.youtube.com/watch?v=-tJtsKngXJU&ab_channel=FrankSinatraVEVO"><img border="0" data-original-height="522" data-original-width="671" height="349" src="https://blogger.googleusercontent.com/img/a/AVvXsEi3g5ggfNKJUwufAXXm7p5OO9aMNYZwQaiKAOORlWuAvxmQ733VwS0IDNCHyLjcMk9ahGHicDQwdTipOhHXgM549CBDSA6Nd0SzmuXtJ3DbxJD_ULtVXoCtMf_FfS7gNg2ciKhp59FZG8k0gHhGQI0sJe85srE7UhW2KIlqR8OVtO0irC9zloPAp299eQ=w449-h349" width="449" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.youtube.com/watch?v=-tJtsKngXJU&ab_channel=FrankSinatraVEVO">Frank Sinatra- have Yourself A Merry Little Christmas</a></td></tr></tbody></table><br /><p><br /></p>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-45652022063225914612021-12-24T02:15:00.001-08:002021-12-24T02:17:20.672-08:00Hacking the Hitachi RAC-EJ10CKM Air Conditioner Remote<p> <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh_GXSSuEmwBFAOokzej_tsaXr9TcFM9ulLe1q9HEsflh6drU15I3pBPaU1N4QKCrCI2N6OolozQBXj1JaENvkUGTtPrQkJ5zA9wPNAStRNnzFN4vvDXzG8ZBDrY2VXhwxP6iyZfNEAIvD9XWBBsT_MRcdgicQ7IKjzqEZeOqrGqquShmyyVfVFtgm0cg=s678" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="412" data-original-width="678" height="351" src="https://blogger.googleusercontent.com/img/a/AVvXsEh_GXSSuEmwBFAOokzej_tsaXr9TcFM9ulLe1q9HEsflh6drU15I3pBPaU1N4QKCrCI2N6OolozQBXj1JaENvkUGTtPrQkJ5zA9wPNAStRNnzFN4vvDXzG8ZBDrY2VXhwxP6iyZfNEAIvD9XWBBsT_MRcdgicQ7IKjzqEZeOqrGqquShmyyVfVFtgm0cg=w579-h351" width="579" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Hitachi RAC-EJ10CKM and IR Remote</td></tr></tbody></table><br /></p><p>Most of the Internet of Things (IoT, ie smart home) work on new products, new dimmable color LED lightbulbs, new robot vacuum cleaners, cameras, toasters and the like. To get a reasonable degree of intelligence in a smart home requires considerable financial investment. </p><p>And yet there are serious issues that discourage such an outlay. Issues like computer security, reliability (especially those based on WiFi), inter-operability problems, and vendor lock-in. Google products rely on Google servers, and they can fail. Being locked out of your house by a smart lock is extremely annoying. </p><p>Perhaps one way of encouraging IoT adoption is to lower the cost of entry. Most people already have home appliances; maybe we should retrofit IoT to <b>existing</b> appliances, like smoke detectors, listen for unusual noises like door/window opening, dogs barking and thunder. Or monitor the oven; a 'Hey Google, there's a chicken in the oven' function would be nice. But let us start with the easy ones, some low-hanging fruit, air conditioners.</p><p>I have always wanted to <a href="https://cmheong.blogspot.com/2021/12/remote-control-of-hitachi-rac-ej10ckm.html">automate my air conditioner</a>: it would be nice not to worry about leaving it on by accident. I usually need it for just an hour or two until I fall asleep; it would be nice to have it take an input from a sleep tracking sensor. Or having a passive infrared turn it off when there is nobody in the room. Most air conditioners seem to be controlled from a infrared remote: perhaps I can get an ESP8266 to transmit the control codes. There are quite a few Arduino projects hacking AC remotes, like <a href="https://www.instructables.com/Web-IR-Remote-With-Esp8266-NodeMCU/">this one from TaxeIT</a>, whose source code is <a href="https://github.com/axelerator/esp8266_ir_blaster">here</a>. </p><p>Unfortunately my Hitachi seems to be one of the few exceptions. I could capture the control codes, but the AC stubbornly refused to respond. Yet TaxeIT's method worked well with my Toshiba TV remote. <a href="https://perhof.wordpress.com/2015/03/29/reverse-engineering-hitachi-air-conditioner-infrared-remote-commands/">Perhof</a> seems to have an answer: the Hitachi code is simply too long! Perhof uses code from <a href="https://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/">Analysir</a> and <a href="https://github.com/cmheong/remoteAC/blob/main/AnalysIR.ino">my copy (tweaked to use GPIO14) is here</a>. It is nearly the same except for a little tweak for the ESP8266:</p><p>void ICACHE_RAM_ATTR rxIR_Interrupt_Handler() {</p><p>The resulting capture fires are in <a href="https://github.com/cmheong/remoteAC">my github repository</a>. It helps to check the length of the capture file from each button press:</p>$awk -F"," '{print NF-1}' AC_On_Raw.txt<br />530<br />$awk -F"," '{print NF-1}' AC_Off_Raw.txt<br />537<br /><br />This is markedly longer than the files from TaxeIT:<br /><br />$awk -F"," '{print NF-1}' hitachiACon.txt<br />98<br />$awk -F"," '{print NF-1}' hitachiACoff.txt<br />98<br /><div><br /></div><div>The bigger files have minimum memory requirements, which may be awkward for some CPUs, but fortunately the ESP8266 was more than adequate. <a href="https://www.analysir.com/blog/2016/04/11/sending-long-ac-signals-flash-irremote/">Analysir's tutorial</a> has the <a href="https://www.analysir.com/blog/wp-content/uploads/2016/04/sendRAW_Flash.ino_.txt">code to transmit large files</a>. Note the raw capture files have alternating positive and negative numbers, but the transmit code expects all to be positive. This is easy enough to do:</div><div>$sed 's/-//g' AC_On_Raw.txt > AC_On.txt</div><div><div>$sed 's/-//g' AC_Off_Raw.txt > AC_Off.txt</div></div><div><br /></div><div>And the codes can then be read into the sendRAW_Flash.ino with a little bit of editing. This worked first time if I hold the transmitter no more than 1m away from the Hitachi air conditioner IR remote receiver. Note that throughout, my hardware is still from <a href="https://www.instructables.com/Web-IR-Remote-With-Esp8266-NodeMCU/">TaxeIT</a>, reproduced here for convenience:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEim6dj4vb_wsSJdnDQi4qLdb4FnGLIWo7tC1PTyRaLpYl7f8UhwV9guzDSb3knQb7UkOOUiMLLonu6V5O1tJTU_lqLhs2s2zXc3oO2W649WPjmJhNHqE3aVULxpTn4_ujUUFakuuT3HL0ygGDKg5q6VQ8se-bRWzKtFjx4mkSbiR9-IapPE2Pp_x3Fs_w=s717" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="700" data-original-width="717" height="454" src="https://blogger.googleusercontent.com/img/a/AVvXsEim6dj4vb_wsSJdnDQi4qLdb4FnGLIWo7tC1PTyRaLpYl7f8UhwV9guzDSb3knQb7UkOOUiMLLonu6V5O1tJTU_lqLhs2s2zXc3oO2W649WPjmJhNHqE3aVULxpTn4_ujUUFakuuT3HL0ygGDKg5q6VQ8se-bRWzKtFjx4mkSbiR9-IapPE2Pp_x3Fs_w=w466-h454" width="466" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Image from TaxeIT</td></tr></tbody></table><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiYKSjB1GUuMqXAdmUKeVj4qnSIZPzErtPIXqq0rwWTC-FjwLjXHPmCNikNMLQCHns-Qgjkq60N0a_PUpUC1qnr5yuVLbEKX9iMUDYia1LXD1ouEALEy0YWcMPU4fsxrgrFuoEVonFVhudUDyV9MdhlFSwIV45CUl8vcOfY4NxlJXsjgzA728bhG8g4JQ=s853" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="587" data-original-width="853" height="319" src="https://blogger.googleusercontent.com/img/a/AVvXsEiYKSjB1GUuMqXAdmUKeVj4qnSIZPzErtPIXqq0rwWTC-FjwLjXHPmCNikNMLQCHns-Qgjkq60N0a_PUpUC1qnr5yuVLbEKX9iMUDYia1LXD1ouEALEy0YWcMPU4fsxrgrFuoEVonFVhudUDyV9MdhlFSwIV45CUl8vcOfY4NxlJXsjgzA728bhG8g4JQ=w464-h319" width="464" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Schematic from TaxeIT</td></tr></tbody></table><br /><div>There you have it, a proven hack for the Hitachi RAC-EJ10CKM IR Remote.</div><div><br /></div><div>Happy Trails.</div><div><br /></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-31215816038305608382021-12-23T06:44:00.003-08:002021-12-28T01:50:10.566-08:00Remote Control of Hitachi RAC-EJ10CKM Air Conditioner<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgWVoldGh18c35bRcINzeqXg3b3fPK3vsjkEvunH8lenPDSRQmf5wclHvcWqzKIJ84TgebSrjPbKfRw-Ph52dQlsKNrsabpb0jnO3i6YH6jUre-DU7N9dWUfZej1hTytX5NAWdVbWQulpl1BtuoasuCRNGda_afhWCJSdAvAg7q7saKdX2sQc2m-PH5XQ=s3264" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="3264" data-original-width="1836" height="862" src="https://blogger.googleusercontent.com/img/a/AVvXsEgWVoldGh18c35bRcINzeqXg3b3fPK3vsjkEvunH8lenPDSRQmf5wclHvcWqzKIJ84TgebSrjPbKfRw-Ph52dQlsKNrsabpb0jnO3i6YH6jUre-DU7N9dWUfZej1hTytX5NAWdVbWQulpl1BtuoasuCRNGda_afhWCJSdAvAg7q7saKdX2sQc2m-PH5XQ=w485-h862" width="485" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">NodeMCU ESP-12E with Baseboard and IR transmitter. The clothes peg is used to hold the IR LED in place aimed at the air conditioner</td></tr></tbody></table><br /><p></p><p>I have often worried about leaving the air conditioner on when I am out of the house, so being able to <a href="https://cmheong.blogspot.com/2021/12/did-i-leave-air-conditioner-on.html">remotely monitor</a> and control it seemed like a good idea. Using its infra-red remote link seemed like the natural way. </p><p>The go-to method would be to buy a spare remote and wire an <a href="https://cmheong.blogspot.com/2020/01/hacking-hw-655-esp8266-wifi-iot-relay.html">ESP8266-based WiFi relay</a> to the On/Off button, but just for kicks I thought it might be fun to hack the 38kHz remote datalink itself. <a href="https://cmheong.blogspot.com/2021/12/hacking-hitachi-rac-ej10ckm-air.html">That is the subject of another post</a>, but having hacked it, I now need to transmit the On/Off code to the air conditioner's indoor unit. </p><p>As usual someone, in this case <a href="https://www.instructables.com/Web-IR-Remote-With-Esp8266-NodeMCU/">TaxeIT</a> has beaten me to it. The relevant circuit here is the IR transmitter using an ESP8266 output pin to drive an IR LED via a 2N2222 transistor. I ripped an IR LED off an old DVD Player remote, and my power adapter is 9V DC from a long-dead ADSL modem. For ease of installation, the aim was to be able to park the transmitter as far away as possible and still reliably switch the air conditioner. I managed 2 metres; the Hitachi remote easily did 4 metres. My circuit is:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhnrIk8xY6Lulh4QaNFN79iOnh9nyRynATvS0z8tNRQz1fq4IL32wwI6VnXOAzkOJVvAi7kDgcWzgrlMSo94ul-GTz7Cp4mbUmEERDNNU083hEp_wfMiPaIFoUkxMblTgVFeMTwiyxtQM2JI34GMGst_chpQMcH8CpTYCnyc2JNUzRmonBdttE0sYWhjg=s425" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="425" data-original-width="350" height="504" src="https://blogger.googleusercontent.com/img/a/AVvXsEhnrIk8xY6Lulh4QaNFN79iOnh9nyRynATvS0z8tNRQz1fq4IL32wwI6VnXOAzkOJVvAi7kDgcWzgrlMSo94ul-GTz7Cp4mbUmEERDNNU083hEp_wfMiPaIFoUkxMblTgVFeMTwiyxtQM2JI34GMGst_chpQMcH8CpTYCnyc2JNUzRmonBdttE0sYWhjg=w416-h504" width="416" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">38kHz IR Transmitter Circuit</td></tr></tbody></table><br /><p>The is a good writeup on driving IR LEDs <a href="https://arduinodiy.wordpress.com/2015/12/12/driving-an-ir-led-constant-current-source-or-not/">by 'E' here</a>. I was probably a little conservative with my unknown LED for <a href="https://arduinodiy.wordpress.com/2015/12/12/driving-an-ir-led-constant-current-source-or-not/">'E'</a> drives his IR204 at 200mA. The IR204 has a maximum continous current rating of 100mA but a peak current of 1000mA. Since the LED is only transmitting for milliseconds, this is probably OK. </p><p>Bear in mind my circuit is for convenience only; I happened to have a <a href="https://cmheong.blogspot.com/2020/11/as3935-lightning-detector-with-i2c-and.html">nodeMCU baseboard V1</a> for my ESP-12E which lets you use up to 12V at the input. There is nothing wrong about using 5V and dispensing with the baseboard like TaxeIT. One of the advantages of 9V or higher is I have more headroom to drive more than one IR LED in series. Angling each LED in slightly different directions will greatly ease the problem of lining up the transmitter with the air conditioner receiver. Try not to overdo it: if there is more than one air conditioner, you might then accidentally switch the wrong one. </p><p>The other reason to use a baseboard is it is easily powered by a battery or power bank, which makes it a lot more convenient to check out the possible installation points.</p><p>The decoded remote data is something like</p>const unsigned int HitachiAC_On[] PROGMEM = {3378, 1696, 448, 1255, 448, 398, 471, 398, 470, 398, 470, 399, 471, 397, 471, 399, 471, 406, 470, 398, 470, 398, 470, 398, 471, 397, 472, 1255, 449, 398, 471, 398, 471, 404, 471, 398, 470, 397, ....<div><br /></div><div>Note that despite the Hitachi using the same button for On/Off, it sends a different bitstream on Off:</div><div><br /></div><div><div>const unsigned int HitachiAC_Off[] PROGMEM = { 189, 63402, 2071, 133, 141, 79167</div><div>0, 3447, 1621, 512, 1189, 512, 355, 512, 355, 513, 354, 512, 355, 512, 355, 513,</div><div> 356, 512, 362, 513, 354, 513, 354, 513, ...</div><br /><div>Which are simply timer intervals to alternately turn the LED on and off. The hack was a little difficult as the bitstream turned out to be unexpectedly long. This is apparently true of some of the Hitachi models. The ESP8266 Arduino code is based on <a href="https://github.com/Arduino-IRremote/Arduino-IRremote">IRremote</a>, with a pretty <a href="https://www.analysir.com/blog/2016/04/11/sending-long-ac-signals-flash-irremote/">good explanation here</a>. The source code is in <a href="https://github.com/cmheong/remoteAC">github</a>.</div></div><div><br /></div><div>To turn the air conditioner on, I use either http or MQTT. For http I use curl:</div><div><div>$curl --connect-timeout 2 -k http://12.34.56.78:8080/on</div><div><!DOCTYPE HTML></div><div><html></div><div>Aircond is on</html></div></div><div><br /></div><div>To use it with the MQTT server:</div><div>$mosquitto_pub -t 'aircond/commands' -m 'StudyAC_On'</div><div><br /></div><div>The MQTT server is typically started on power-up with something like:</div><div>$mosquitto -c /etc/mosquitto/mosquitto.conf</div><div><br /></div><div>This works well as long as the transmitter is not more than 2m away and pointed directly at the Hitachi air conditioner, ie at the IR receiver in the bottom right corner. However, the command might be ignored if say the air conditioner is already on and the 'On' command is transmitted. This happens if for example someone else operated it via its regular IR remote. Worse if the WiFi command is used sometimes curl times out without completing the command. This happens especially when there are WiFi connection problems.</div><div><br /></div><div>To resolve lingering doubts about failing to turn off the unit, I use a separate IoT system, a <a href="https://cmheong.blogspot.com/2021/12/did-i-leave-air-conditioner-on.html">Raspberry Pi to visually detect the orange 'On' LED on the indoor unit</a>. Now that seems like overkill, but that Pi can be to detect other events remotely like smoke detectors, thunderclaps, door bells, distress calls, etc. At some point. With a lot of programming. But you get the idea ... I integrated it into my Google Assistant smarthome server for the remote operation part. </div><div><br /></div><div><a href="https://youtu.be/JNG-CFvlAHg">Here is a video</a> of it in operation:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://youtu.be/JNG-CFvlAHg"><img border="0" data-original-height="888" data-original-width="1061" height="448" src="https://blogger.googleusercontent.com/img/a/AVvXsEjt8V4eIhi5yF76dIUGXzY41IHJbxXcv6gb8HGV7y0JhOOiARhRsJHfgcpf67drP7xLyHt70zpDNjOEXKBMRYftgrXbqmuTxeTMuNb9r32_3GURnxWceKzO_L_tLV6vc8k5D-e7amNtcLy9vMCKfzX91dU-zc_ELJhnPpgSZR0tYXRx-5XbSwMy28eftg=w536-h448" width="536" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://youtu.be/JNG-CFvlAHg">Youtube video of voice activation</a></td></tr></tbody></table><br /><div><br /></div><div><br /></div><div>There you have it, a remote controlled Hitachi air conditioner, an IoT air conditioner.</div><div><br /></div><div>Happy Trails.</div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-46208178843445358682021-12-07T06:35:00.007-08:002021-12-07T22:39:59.238-08:00Did I leave the Air Conditioner On? Indicator LED detection using Raspberry Pi and OpenCV<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLmfJaJlm9m6WpdTJELkYgF0aYr2OFBCznnYFLgve_y6iKLmgrNnkt0rc6FWBww5xc6xRV89xi8AYpZdWm56-yyHy6GcBUBeLlE1g8wb9rNIOf-lVd9Uy6APBeSXnFk0n5agezbZG4nkUc/s640/image_on.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLmfJaJlm9m6WpdTJELkYgF0aYr2OFBCznnYFLgve_y6iKLmgrNnkt0rc6FWBww5xc6xRV89xi8AYpZdWm56-yyHy6GcBUBeLlE1g8wb9rNIOf-lVd9Uy6APBeSXnFk0n5agezbZG4nkUc/w568-h426/image_on.png" width="568" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Air Conditioner Indoor Unit with Yellow Indicator LED</td></tr></tbody></table><br /><p></p><p>Air conditioners are essential in hot and humid Malaysia, especially if you want to work from home. Most of us have occasionally wondered if we have left it on after we left the house: the resulting electricity bill can be a nasty surprise. Most times you cannot do much about it, save for going back home to check.</p><p>But then, I managed to hack its infrared remote using an ESP8266, which made it an Internet of Things (IoT) device, which lets me turn it on and off from my smartphone. <b>Now</b> I have a need to know if I left the aircond turned on at home. </p><p>When the indoor unit comes on, there is a beep and an orange LED lights up. The standard way is to mount an optocoupler diode in series with the orange LED, wire the optocoupler output to an ESP8266 and the resulting IoT will reliably report the aircond on/off status every time.</p><p>But variety, they say, is the spice of life, and I happened to have an obsolete <a href="https://cmheong.blogspot.com/2021/12/the-littlest-computer-that-could-opencv.html">Raspberry Pi Model B with OpenCV</a> installed. And lots of ancient 640x480 webcams. Granted the lighting conditions would change through the day, but surely it can recognize that round orange light with some consistency?</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2kYTa4dJg5VzPoLJ2jfboJ-fr2FhsLRIgoRhp05_LUzNgor0uYL01zuE8dFtHh56N43mDxjd6GhbKucO97kp1rfQYwZ0v67ibgAtC2bISI5ZMzrxFw4JGVDzbVWZT0rU-p95MeE6aJ_zb/s2048/setup.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2kYTa4dJg5VzPoLJ2jfboJ-fr2FhsLRIgoRhp05_LUzNgor0uYL01zuE8dFtHh56N43mDxjd6GhbKucO97kp1rfQYwZ0v67ibgAtC2bISI5ZMzrxFw4JGVDzbVWZT0rU-p95MeE6aJ_zb/w547-h308/setup.jpg" width="547" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">USB webcam looking at the indicator LED from 3 feet away</td></tr></tbody></table><br /><p>It would be a bonus if software can be added later to detect that beep. That would have other applications like detection of smoke alarms' beeps, thunder, doorbell chimes and other interesting sounds. But that is another blog post.</p><p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYOTGrQh-zsVHq9B6xxqH1dkysLdOex4PzMpepZo_JRdX7A0cdSqcLNsae1ks6t0jW5RcwUnDkm05Ec620TqLMJwstZRB2gMQxmHf9DffMexcz8mx5K6WXP2oiUOUndiGw8vUqRMY1QdF3/s2048/raspi_1_modB.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYOTGrQh-zsVHq9B6xxqH1dkysLdOex4PzMpepZo_JRdX7A0cdSqcLNsae1ks6t0jW5RcwUnDkm05Ec620TqLMJwstZRB2gMQxmHf9DffMexcz8mx5K6WXP2oiUOUndiGw8vUqRMY1QdF3/w568-h320/raspi_1_modB.jpg" width="568" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">OpenCV Raspberry Pi Model B with LAN connection (ie 'headless' mode)</td></tr></tbody></table><br /> <a href="http://kazuar.github.io/light-detection-opencv/">Isaac Vidas</a> looks like a good starting point, first using an HSV transform to isolate the color of interest, then using cv2.HoughCircles() to precisely locate the LED itself. <div><br /><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh3qWyeXILPy_-mZA-PfcNh9nU8VbL25_soKPLMgLn-CyIjAu8okL252hU9U9OhtNQ19iRvx-GjRbkj4DVjUjt8OAP3v3EV2vgi3yoKUmut6hVyI-r4FHcGBqEEN5UFHwlC-Z1sLSnYRmKwpJBp7oo9dPv2JeiC4wy1OwKzCX7lXQCgxDkEHQPOcyr6xg=s640" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEh3qWyeXILPy_-mZA-PfcNh9nU8VbL25_soKPLMgLn-CyIjAu8okL252hU9U9OhtNQ19iRvx-GjRbkj4DVjUjt8OAP3v3EV2vgi3yoKUmut6hVyI-r4FHcGBqEEN5UFHwlC-Z1sLSnYRmKwpJBp7oo9dPv2JeiC4wy1OwKzCX7lXQCgxDkEHQPOcyr6xg=w533-h400" width="533" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Image after HSV transform</td></tr></tbody></table><br /></div><div>I did need some additional help in setting the color thresholds required in his code to:<p></p># Get lower orange hue<div>lower_orange_hue = create_hue_mask(hsv_image, [0, 0, 255], [0, 255, 255]) </div><div># Get higher orange hue </div><div>higher_orange_hue = create_hue_mask(hsv_image, [0, 0, 255], [38, 255, 255])<div><br /></div><div>There is a <a href="https://stackoverflow.com/questions/57469394/opencv-choosing-hsv-thresholds-for-color-filtering">handy python script by nathancy here</a>, and together with a <a href="https://stackoverflow.com/questions/21737613/image-of-hsv-color-wheel-for-opencv">HSV color wheel</a>, my threshold values could be determined using several images of the aircond LED under different lighting conditions.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3XSuNjYrl2Lk6-_c-iyXE2AsrziYo1BL_uGrTrgU1XqaEjboEuCHf-caYXbKm_tTtMHQKBt58Q5U2SXDf5lpxu0Oq82AZiLnx8BDXrOncFUVtFdvjXSOB6fIDqusUr2Qv9v3RkJpAUJTT/s320/HSVcolorWheel.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="319" data-original-width="320" height="534" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3XSuNjYrl2Lk6-_c-iyXE2AsrziYo1BL_uGrTrgU1XqaEjboEuCHf-caYXbKm_tTtMHQKBt58Q5U2SXDf5lpxu0Oq82AZiLnx8BDXrOncFUVtFdvjXSOB6fIDqusUr2Qv9v3RkJpAUJTT/w535-h534/HSVcolorWheel.jpg" width="535" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">HSV Color wheel</td></tr></tbody></table><br /><div> </div></div><div><br /></div><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhXdZCwihu9aJbWDOShx-QKW0uUhAmqY7GyEtOFge3AY4abNp8Fu41FEFYFncjjWmWi-uT1L4ajD7G-9fMVv7jq01ZsdqDztOnszFD6PMxKaUPAt-dehvcAdBXy48_9E1n0vGFOS5043Tm6Bp0kO25l5yfRSaXsw2uXsIGjPJsmwHE_qT3hFl8laNqNjg=s640" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="432" src="https://blogger.googleusercontent.com/img/a/AVvXsEhXdZCwihu9aJbWDOShx-QKW0uUhAmqY7GyEtOFge3AY4abNp8Fu41FEFYFncjjWmWi-uT1L4ajD7G-9fMVv7jq01ZsdqDztOnszFD6PMxKaUPAt-dehvcAdBXy48_9E1n0vGFOS5043Tm6Bp0kO25l5yfRSaXsw2uXsIGjPJsmwHE_qT3hFl8laNqNjg=w576-h432" width="576" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Image after color filtering</td></tr></tbody></table><br /><br /><div><br /></div><div><div>Firstof, you will be needing a programs to view the USB webcam video and still frames. I use mplayer and feh:</div><div><br /></div><div># apt-get install mplayer</div><div># apt-get install feh</div><div><br /></div><div>You set the Pi via raspi-config not to run the X Server (ie the GUI desktop), but it helps to have the X libraries installed. From your laptop/desktop you just ssh in:</div><div>fred@pi:~ $ ssh -t -Y 12.34.56.78</div><div><br /></div><div>And from there, mplayer should display the video on your desktop. This lets you position the camera properly.</div><div>fred@pi:~ $ mplayer tv://</div><div><br /></div><div>To get 10 still frames after 10s (some cameras auto-adjust brightness):</div><div>fred@pi:~ $ mplayer -vo jpeg -frames 10 -ss 10 -brightness 25 tv://</div><div><br /></div><div>You can use 'mplayer -loop 0' to display the still images, but they flash on and off rather annoyingly. I much prefer something like feh:</div><div>fred@pi:~ $ feh .images/image_on.png</div><div><br /></div><div>And best of all, the openCV code will execute as if you were using the Pi's console (ie HDMI).</div><div><br /></div><div>Having selected your camera position, you should probably make a set of images under different lighting conditions. I used a fragment of <a href="http://kazuar.github.io/light-detection-opencv/">Isaac Vidas</a>'s code to do this, in particular to see the effect of lighting on the separate operations like blurring and HSV transformation. This is named webcamTest.py and is available on <a href="https://github.com/cmheong/checkLed">my github repository</a>. You typically do:</div><div> </div><div>fred@pi:~/checkLed $ source ~/opencv/OpenCV-4.0-py3/bin/activate</div><div>(OpenCV-4.0-py3) fred@pi:~/checkLed $</div><div><br /></div><div>(OpenCV-4.0-py3) fred@pi:~/checkLed $ python ./webcamTest.py image_on.png </div><div><br /></div><div>Next, use the <a href="https://stackoverflow.com/questions/57469394/opencv-choosing-hsv-thresholds-for-color-filtering">nathancy</a> code, which I named hsvThresholder.py. </div><div>(OpenCV-4.0-py3) fred@pi:~/checkLed $ python hsvThresholder.py</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhowk1pfrM4T-5J5pmmo0IKpcIuogAfML8KlKIe_7v13LyMiVVtOMd7JfWLEQhit1DSSl0Sor_SfapOgmzA_bje7E2PZBeZokU6k5xZuPbyzznGF2Jrzfr7bYHVPWpbZfQJqi8fEIWAjANjkkIDcxl8qn8CdRDCn_noE4nVqDucwKDWri3ExAr8V1kVeg=s772" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="755" data-original-width="772" height="516" src="https://blogger.googleusercontent.com/img/a/AVvXsEhowk1pfrM4T-5J5pmmo0IKpcIuogAfML8KlKIe_7v13LyMiVVtOMd7JfWLEQhit1DSSl0Sor_SfapOgmzA_bje7E2PZBeZokU6k5xZuPbyzznGF2Jrzfr7bYHVPWpbZfQJqi8fEIWAjANjkkIDcxl8qn8CdRDCn_noE4nVqDucwKDWri3ExAr8V1kVeg=w528-h516" width="528" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">hsvThresholder.py: adjust the sliders at the bottom. Runs very slowly on a Pi B, so be patient and watch the console output in the window below</td></tr></tbody></table><div><br /></div><div>You want to adjust the various sliders in order to mask out all other regions of different color to your LED. A Raspberry Pi 1 Model B will be extremely slow here so patience is required. One way is to watch the bash console messages as they are much quicker to update than the picture. Copy the final settings from the console, which will be something like:</div><div>(hMin = 0 , sMin = 0, vMin = 85), (hMax = 28 , sMax = 255, vMax = 255)</div><div><br /></div><div>My version of <a href="http://kazuar.github.io/light-detection-opencv/">Isaac Vidas</a>'s code is named checkAC_led.py. and pretty much works as advertised, except it required a much larger (something like 6x diameter) image of the LED. I would have needed to mount my camera much closer, just 17cm from the LED. The other problem is the camera needs to be square over the LED as cv2.HoughCircles() do not detect ellipses very well. And line (ie hollow) circles worked better than a solid one.</div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj2gjNh1yUdWQ-jbOL5hB377E8qHpx_1L1BqbWsAymttGjq7xXTRHbQgWs0DUdr04aQMlDG2DPziv7njzHcip0UppmXZt-h8uoUAZJnXu9Xi8tj-6zVKsRmR5TZI-lEBiBlGeAb3yA421PLPbcc6bJtYefFlogJTyrx5Cz4JOMtNgg5GBVzCBdGPvlOTQ=s640" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="395" src="https://blogger.googleusercontent.com/img/a/AVvXsEj2gjNh1yUdWQ-jbOL5hB377E8qHpx_1L1BqbWsAymttGjq7xXTRHbQgWs0DUdr04aQMlDG2DPziv7njzHcip0UppmXZt-h8uoUAZJnXu9Xi8tj-6zVKsRmR5TZI-lEBiBlGeAb3yA421PLPbcc6bJtYefFlogJTyrx5Cz4JOMtNgg5GBVzCBdGPvlOTQ=w527-h395" width="527" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Image with test circle added: this is the minimum size circle cv2.HoughCircles() will detect</td></tr></tbody></table><br /></div><div>Mounting my camera closer and square-on the LED is the correct solution. This also minimizes false alarms and improves reliability of detection. This probably means some sort of mounting bracket on the wall, and might get in the way when the air conditioner is being serviced. A software solution would be great, and the future beep detector would help filter out those false alarms ...</div><div><br /></div><div>This led me to <a href="https://learnopencv.com/blob-detection-using-opencv-python-c/">cv2.SimpleBlobDetection() code</a>, which does much better with smaller and deformed circles. Take care to set minArea as large as possible: I actually counted the number of LED pixels in my HSV transform.</div><div><br /></div><div>The gotcha here is that the HSV image has to be inverted for blob detection to work:</div><div><div> h, s, image_gray = cv2.split(full_image)</div><div> image_gray_neg = cv2.bitwise_not(image_gray) </div><div> detector = cv2.SimpleBlobDetector_create(params)</div></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgsvG8T5yPTxU9FT_RBxK0b13620vzYJ1hcd_FcSkh7XPaE8DGJ3YwA0CsFjFBZWF3l-16sSu70VQh3fjEK2X37t2XNlcv3VW8ZbGvdXI99p3poqdrSwcZIWg4zc0l0SGmxwWoqFnJzxXdkvTRUdppiPTC90uTT_GVtN1u7kPcTRfrqZFN6aCBH4zv2xQ=s640" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="422" src="https://blogger.googleusercontent.com/img/a/AVvXsEgsvG8T5yPTxU9FT_RBxK0b13620vzYJ1hcd_FcSkh7XPaE8DGJ3YwA0CsFjFBZWF3l-16sSu70VQh3fjEK2X37t2XNlcv3VW8ZbGvdXI99p3poqdrSwcZIWg4zc0l0SGmxwWoqFnJzxXdkvTRUdppiPTC90uTT_GVtN1u7kPcTRfrqZFN6aCBH4zv2xQ=w563-h422" width="563" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">After conversion to grayscale and inversion<br /><br /></td></tr></tbody></table></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgWgViOUfgczAcVNcM-gNPcRCqQgJoYJjYXcBngtfTb56NCfHvAF2rykdy1kUkDwFV8MFtbD9zeQLmwu7dCL0wLlwgNsodgu_WalX6NkeaVxkmNno0yuuoEWZ6B4PgGl8qp79WORmw3lp2FWKaONRCSjwS6TbYu-QuVw-3CBYk_hk6Ly-XbR6IGTm158Q=s640" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="413" src="https://blogger.googleusercontent.com/img/a/AVvXsEgWgViOUfgczAcVNcM-gNPcRCqQgJoYJjYXcBngtfTb56NCfHvAF2rykdy1kUkDwFV8MFtbD9zeQLmwu7dCL0wLlwgNsodgu_WalX6NkeaVxkmNno0yuuoEWZ6B4PgGl8qp79WORmw3lp2FWKaONRCSjwS6TbYu-QuVw-3CBYk_hk6Ly-XbR6IGTm158Q=w551-h413" width="551" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">After successful blob detection</td></tr></tbody></table><br /><div><br /></div><div>The final version, checkACvideo_led.py reads from the webcam instead of still image files, filters out false alarms based on the blob x and y coordinates and prints the air conditioner status. In its IoT form the print statement just needs to be modified to publish to an MQTT server like mosquitto.</div><div><br /></div><div>So did I leave the air conditioner on? <a href="https://cmheong.blogspot.com/2020/05/raspberry-pi-4-voice-assistant-mycroft.html">Hey Mycroft</a>, is my air conditioner on or off?</div><div><br /></div><div>Happy Trails<br /></div></div></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-781886510159748622021-12-06T05:09:00.001-08:002021-12-09T01:19:00.056-08:00The Littlest Computer that Could: OpenCV using Raspberry Pi 1 Model B Rev 2<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEVd0t7zaZOFVLx3rPjsU0JokxWyTs6uh_qmNG5BXKS0jLs7fVOIgoSm5OVLUR9eYeFfChsOZCkaOIgGhOqFGV47UojPKYMqJNLdhR01oRHJM5cFqfOCNkDJxUVWaeMzWUCBew4D1pAxGT/s800/Raspberry_Pi_Model_B_Rev._2.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="533" data-original-width="800" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEVd0t7zaZOFVLx3rPjsU0JokxWyTs6uh_qmNG5BXKS0jLs7fVOIgoSm5OVLUR9eYeFfChsOZCkaOIgGhOqFGV47UojPKYMqJNLdhR01oRHJM5cFqfOCNkDJxUVWaeMzWUCBew4D1pAxGT/w522-h348/Raspberry_Pi_Model_B_Rev._2.jpg" width="522" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">First there was the 1B: Raspberry Pi One Model B.</td></tr></tbody></table><br /><p></p><p>Now out of production, the Raspberry Pi One Model B was released in 2012, <b>earlier</b> than the Model A. I had a few lying unused in my parts box, some damaged by defective power supplies, but mostly superseded by better versions like the Pi 2, 3 and 4s. The Pi 1 Model B was the slowest, had only 512MB DRAM and used the sdcard as mass storage. The USB functionality was questionable: the LAN chip was internally routed through the USB bus which crippled its throughput. And since the Pi was always touchy about its 5V input power adding basic functionality like keyboard, hdmi USB was always a hit and miss affair.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGymiEKgonObeaVX9M4UAR1xsUZpswkFmBj_Gw0SanmL1kMOjVOK0qkTPNJeZ0d8FOv7pYv59k_EKfzn7d0-uNGp5fiPDyIHAhr-5f81lshKgxb-zFWTtcww3P1UeNHBeZ5sUPBY0_8EKq/s700/sdcard_microsd.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="467" data-original-width="700" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGymiEKgonObeaVX9M4UAR1xsUZpswkFmBj_Gw0SanmL1kMOjVOK0qkTPNJeZ0d8FOv7pYv59k_EKfzn7d0-uNGp5fiPDyIHAhr-5f81lshKgxb-zFWTtcww3P1UeNHBeZ5sUPBY0_8EKq/w534-h355/sdcard_microsd.jpeg" width="534" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Left: sdcard, right: micro-sdcard</td></tr></tbody></table><p><br /></p><p>The sdcard is getting very hard to find. You find micro-sdcard with an adapter but these tend to develop contact problems and corrupt the onboard filesystem. To make matters worse, a Pi Model B which cannot boot will have no indication: there is just that red power LED on and nothing else, and it looks pretty much like a dead Pi. Some 60% of my discarded Pi 1s simply had microsd adapter contact problems and could not boot.</p><p>On the plus side, the Pi 1 drew the least power amongst the Pi series which meant most old Android phone chargers could power it. It also had audio and video jacks, which were very handy with retro electronics. </p><p>I managed put one to use monitoring my solar panel, but most of the little jobs are better served by the ESP8266 or the Microchip PIC. If only the Raspberry Pi Model B could run OpenCV; with a bit of nifty image processing, it might find a use, perhaps to check if my front gate has been left open, or the air conditioner left running, or if the smoke alarm is beeping. </p><p>Most of the time, the Pi 3 is the minimum recommended model, but there is no mention Raspberry Pi One <b>cannot</b> be used. No harm trying; and since the install process can be left alone, it is easily done on the side. </p><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdOpofu592wulqQr4VjgolJ-1LsPKR_4Nj_UjIklU1iRm9BX_VcBpW-ShbbwpR7JsPfeQokA6tdscQp1gyC877ZvigTu_x-sb8mv5S81Y_3OmocA9uk0d8XgnQ4RONB9pUsYY0hJIzhaJy/s2048/raspi_1_modB.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="303" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdOpofu592wulqQr4VjgolJ-1LsPKR_4Nj_UjIklU1iRm9BX_VcBpW-ShbbwpR7JsPfeQokA6tdscQp1gyC877ZvigTu_x-sb8mv5S81Y_3OmocA9uk0d8XgnQ4RONB9pUsYY0hJIzhaJy/w540-h303/raspi_1_modB.jpg" width="540" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Raspberry Pi 1 Model B Rev 2 with infamous microsd adapter</td></tr></tbody></table><p>$dd if=2021-10-30-raspios-bullseye-armhf-lite.img of=/dev/sdc</p><p>After the standard install of Raspbian, I use raspi-config to turn on the ssh server and set a fixed ethernetIP. It can then be used as a headless (ie no monitor or keyboard) system via ssh from a host laptop or desktop. After which there is the usual obligatory</p><p># apt-get update --allow-releaseinfo-change<br /># apt-get upgrade</p><p>And the Pi model:</p><p>root@pi:~# cat /sys/firmware/devicetree/base/model<br />Raspberry Pi Model B Rev 2<br /><br /><a href="https://www.jeremymorgan.com/tutorials/raspberry-pi/how-to-install-opencv-raspberry-pi/">Jeremy Morgan's OpenCV install</a> worked for my Pi 3 before, but now instead it stops:</p># pip install opencv-contrib-python<br />Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple<br />Collecting opencv-contrib-python<br /> Downloading opencv-contrib-python-4.5.4.60.tar.gz (150.7 MB)<br /> |��������������������������������| 150.4 MB 93 kB/s eta 0:00:04Killed<p>From 'dmesg -T' it looks like I ran out of memory:</p><p>[Tue Nov 23 18:03:30 2021] [ 5714] 0 5714 87141 21594 104 0</p><p> 21597 0 pip</p><p>[Tue Nov 23 18:03:30 2021] Out of memory: Kill process 5714 (pip) score 349 or sacrifice child</p><p>[Tue Nov 23 18:03:30 2021] Killed process 5714 (pip) total-vm:348564kB, anon-rss</p><p>:86376kB, file-rss:0kB, shmem-rss:0kB</p><p>[Tue Nov 23 18:03:30 2021] oom_reaper: reaped process 5714 (pip), now anon-rss:0</p><p>kB, file-rss:0kB, shmem-rss:0kB</p><div>My free memory is:</div><div><div># free -m</div><div> total used free shared buff/cache available</div><div>Mem: 369 18 285 0 65 304</div><div>Swap: 15358 21 15337</div></div><div><br /></div><div>And I can get a litte more by editing the boot partition's config.txt:</div><div># vi /boot/config.txt</div><div><br /></div><div>Add:</div><div>gpu_mem=16</div><div><br /></div><div>And comment out</div><div><div>#start_x=1</div></div><div><br /></div><div>After a reboot I get more memory:</div><div><div># free -m</div><div> total used free shared buff/cache available</div><div>Mem: 477 31 338 6 106 390</div><div>Swap: 99 0 99</div></div><div> </div><div>But this is still not enough. Now I could increase the swap file in my micro sdcard, but the thrashing might wear it out as the number of write operations is limited. Instead I used one of the many ancient thumbdrives, discarded just because of their low capacities. I ended up using a compactflash card for its speed:</div><br /># dd if=/dev/zero of=/dev/sda bs=1M count=1024<div># mkswap /dev/sda<br /><div># swapon /dev/sda</div><div><br /># pip install --upgrade pip setuptools wheel</div></div><div># python -m pip install --upgrade pip</div><div># pip3 install opencv-contrib-python</div><div><br /></div><div>pip seems to have gone walkabout so,</div><div><br /></div><div># ln -s /usr/local/bin/pip /usr/bin/pip</div><div><br /></div><div>Failure:</div><div># pip install opencv-contrib-python</div><div><div> File "setup.py", line 381, in _classify_installed_files_override</div><div> with open(os.path.join(cmake_install_dir, "python", "cv2", "__init__.py"),</div><div> 'r') as opencv_init:</div><div> FileNotFoundError: [Errno 2] No such file or directory: '_skbuild/linux-armv6l</div><div>-3.7/cmake-install/python/cv2/__init__.py'</div><div> ----------------------------------------</div><div> ERROR: Failed building wheel for opencv-contrib-python</div><div>Failed to build opencv-contrib-python</div><div>ERROR: Could not build wheels for opencv-contrib-python, which is required to in</div><div>stall pyproject.toml-based projects</div></div><div><br /></div><div><a href="https://learnopencv.com/install-opencv-4-on-raspberry-pi/">Vishwesh Shrimali's instructions</a> seem promising, and his minimum requirement is for a Pi 2. There are more separate bash commands which increases the chances for a successful debug. Since a fail is near certain, I chose to key in the commands manually instead of running Shrimali's script.</div><div><br /></div><div><div>root@pi:/root/opencv# apt-get -y purge wolfram-engine</div><div>root@pi:/root/opencv# apt-get -y purge libreoffice*</div><div>root@pi:/root/opencv# apt-get -y clean</div><div>root@pi:/root/opencv# apt-get -y autoremove</div></div><div><div>root@pi:/root/opencv# apt -y update</div></div><div><div>root@pi:/root/opencv# apt -y upgrade</div><div>root@pi:/root/opencv# apt-get -y remove x264 libx264-dev</div></div><div><div>root@pi:/root/opencv# apt-get -y install build-essential checkinstall</div><div> cmake pkg-config yasm</div><div>root@pi:/root/opencv# apt-get -y install git gfortran</div><div>root@pi:/root/opencv# apt-get -y install libjpeg8-dev libjasper-dev libpng12-dev</div><div>root@pi:/root/opencv# apt-get -y install libtiff5-dev</div><div>root@pi:/root/opencv# apt-get -y install libtiff-dev</div></div><div><div>root@pi:/root/opencv# apt-get -y install libxine2-dev libv4l-dev</div><div>root@pi:/root/opencv# cd /usr/include/linux</div><div>root@pi:/usr/include/linux# ln -s -f ../libv4l1-videodev.h videodev.h</div><div>root@pi:/usr/include/linux# cd $cwd</div><div>root@pi:/root/opencv#</div><div>root@pi:/root/opencv# apt-get -y install libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev</div><div>root@pi:/root/opencv# apt-get -y install libgtk2.0-dev libtbb-dev qt5-default </div><div>root@pi:/root/opencv# apt-get -y install libatlas-base-dev</div><div>root@pi:/root/opencv# apt-get -y install libmp3lame-dev libtheora-dev</div><div>root@pi:/root/opencv# apt-get -y install libvorbis-dev libxvidcore-dev libx264-dev</div><div>root@pi:/root/opencv# apt-get -y install libopencore-amrnb-dev libopencore-amrwb-dev </div><div>root@pi:/root/opencv# apt-get -y install libavresample-dev</div><div>root@pi:/root/opencv# apt-get -y install x264 v4l-utils</div><div><br /></div><div> The following are optional:</div><div>root@pi:/root/opencv# apt-get -y install libprotobuf-dev protobuf-compiler</div><div>root@pi:/root/opencv# apt-get -y install libgoogle-glog-dev libgflags-dev </div><div>root@pi:/root/opencv# apt-get -y install libgphoto2-dev libeigen3-dev libhdf5-dev doxygen</div><div><br /></div><div> Required python libraries</div><div>root@pi:/root/opencv# apt-get -y install python3-dev python3-pip</div><div><br /></div><div> Virtual environment:</div><div>fred@pi:~/opencv $ python3 -m venv OpenCV-4.0-py3</div><div>fred@pi:~/opencv $ echo "# Virtual Environment Wrapper" >> ~/.bashrc</div><div>fred@pi:~/opencv $ echo "alias workoncv-4.0=\"source /root/opencv/OpenCV-4.0-py3/bin/activate\"" >> ~/.bashrc </div><div>fred@pi:~/opencv $ source /root/opencv/OpenCV-4.0-py3/bin/activate(OpenCV-4.0-py3) fred@pi:~/opencv $</div></div><div><br /></div><div> Increase the swap file from 100 to 1024:</div><div><div>(OpenCV-4.0-py3) fred@pi:~/opencv $ sudo sed -i 's/CONF_SWAPSIZE=100/CONF_SWAPSIZE=1024/g' /etc/dphys-swapfile</div><div>(OpenCV-4.0-py3) fred@pi:~/opencv $ sudo /etc/init.d/dphys-swapfile stop</div><div>[ ok ] Stopping dphys-swapfile (via systemctl): dphys-swapfile.service. </div><div>(OpenCV-4.0-py3) fred@pi:~/opencv $ sudo /etc/init.d/dphys-swapfile start</div><div>[ ok ] Starting dphys-swapfile (via systemctl): dphys-swapfile.service. </div><div><br /></div><div>(OpenCV-4.0-py3) fred@pi:~/opencv $ pip install numpy dlib</div><div>(OpenCV-4.0-py3) fred@pi:~/opencv $ deactivate</div><div><br /></div><div>This is an over 400MB porker of a file:</div><div>fred@pi:~/opencv $ git clone https://github.com/opencv/opencv.git</div><div><br /></div><div>In retrospect I should have checked out 4.0.1 as having cv2.drawKeypoints() would have been handy.</div><div>fred@pi:~/opencv/opencv $ git checkout 4.0.0</div></div><div><br /></div><div><div>fred@pi:~/opencv $ git clone https://github.com/opencv/opencv_contrib.git</div><div>fred@pi:~/opencv $ cd opencv_contrib</div><div>fred@pi:~/opencv/opencv_contrib $ git checkout 4.0.0</div></div><div><br /></div><div>Then comes the config:</div><div><div>fred@pi:~/opencv/opencv/build $ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE</div><div>_INSTALL_PREFIX=/home/heong/opencv/installation/OpenCV-4.0 -D INSTALL_C_EXAMPLES</div><div>=ON -D INSTALL_PYTHON_EXAMPLES=ON -D WITH_TBB=ON -D WITH_V4L=ON -D OPENCV_PYTHON3_INSTALL_PATH=/home/heong/opencv/OpenCV-4.0-py3/lib/python3.5/site-packages -D WITH_QT=ON -D WITH_OPENGL=ON -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules -D BUILD_EXAMPLES=ON ..</div></div><div><br /></div><div>Now for the make:</div><div><div>fred@pi:~/opencv/opencv/build $ CMAKE_INSTALL_PREFIX=/usr/local</div><div>fred@pi:~/opencv/opencv/build $ export CMAKE_INSTALL_PREFIX</div><div>fred@pi:~/opencv/opencv/build $ make</div></div><div><br /></div><div>Produces the error</div><div><div>In file included from /home/fred/opencv/opencv_contrib/modules/cvv/src/qtutil/f</div><div>ilter/sobelfilterwidget.cpp:3:</div></div><div><div>/home/heong/opencv/opencv/modules/imgproc/include/opencv2/imgproc.hpp:208:5: not</div><div>e: �FILTER_SCHARR�</div><div> FILTER_SCHARR = -1</div><div> ^~~~~~~~~~~~~</div><div>make[2]: *** [modules/cvv/CMakeFiles/opencv_cvv.dir/build.make:453: modules/cvv/</div><div>CMakeFiles/opencv_cvv.dir/src/qtutil/filter/sobelfilterwidget.cpp.o] Error 1</div><div>make[1]: *** [CMakeFiles/Makefile2:12676: modules/cvv/CMakeFiles/opencv_cvv.dir/</div><div>all] Error 2</div><div>make: *** [Makefile:163: all] Error 2</div></div><div><br /></div><div>From <a href="https://github.com/opencv/opencv_contrib/issues/1914">Nobuo Tsukamoto</a>, in the file /home/fred/opencv/opencv_contrib/modules/cvv/src/qtutil/f</div><div>ilter/sobelfilterwidget.cpp added 'using namespace cv;' at line 13 thus:</div><div><br /></div><div><div>#include "../../util/util.hpp"</div><div>#include "../filterfunctionwidget.hpp"</div><div>#include "../filterselectorwidget.hpp"</div><div><br /></div><div>using namespace cv; // cmheong 2021-11-29</div><div><br /></div><div>namespace cvv</div><div>{</div><div>namespace qtutil</div><div>{</div><div><br /></div><div>SobelFilterWidget::SobelFilterWidget(QWidget *parent)</div></div><div><br /></div><div>After which</div><div><div>fred@pi:~/opencv/opencv/build $ make</div><div>Produces the error</div></div><div><div>Scanning dependencies of target example_cpp_detect_mser</div><div>[ 89%] Building CXX object samples/cpp/CMakeFiles/example_cpp_detect_mser.dir/detect_mser.cpp.o</div><div>/home/fred/opencv/opencv/samples/cpp/detect_mser.cpp:28:10: fatal error: GL/glu.h: No such file or directory</div><div> #include <GL/glu.h></div><div> ^~~~~~~~~~</div><div>compilation terminated.</div><div>make[2]: *** [samples/cpp/CMakeFiles/example_cpp_detect_mser.dir/build.make:63:</div><div>samples/cpp/CMakeFiles/example_cpp_detect_mser.dir/detect_mser.cpp.o] Error 1</div><div>make[1]: *** [CMakeFiles/Makefile2:29519: samples/cpp/CMakeFiles/example_cpp_det</div><div>ect_mser.dir/all] Error 2</div><div>make: *** [Makefile:163: all] Error 2</div></div><div><br /></div><div>From <a href="https://github.com/IntelRealSense/librealsense/issues/5232">RajkiranVeldur</a>, just do</div><div>root@pi:~# apt-get install libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev</div><div><br /></div><div><div>After which</div><div><div>fred@pi:~/opencv/opencv/build $ make</div><div>Produces the link error</div></div></div><div><div>[ 89%] Linking CXX executable ../../bin/example_cpp_detect_mser</div><div>/usr/bin/ld: CMakeFiles/example_cpp_detect_mser.dir/detect_mser.cpp.o: in functi</div><div>on `draw(void*)':</div></div><div><div>detect_mser.cpp:(.text.startup.main+0x1c70): undefined reference to `gluPerspect</div><div>ive'</div><div>collect2: error: ld returned 1 exit status</div><div>make[2]: *** [samples/cpp/CMakeFiles/example_cpp_detect_mser.dir/build.make:134:</div><div> bin/example_cpp_detect_mser] Error 1</div><div>make[1]: *** [CMakeFiles/Makefile2:29519: samples/cpp/CMakeFiles/example_cpp_det</div><div>ect_mser.dir/all] Error 2</div><div>make: *** [Makefile:163: all] Error 2</div></div><div><br /></div><div><a href="https://github.com/opencv/opencv/issues/12648">regpa</a> mentioned that I need openGLU.so, but a brute-force search could not come up with one:</div><div><div>fred@pi:~/opencv/opencv/build $ sudo ls -lR / | grep -e openGLU </div><div>fred@pi:~/opencv/opencv/build $</div></div><div><br /></div><div>There is however, a file called libGLU.so mentioned by <a class="author Link--primary css-truncate-target width-fit" data-hovercard-type="user" data-hovercard-url="/users/myinternetofthings/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/myinternetofthings" show_full_name="false" style="box-sizing: border-box; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; font-weight: 600; max-width: 125px; overflow: hidden; text-decoration-line: none; text-overflow: ellipsis; vertical-align: top; white-space: nowrap;">myinternetofthin</a>gs:</div><div><div>fred@pi:~/opencv/opencv/build $ sudo ls -lR / 2>/dev/null | grep -e GLU.so</div><div>lrwxrwxrwx 1 root root 15 Sep 20 2015 libGLU.so -> libGLU.so.1.3.1</div><div>lrwxrwxrwx 1 root root 15 Sep 20 2015 libGLU.so.1 -> libGLU.so.1.3.1</div><div>-rw-r--r-- 1 root root 358228 Sep 20 2015 libGLU.so.1.3.1</div></div><div><br /></div><div>Added it to 2 separate files link.txt:</div><div><br /></div><div><div>fred@pi:~/opencv/opencv/build $ cat samples/opengl/CMakeFiles/example_open</div><div>gl_opengl.dir/link.txt</div><div>/usr/bin/c++ -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-</div><div>dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wm</div><div>issing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -W</div><div>uninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comme</div><div>nt -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthr</div><div>ead -fomit-frame-pointer -ffunction-sections -fdata-sections -mfp16-format=ieee</div><div> -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG -Wl,-</div><div>-gc-sections CMakeFiles/example_opengl_opengl.dir/opengl.cpp.o -o ../../bin/e</div><div>xample_opengl_opengl -Wl,-rpath,/home/heong/opencv/opencv/build/lib -ldl -lm -l</div><div>pthread -lrt /usr/lib/arm-linux-gnueabihf/libGL.so ../../lib/libopencv_highgui.s</div><div>o.4.0.0 ../../lib/libopencv_videoio.so.4.0.0 ../../lib/libopencv_imgcodecs.so.4.</div><div>0.0 ../../lib/libopencv_imgproc.so.4.0.0 <b>../../lib/libopencv_core.so.4.0.0 /usr/</b></div><div><b>lib/arm-linux-gnueabihf/libGLU.so</b></div></div><div><br /></div><div><div>fred@pi:~/opencv/opencv/build $ cat samples/cpp/CMakeFiles/example_cpp_det</div><div>ect_mser.dir/link.txt</div><div>/usr/bin/c++ -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-</div><div>dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wm</div><div>issing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -W</div><div>uninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comme</div><div>nt -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthr</div><div>ead -fomit-frame-pointer -ffunction-sections -fdata-sections -mfp16-format=ieee</div><div> -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG -Wl,-</div><div>-gc-sections CMakeFiles/example_cpp_detect_mser.dir/detect_mser.cpp.o -o ../.</div><div>./bin/example_cpp_detect_mser -Wl,-rpath,/home/heong/opencv/opencv/build/lib -l</div><div>dl -lm -lpthread -lrt /usr/lib/arm-linux-gnueabihf/libGL.so ../../lib/libopencv_</div><div>gapi.so.4.0.0 ../../lib/libopencv_stitching.so.4.0.0 ../../lib/libopencv_aruco.s</div><div>o.4.0.0 ../../lib/libopencv_bgsegm.so.4.0.0 ../../lib/libopencv_bioinspired.so.4</div><div>.0.0 ../../lib/libopencv_ccalib.so.4.0.0 ../../lib/libopencv_cvv.so.4.0.0 ../../</div><div>lib/libopencv_dnn_objdetect.so.4.0.0 ../../lib/libopencv_dpm.so.4.0.0 ../../lib/</div><div>libopencv_face.so.4.0.0 ../../lib/libopencv_freetype.so.4.0.0 ../../lib/libopenc</div><div>v_fuzzy.so.4.0.0 ../../lib/libopencv_hdf.so.4.0.0 ../../lib/libopencv_hfs.so.4.0</div><div>.0 ../../lib/libopencv_img_hash.so.4.0.0 ../../lib/libopencv_line_descriptor.so.</div><div>4.0.0 ../../lib/libopencv_reg.so.4.0.0 ../../lib/libopencv_rgbd.so.4.0.0 ../../l</div><div>ib/libopencv_saliency.so.4.0.0 ../../lib/libopencv_sfm.so.4.0.0 ../../lib/libope</div><div>ncv_stereo.so.4.0.0 ../../lib/libopencv_structured_light.so.4.0.0 ../../lib/libo</div><div>pencv_superres.so.4.0.0 ../../lib/libopencv_surface_matching.so.4.0.0 ../../lib/</div><div>libopencv_tracking.so.4.0.0 ../../lib/libopencv_videostab.so.4.0.0 ../../lib/lib</div><div>opencv_xfeatures2d.so.4.0.0 ../../lib/libopencv_xobjdetect.so.4.0.0 ../../lib/li</div><div>bopencv_xphoto.so.4.0.0 ../../lib/libopencv_shape.so.4.0.0 ../../lib/libopencv_p</div><div>hase_unwrapping.so.4.0.0 ../../lib/libopencv_optflow.so.4.0.0 ../../lib/libopenc</div><div>v_ximgproc.so.4.0.0 ../../lib/libopencv_datasets.so.4.0.0 ../../lib/libopencv_pl</div><div>ot.so.4.0.0 ../../lib/libopencv_text.so.4.0.0 ../../lib/libopencv_ml.so.4.0.0 ..</div><div>/../lib/libopencv_dnn.so.4.0.0 ../../lib/libopencv_video.so.4.0.0 ../../lib/libo</div><div>pencv_photo.so.4.0.0 ../../lib/libopencv_objdetect.so.4.0.0 ../../lib/libopencv_</div><div>calib3d.so.4.0.0 ../../lib/libopencv_features2d.so.4.0.0 ../../lib/libopencv_fla</div><div>nn.so.4.0.0 ../../lib/libopencv_highgui.so.4.0.0 ../../lib/libopencv_videoio.so.</div><div>4.0.0 ../../lib/libopencv_imgcodecs.so.4.0.0 ../../lib/libopencv_imgproc.so.4.0.</div><div>0 <b>../../lib/libopencv_core.so.4.0.0 /usr/lib/arm-linux-gnueabihf/libGLU.so</b></div></div><div><br /></div><div>After which</div><div>fred@pi:~/opencv/opencv/build $ make</div><div><br /></div><div>Completes successfully. But there is still the installation. Set the environment variable CMAKE_INSTALL_PREFIX so that:</div><div><div><br /></div><div>fred@pi:~/opencv/opencv/build $ echo $CMAKE_INSTALL_PREFIX</div><div>/usr/local</div><div>fred@pi:~/opencv/opencv/build $ sudo make install</div></div><div><br /></div><div>And a quick test run:</div><div><div>fred@pi:~/opencv/opencv/build $ source /home/fred/opencv/OpenCV-4.0-py3/bin/activate</div><div><br /></div><div>(OpenCV-4.0-py3) fred@pi:~/opencv/opencv/build $ python</div><div>Python 3.7.3 (default, Jan 22 2021, 20:04:44)</div><div>[GCC 8.3.0] on linux</div><div>Type "help", "copyright", "credits" or "license" for more information.</div><div>>>> import cv2</div><div>>>> print(cv2.__version__)</div><div>4.0.0</div><div>>>> quit()</div></div><div><br /></div><div>And there you have it, Raspberry Pi 1 Model B Rev 2, the littlest computer that could OpenCV.</div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-89936505559765797542021-08-04T03:51:00.007-07:002021-09-19T22:41:05.406-07:00The Little Computer that Could: Motion Detection with Outdoor Camera, Tensorflow and Raspberry Pi Part 3 of 3<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVLXnxpbrYnnicZMywqSCL1WmuPC3m4tdCM_v03nsSOKBYKQidKF3xSaXVLFjvrpwZ_C4bLX1HJpL2TaYtONIUO983zUiGnbUtChV7pAtIOTDqNrC7g64vz09MGiiaHMbQprKQTqCuneDV/s1361/macbeth.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="567" data-original-width="1361" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVLXnxpbrYnnicZMywqSCL1WmuPC3m4tdCM_v03nsSOKBYKQidKF3xSaXVLFjvrpwZ_C4bLX1HJpL2TaYtONIUO983zUiGnbUtChV7pAtIOTDqNrC7g64vz09MGiiaHMbQprKQTqCuneDV/w569-h236/macbeth.jpg" width="569" /></a></td></tr><tr><td class="tr-caption">"I have no spur to prick the sides of my intent, but only vaulting ambition, which o'erleaps itself and falls on the other." - Macbeth</td></tr></tbody></table><br /><p></p><p><a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-motion.html">Motion detection with an outdoor camera</a> can be problematic, with wind, shadow and direct sunlight causing multiple false alarms. Suppressing these false alarms can result in genuine alarms being missed. One way is to filter all the alarms through an <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-yolo.html">object recognition program</a>.</p><p>The <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-motion.html">motion detection program of Part 1</a> will write all alarm image frames to the ./alarms/ directory. A modified <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-yolo.html">object recognition program of Part 2</a> will inspect each alarm frame and if an object is recognized, will write it to another directory ./alarm/. The alarm filter program is called <a href="https://github.com/cmheong/opencvalarm/blob/main/tiny-yolo_alarmfilter.py">tiny-yolo_alarmfilter.py</a>. This seemed to work well to start with, but with any new project, time will tell. For starters it seemed to think my dog is a cow, probably because she was sniffing at the grass.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8vrr3wIjmy4akIokPT1Bh66e0ny-6Plemz507jdwa1p91wm6mzO5n2_xpXDZtIu5Z2T94H-dk5ANjrOg03y1qzza73VzMNWbupSBdeyeZzmp1MTqRdQMa3Ga5pyrpRRZV3eWYNf0vtdyJ/s640/341front_20210730_173759.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="415" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8vrr3wIjmy4akIokPT1Bh66e0ny-6Plemz507jdwa1p91wm6mzO5n2_xpXDZtIu5Z2T94H-dk5ANjrOg03y1qzza73VzMNWbupSBdeyeZzmp1MTqRdQMa3Ga5pyrpRRZV3eWYNf0vtdyJ/w553-h415/341front_20210730_173759.jpg" width="553" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">tiny YOLO mislabelling dog as cow</td></tr></tbody></table><br /><p>Now my dog does have a temper, but calling her a cow is a little harsh. Even so, both dogs and cows qualify (in my opinion) as valid alarm triggers so it is not a show-stopper for now. It is particularly good at excluding changes in lighting and shadows. Proof positive that the little Raspberry Pi <b>could</b>, and <b>did</b>. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglXOaqofflGa6uzvL0_Lo3H0BO6uV9fw7lbBzoLPRc5difZRi5-QosF745BpdF4NOMEjsjBkxLY66hqXYt0_LElFWNPfs7ZnxD23OIuOtdq_2pHxbs8gowYhle84xy6lSPXgZYhZ9mgSND/s640/341front_20210731_082002.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="403" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglXOaqofflGa6uzvL0_Lo3H0BO6uV9fw7lbBzoLPRc5difZRi5-QosF745BpdF4NOMEjsjBkxLY66hqXYt0_LElFWNPfs7ZnxD23OIuOtdq_2pHxbs8gowYhle84xy6lSPXgZYhZ9mgSND/w537-h403/341front_20210731_082002.jpg" width="537" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Recognizing passing vehicles </td></tr></tbody></table><p><br /></p><p>Ah, vaulting ambition ... if the Pi can recognize an object, maybe it can also track it. Most alarms are quite passive, except for the loud siren, which tends to annoy the neighbors and should only be used as a last resort. A pan/tilt camera like the Trendnet TV-IP422WN that visibly tracks the object is a lot more menacing, and should scare off the more timid intruders like birds and squirrels. But that is another blog post.</p><p>A tensorflow model looks promising, as it can be potentially speeded up with the use of custom hardware like the <a href="https://coral.ai/products/accelerator">Coral USB acelerator</a> for about the price of a Raspberry Pi 4.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://coral.ai/products/accelerator"><img border="0" data-original-height="1125" data-original-width="2000" height="279" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlTJ5DA19I08PzP4VH1FfYiqZf9F3bvHstweEehIvD5iIu0JEdCpSPKa4M6_iltLSMFuj0DgfW1IOwlb_dFlNmMCSTya1IiXmIXQSheqMqr4DcfhjruXyIvQvyouqFgztQcGvvK1zPn15G/w496-h279/coral.webp" width="496" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://coral.ai/products/accelerator">Coral USB Accelerator</a></td></tr></tbody></table><br /><p>Installing tensorflow proved to be a bit hit and miss, but <a href="https://github.com/PINTO0309/Tensorflow-bin/#usage">Katsuya Hyodo's github readme</a> worked for me. This time I started with a squeaky clean version of Raspbian, <a href="https://www.raspberrypi.org/software/operating-systems/#raspberry-pi-os-32-bit">2021-05-07-raspios-buster-armhf.img</a>.<br /><br />Remember to uninstall the dud versions:</p><p># pip3 uninstall tensorflow<br /># apt-get install -y libhdf5-dev libc-ares-dev libeigen3-dev gccgfortran libgfortran5 libatlas3-base libatlas-base-dev libopenblas-dev libopenblas-base libblas-dev liblapack-dev cython3 openmpi-bin libopenmpi-dev libatlas-base-dev python3-dev<br /># pip3 install pip --upgrade<br /># pip3 install keras_applications==1.0.8 --no-deps<br /># pip3 install keras_preprocessing==1.1.0 --no-deps<br /># pip3 install h5py==2.9.0<br /># pip3 install pybind11<br /># pip3 install -U --user six wheel mock<br /># wget "https://raw.githubusercontent.com/PINTO0309/Tensorflow-bin/master/tensorflow-1.15.0-cp37-cp37m-linux_armv7l_download.sh"<br /># sh ./tensorflow-1.15.0-cp37-cp37m-linux_armv7l_download.sh<br /># pip3 install tensorflow-1.15.0-cp37-cp37m-linux_armv7l.whl</p><div>A quick test:</div><div><div># python3</div><div>Python 3.7.3 (default, Jan 22 2021, 20:04:44)</div><div>[GCC 8.3.0] on linux</div><div>Type "help", "copyright", "credits" or "license" for more information.</div><div>>>> import tensorflow</div><div>>>> tensorflow.__version__</div><div>'1.15.0'</div><div>>>></div></div><div><br /></div><div>For object detection I used <a href="https://pythonrepo.com/repo/EdjeElectronics-TensorFlow-Object-Detection-on-the-Raspberry-Pi-python-deep-learning">Edje Electronics</a>. </div><div><div>Packages tensorflow, libatlas-base-dev, libhdf5-dev, libhdf5-serial-dev I had already installed previously</div></div><div><br /></div><div># apt-get install libjasper-dev</div><div># apt-get install libqtgui4</div><div># apt-get install libqt4-test</div><div><br /></div><div>I used version 4.4.0.46 because 4.1.0.25 could not be found</div><div><div># pip3 install opencv-contrib-python==4.4.0.46</div></div><div># apt-get install protobuf-compiler</div><div><div># pip install --user Cython</div></div><div># pip install --user contextlib2</div><div># pip install --user pillow</div><div># pip install --user lxml</div><div><div># pip install --user matplotlib</div></div><div><br /></div><div>Got the tensorflow models</div><div><div># git clone https://github.com/tensorflow/models.git</div></div><div><br /></div><div>Then SSD_Lite:</div><div><div># wget http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_c</div><div>oco_2018_05_09.tar.gz</div></div><div># tar -xzvf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz</div><div><br /></div><div>The original tensorflow program, ./models/research/object_detection/TensorFlow.py got its images from the default Raspberry Pi camera, so I made a simpler version to take one frame (./341front.jpg in 640x480) at a time, <a href="https://github.com/cmheong/opencvalarm/blob/main/uTensorFlow.py">uTensorFlow.py</a>.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikx1XV6b_H4WPZd0cSCrPFwEzOnpM8hPNYZwWQGm_fUjUTTlLdLyVVyPlBMq3ZkllBGx3zw3H4Uc6XQQYmcLY4MUflUZh_04TKHTk6EX-EGG69-0OWc35tUpQ2LLZ8Xh-LLAS7q6V7uP36/s640/output_image_3puppies.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikx1XV6b_H4WPZd0cSCrPFwEzOnpM8hPNYZwWQGm_fUjUTTlLdLyVVyPlBMq3ZkllBGx3zw3H4Uc6XQQYmcLY4MUflUZh_04TKHTk6EX-EGG69-0OWc35tUpQ2LLZ8Xh-LLAS7q6V7uP36/w517-h388/output_image_3puppies.jpg" width="517" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Note SSD_Lite misclassified a dog as sheep</td></tr></tbody></table><br /><div>The processing time was over 40s on my Raspberry Pi 3. My Coral USB accelerator will take more than a month to arrive, and <a href="https://faun.pub/machine-learning-inferencing-through-coral-usb-accelerator-f58784d82677">it needs Tensorflow Lite</a>, for which Edje Electronics has a very <a href="https://github.com/EdjeElectronics/TensorFlow-Lite-Object-Detection-on-Android-and-Raspberry-Pi">promising Tensorflow Lite repository</a>, so why not. Notice this time the commands are as a sudoer user and not root, which I am told is the proper way to do things:</div><div><div>$ sudo pip3 install virtualenv</div></div><div><div>$ python3 -m venv tflite1-env</div></div><div><div>$ source tflite1-env/bin/activate</div></div><div><br /></div><div>Then comes a whopper of a download:</div><div><div>$ git clone https://github.com/EdjeElectronics/TensorFlow-</div><div>Lite-Object-Detection-on-Android-and-Raspberry-Pi.git</div></div><div>$ bash get_pi_requirements.sh</div><div>Notice with Tensorflow Lite there is no Tensorflow module:</div><div><div>$ python3</div><div>Python 3.7.3 (default, Jan 22 2021, 20:04:44)</div><div>[GCC 8.3.0] on linux</div><div>Type "help", "copyright", "credits" or "license" for more information.</div><div>>>> import tensorflow</div><div>Traceback (most recent call last):</div><div> File "<stdin>", line 1, in <module></div><div>ModuleNotFoundError: No module named 'tensorflow'</div><div>>>></div></div><div><br /></div><div><div>$ wget https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip</div></div><div><div>$ unzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip</div><div>Archive: coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip</div><div> inflating: detect.tflite</div><div> inflating: labelmap.txt</div></div><div><br /></div><div>The original program is TFLite_detection_webcam.py but I need a version that works on individual image files, and not a video file, as in tiny-yolo_alarmfilter.py. The progam is <a href="https://github.com/cmheong/opencvalarm/blob/main/tflite_alarmfilter.py">tflite_alarmfilter.py</a>, which took no time at all to write in python. You run it thus:</div><div><br /></div><div><div>$ python3 tflite_alarmfilter.py --resolution='640x480' --modeldir=.</div><div>Processing alarm file 341front_20210804_094635_original.png</div><div>Processing alarm file 341front_20210804_094649_original.png</div><div>Processing alarm file 341front_20210804_094648_original.png</div></div><div><br /></div><div>The framerate is now an astounding 2fps even without the Coral USB Accelerator. The detection seems slightly better with a more accurate bounding box without multiple boxes nested in the same object.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKtS-OLd8mmoJsFM9Z_4MTcipv6kSlB_mo9OqxA46JCJuB-O_z93y6TBdNcJdUtzfMfBsZ8L8rF1-aTmVRGcxw7-v_Zux8Sflgt1ihCNTalblkWfNdbeHOwDOkbnUFsS1V8rpKlgqijnKj/s640/me_tfl.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="418" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKtS-OLd8mmoJsFM9Z_4MTcipv6kSlB_mo9OqxA46JCJuB-O_z93y6TBdNcJdUtzfMfBsZ8L8rF1-aTmVRGcxw7-v_Zux8Sflgt1ihCNTalblkWfNdbeHOwDOkbnUFsS1V8rpKlgqijnKj/w557-h418/me_tfl.jpg" width="557" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Tensorflow Lite SSDLite MobileNet v2: note accurate bounding box</td></tr></tbody></table><br /><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSNTRDGE4-Ju_pDwKiCRwj8nc99-N1UW-QbOxpZq_ZRcLB3jmjXQNm_FCQaR6nCtGc42GJlH7qh4yRoAU2uqGe3YjBwOKUPBJhcikOpZDZ63StTEZtRFbpEm5DX5Fak4SKcMj6iNlnTP9Z/s640/me_tiny-yolo.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="404" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSNTRDGE4-Ju_pDwKiCRwj8nc99-N1UW-QbOxpZq_ZRcLB3jmjXQNm_FCQaR6nCtGc42GJlH7qh4yRoAU2uqGe3YjBwOKUPBJhcikOpZDZ63StTEZtRFbpEm5DX5Fak4SKcMj6iNlnTP9Z/w539-h404/me_tiny-yolo.jpg" width="539" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">tiny-YOLO: multiple bounding boxes over same object</td></tr></tbody></table><br /><div>I had originally planned to outsource the alarm files filtering to an x86 CPU, but the results with Tensorflow Lite made everything possible on the same Raspberry Pi 3, truly the little CPU that could. </div><div><br /></div><div>Happy Trails.</div><div><br /></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-64613598861086374702021-07-27T19:08:00.002-07:002021-08-04T19:55:28.065-07:00The Little Computer that Could: YOLO Object Recognition and Raspberry Pi Part 2 of 3<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://pjreddie.com/darknet/yolo/"><img border="0" data-original-height="302" data-original-width="460" height="319" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRsBvNJcPrbee10wXdDdgl3Hy91g2fmbvmQXezeqvmxH9zNiGOl8yLRQX6Ivd80rqkQo9Uu4QNcRkwJttDnUpbeVGDHDToayXnHORFwAveDwTD4K0tSsOGR5DWPIWLZRkdSSA_Ywm9pUWB/w487-h319/sayit.jpg" width="487" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://pjreddie.com/darknet/yolo/">You Only Look Once</a></td></tr></tbody></table><br /><p></p><p>One cure for <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-motion.html">motion detector false alarms in Part 1</a> is object recognition; the alarm is only raised if the intruder is recognized. YOLO is fast, trendy (deep neural net!) and will run on a Raspberry Pi. <a href="https://github.com/arunponnusamy/object-detection-opencv">arunponnusamy</a> comes straight to the point.</p><p>I already had numpy and openCV from <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-motion.html">Part 1</a>, so it is just</p># wget https://pjreddie.com/media/files/yolov3.weights<br /><br />Now this is a massive file and I needed a copper Ethernet connection to the Internet to download it. Next you download the zip file from arunponnusamy for the files yolo_opencv.py, yolov3.cfg, yolov3.txt and dog.jpg. Do not use wget on github. And simply run it:<div><br /></div><div><div># python3 yolo.py --image dog.jpg --config yolov3.cfg --weights yolov3.weights --classes yolov3.txt</div></div><div><br /></div><div>If you get 'OutOfMemoryError' you will probably need to reboot your Pi.</div><div><br /></div><div>The output should be:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbVbJHDY_BfSrbZp8QY4F9WxH5vvezVwA2CRBY6B_vcu9iwcHatqAYv3phM6FzRDzIwtX-yNaGVn2ynevL5XPynmLekkGt-eHpw906fS0PbFbgqm32Ue2zmeBus3z4-ExTq5ERk340H4wb/s416/object-detection.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="416" data-original-width="416" height="457" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbVbJHDY_BfSrbZp8QY4F9WxH5vvezVwA2CRBY6B_vcu9iwcHatqAYv3phM6FzRDzIwtX-yNaGVn2ynevL5XPynmLekkGt-eHpw906fS0PbFbgqm32Ue2zmeBus3z4-ExTq5ERk340H4wb/w457-h457/object-detection.jpg" width="457" /></a></div><br /><div><br /></div><div>I substituted a frame from my IP Camera, and sure enough it recognized a person correctly:</div><div><br /></div><div># python3 yolo.py --image alarm.png --config yolov3.cfg --weights yolov3.weights --classes yolov3.txt</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTKdFsCJmSbDuXprAKVWVOopdBff9J1yBfGTvFdf6yOtOVDHkgXswrEG6VqKIwGXPGo08jxCaSamIo5lZwzvzQ7h-oZOpAej2Z0rmGArejiWxJ2uOuxKpoS2z_UBatLgVd_KmbL5b5iwvW/s640/object-detection.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTKdFsCJmSbDuXprAKVWVOopdBff9J1yBfGTvFdf6yOtOVDHkgXswrEG6VqKIwGXPGo08jxCaSamIo5lZwzvzQ7h-oZOpAej2Z0rmGArejiWxJ2uOuxKpoS2z_UBatLgVd_KmbL5b5iwvW/w541-h406/object-detection.jpg" width="541" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Output of yolov3.weights model</td></tr></tbody></table><br /><div>For convenience, see my <a href="https://github.com/cmheong/opencvalarm">github repository</a> for copies of arunponnusamy's code. It took my Raspberry Pi 3 some 50 seconds to process the image, which is a little long but would probably keep up with the motion detector triggers of a few frames per hour. But <a href="https://github.com/arunponnusamy/object-detection-opencv">arunponnusamy</a>'s reference is <a href="https://pjreddie.com/darknet/yolo/">Joseph Redmon</a>, who also mentioned a <a href="wget https://pjreddie.com/media/files/yolov3-tiny.weights">tiny version</a> of the pre-trained neural net model. You will also need to download his yolov3-tiny.cfg, which I got by cloning from his github.</div><div><pre style="background-color: #220055; color: cyan; font-family: "Ubuntu Mono", monospace; font-size: 16px; overflow: scroll; padding: 1em;"><code style="color: lime; font-family: "Ubuntu Mono", monospace;">git clone https://github.com/pjreddie/darknet</code></pre></div><div>Joseph's executable is a C program, but the input files are the same so I simply used his tiny model files with arunponnusamy's python script:</div><div><br /></div><div><div>$ python3 yolo.py --image alarm.png --config yolov3-tiny.cfg --weights yolov3-tiny.weights --classes yolov3.txt</div></div><div><br /></div><div>Note I also reused arunponnusamy's yolov3.txt which is the dictionary of object names. Joseph's dictionary seems to be baked into his executable file. The command finishes in 5 seconds, which is 10 times better. The output bounding box is different, but it did recognize the object as a person.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcYP0C_wqBvAaLyn9QK7TBDsDIPOLub5qFlfop875uL1-pEdhdUuJwwsgj2L_RsP3HJXPiCXBJWA7E3y7yir4x7sqEInq09dWkCduapf3OlzqEDGRnGVt7s1bCpH09Ti9DvxzZLEZDHoZh/s640/object-detection-alarm6tinygood.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="640" height="395" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcYP0C_wqBvAaLyn9QK7TBDsDIPOLub5qFlfop875uL1-pEdhdUuJwwsgj2L_RsP3HJXPiCXBJWA7E3y7yir4x7sqEInq09dWkCduapf3OlzqEDGRnGVt7s1bCpH09Ti9DvxzZLEZDHoZh/w527-h395/object-detection-alarm6tinygood.jpg" width="527" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Output of yolov3-tiny.weights model</td></tr></tbody></table><br /><div>The idea is to use YOLO to filter out the false alarms from the motion detection program from <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-motion.html">Part 1</a>, In <a href="https://cmheong.blogspot.com/2021/08/the-little-computer-that-could-motion.html">Part 3</a>, we will look at tiny-YOLO, Tensorflow, and SSD_Lite. The Raspberry Pi is truly the little computer that could.</div><div><br /></div><div>Happy Trails.</div><div><br /></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-49587130252448519982021-07-27T00:11:00.007-07:002021-12-09T01:19:21.130-08:00The Little Computer that Could: motion detection with OpenCV and Raspberry Pi Part 1 of 3<p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmF5XBEna9E_SG-B3kopZs-MK4MJ9BDk3Pcs0t8fo0UqciBea3KX41fAbW_n7Y3PxkSZSFGwLT_r-DFbHT7ioRalD1T6xmN-ndR_X5NUEsFbRPt8r9VaTR3hhuzj15GZ7zvnpQNulTVFCk/s768/install-opencv4-rpi-header-768x512.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="768" height="349" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmF5XBEna9E_SG-B3kopZs-MK4MJ9BDk3Pcs0t8fo0UqciBea3KX41fAbW_n7Y3PxkSZSFGwLT_r-DFbHT7ioRalD1T6xmN-ndR_X5NUEsFbRPt8r9VaTR3hhuzj15GZ7zvnpQNulTVFCk/w524-h349/install-opencv4-rpi-header-768x512.jpg" width="524" /></a></div><div><br /></div>One of the silver linings with this pandemic lockdown is you get round to doing one or two thing you always meant to do. For me it is vision systems. I happened to be testing an lcd panel using my Raspberry Pi 3. Like that little engine, I think I can ...<div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqKokr3htVsYG4B7O1wliVy86BwPpdJN39q38LUt5n273GD9P8QTrSbs3ExlEBvE5U1q_a-huu8W4nqX6F-7gomHqQOewjJSjYXkcP55mRodhdynY0lzUkbmhH8iTsNWnhTldaAz7JBO_l/s400/little_enine.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="400" data-original-width="322" height="542" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqKokr3htVsYG4B7O1wliVy86BwPpdJN39q38LUt5n273GD9P8QTrSbs3ExlEBvE5U1q_a-huu8W4nqX6F-7gomHqQOewjJSjYXkcP55mRodhdynY0lzUkbmhH8iTsNWnhTldaAz7JBO_l/w437-h542/little_enine.jpg" width="437" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><i style="color: #202122; font-family: sans-serif; font-size: 14px; text-align: left;">As it neared the top of the grade, which had so discouraged the larger engines, it went more slowly. However, it still kept saying, "I—think—I—can, I—think—I—can."</i><span face="sans-serif" style="background-color: white; color: #202122; font-size: 14px; text-align: left;"> - The Little Engine That Could</span></td></tr></tbody></table><br /><div><br /><p><a href="https://en.wikipedia.org/wiki/OpenCV">OpenCV</a> seems as good a starting point as any. My Raspberry Pi 3 did not have the most recent image, so your mileage may vary.</p><p># cat /proc/version<br />Linux version 4.19.66-v7+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1253 SMP Thu Aug 15 11:49:46 BST 2019<br /><br /># cat /etc/debian_version<br />9.13</p><p>Using <a href="https://www.jeremymorgan.com/tutorials/raspberry-pi/how-to-install-opencv-raspberry-pi/">jeremymorgan</a>'s instructions, </p><p># apt-get update<br /># apt-get upgrade<br /><br />After a <b>really long</b> wait, it finished. If like me your downloads get interrupted you can resume using:</p><p># dpkg --configure -a</p><p>I also had to tweak jeremymorgan's instructions a little:</p><div><div># wget https://bootstrap.pypa.io/pip/3.5/get-pip.py</div></div><div># python3 get-pip.py</div><div><br /></div><div>But the next command failed:</div><div><div># pip install opencv-contrib-python</div><div>-su: /usr/bin/pip: No such file or directory</div></div><div><br /></div><div>Wait, I just installed pip!</div><div><div># whereis pip</div><div>pip: /etc/pip.conf /usr/local/bin/pip /usr/local/bin/pip2.7 /usr/local/bin/pip3.5 /usr/share/man/man1/pip.1.gz</div></div><div><br /></div><div>Ah, my python install usually seeks its commands at /usr/bin, so</div><div># ln -s /usr/local/bin/pip /usr/bin/pip</div><div><br /></div><div>Now it completes:</div><div># pip install opencv-contrib-python</div><div><div>Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python3/dist-packages (from opencv-contrib-python) (1.12.1)</div><div>Installing collected packages: opencv-contrib-python</div><div>Successfully installed opencv-contrib-python-4.1.1.26</div></div><div><br /></div><div>I'll be needing someting to play video, so</div><div># apt-get install mplayer</div><div><br /></div><div>OpenCV seems to speak native C++, but python seems like a good idea to me, so:</div><div><div># pip3 install opencv-python</div></div><div><br /></div><div>The Raspberry Pi has a built-in camera interface and all the OpenCV worked examples seems to use it, but I did not have a camera handy. What I do have is my old <a href="https://cmheong.blogspot.com/2021/02/hacking-trendnet-tv-ip422wn-ip-camera.html">Trendnet TV-IP422WN IP Camera</a>. It works with an ancient, rickety and totally unsafe version of Microsoft Explorer (ActiveX - eeek!) but with a little bit of luck, and help from <a href="https://circuitdigest.com/microcontroller-projects/stream-cctv-video-from-dvr-to-raspberry-pi-using-python-and-opencv">Aswinth Raj</a> got it to work in plain http:</div><div><br />http://192.168.10.30/cgi/mjpg/mjpg.cgi</div><div><br /></div><div>2021-08-04 update: The Trendnet TV-IP422WN also supports rtsp:</div><div><br />rtsp://192.168.10.30/mpeg4</div><div><br /></div><div>The program to test your non-Raspberry Pi video camera is <a href="https://github.com/cmheong/opencvalarm/blob/main/rtsp_videocapture.py">here</a>.</div><div><br />Now <a href="https://circuitdigest.com/microcontroller-projects/stream-cctv-video-from-dvr-to-raspberry-pi-using-python-and-opencv">Aswinth Raj</a> managed to stream video from his DVR with OpenCV using rtsp. It is not http, but worth a try. His code uses cvui, so in it goes:<br /><br /></div><div><div># pip3 install cvui</div></div><div><br /></div><div>But when you first run motion_capture.py, there are errors. You need:</div><div><div># apt-get install libatlas-base-dev</div></div><div><br /></div><div>Then the python module numpy throws an exception. For some mysterious reason this made it work:</div><div># apt-get remove python-numpy</div><div># apt-get remove python3-numpy</div><div># pip uninstall numpy</div><div><div># pip3 uninstall numpy</div></div><div><div># pip3 install numpy</div></div><div># apt-get autoremove</div><div><br /></div><div>This caused a crash and CPU reboot, after which</div><div><div># dpkg --configure -a</div></div><div># apt-get autoremove</div><div><div># pip3 install numpy</div></div><div><br /></div><div>And now, work it does. <a href="https://github.com/cmheong/opencvalarm/blob/main/motion_capture.py">Here is my http version</a>.</div><div><br /></div><div>Next is <a href="https://automaticaddison.com/motion-detection-using-opencv-on-raspberry-pi-4/">motion detection, by automaticaddison</a>. He has working python code for two methods: by absolute difference and by background subtraction. Both work without fuss; I only modified it for my Trendnet IP camera instead of the default Raspberry Pi camera.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb3KWr9fYAULBByDQg8eNXnjYJdquRzbRh2y48P5mXiUYCU-gGyw0niPSVDdEdh4Ro2NrFi3S1i3kNAhdOESiGSOJb4_iT-cOoGTZBJnooNCEErcUJAyNrCSmhd115Fz5opW1uEyreqQj4/s600/alarm.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="360" data-original-width="600" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb3KWr9fYAULBByDQg8eNXnjYJdquRzbRh2y48P5mXiUYCU-gGyw0niPSVDdEdh4Ro2NrFi3S1i3kNAhdOESiGSOJb4_iT-cOoGTZBJnooNCEErcUJAyNrCSmhd115Fz5opW1uEyreqQj4/w547-h328/alarm.png" width="547" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Note the dog is also detected but the program chose the biggest contour</td></tr></tbody></table><br /><div><br /></div><div>Now by any reasonable measure either program would solve the problem of motion detection using Raspberry Pi and OpenCV. True, the frame rate was not brilliant at 1 fps but it would detect most intrusions unless the intruder flat-out sprinted across the camera field of view.</div><div><br /></div><div>My problem was I had mounted my IP camera to look out on the front lawn which pointed the camera northeast. When run 24/7 the morning sun and the evening shadow of the house, coupled with wind blowing through the vegetation caused almost continous triggering. It did not matter if absolute difference or background subtraction was used. When motion_capture.py was modified to save the triggering images, it used up a <b>few gigabytes</b> every day.</div><div><br /></div><div>One way to reduce false alarms is to mask out problem regions. I used the cruder image cropping, which does work but over 24 hours essentially my entire background changes a few times a day. </div><div><br /></div><div>Adjusting the image threshold, including <a href="https://www.pyimagesearch.com/2021/05/12/adaptive-thresholding-with-opencv-cv2-adaptivethreshold/">adaptive thresholding</a> made little difference. Next I took a <a href="https://www.pyimagesearch.com/2015/06/01/home-surveillance-and-motion-detection-with-the-raspberry-pi-python-and-opencv/">Adrian Rosebrock's weighted average</a> (cv2.accumulateWeighted) of a few consecutive frames, and while this helped the false alarms were still annoyingly high.</div><div><br /></div><div>The next thing to try was to only raise an alarm on say 5 consecutive triggers. This caused some intrusions to be missed, particularly if the intruder moved quickly. But there were still too many false alarms. A similarly crude method was to put upper and lower limits on the size of the detected bounding rectangle (cv2.boundingRect)</div><div><br /></div><div>I ended up using all the methods in one after the other, and maybe got a few false alarms per hour. It sort of works, but was a little error-prone (ie misses intrusions). The program is <a href="https://github.com/cmheong/opencvalarm/blob/main/background_subtraction.py">background_subtraction.py</a>. One possible improvement is <a href="https://bitworks.software/en/high-speed-movement-detector-opencv-numba-numpy-python.html">Ivan Kudriavtsev's take on motion detection</a>. The installation of Numba looks a bit daunting, so I left it for another time.</div><div><br /></div><div>In <a href="https://cmheong.blogspot.com/2021/07/the-little-computer-that-could-yolo.html">Part 2</a>, we will investigate if object recognition will help.</div><div><br /></div><div>There you have it: the little Raspberry Pi that could do motion detection using OpenCV. Happy Trails.</div><div><br /></div></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-55157053465108310902021-06-22T05:30:00.023-07:002021-06-29T02:09:39.121-07:00BB View 7" LCD on Debian Buster 10.3: Abandonware revisited<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5OzbTOZwJLD0itqLiHquQxfx7qoAAFcMiDty3luMHrXRcolY6oG6S4Gk9J4Zl_OX28HRmx_0d3Y4lGbuCk9Do6U4lykWMNue9VoqEREoAH4_bz79UIN8FINwTBNJl4iju4B5BlFkHFHku/s510/bb-view.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="308" data-original-width="510" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5OzbTOZwJLD0itqLiHquQxfx7qoAAFcMiDty3luMHrXRcolY6oG6S4Gk9J4Zl_OX28HRmx_0d3Y4lGbuCk9Do6U4lykWMNue9VoqEREoAH4_bz79UIN8FINwTBNJl4iju4B5BlFkHFHku/w547-h330/bb-view.jpg" width="547" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">BB View LCD by element14. Note: the FPC cable when correctly inserted may not show printing topside</td></tr></tbody></table><br /><p></p><p><br /><br />The <a href="https://www.youtube.com/watch?v=SUVvdvYULNc&ab_channel=element14extras">BB View LCD</a> came out about mid-2013, and was one of the earliest LCD panels for the beaglebone. It came with a "cape", ie a beaglebone interface board. I bought mine in December 2014 and could not get it to work. No doubt it worked for many other people: <a href="https://www.element14.com/community/docs/DOC-67958/l/element14-bb-view-lcd-cape-software-download-centre1">it came with kernel patches and source code for Angstrom, the TI SDK as well as Debian</a>. It is still listed for sale in element14 and Mouser, but recently has become "unavailable".<br /><br />Currently, there is a worldwide semiconductor shortage, and component leadtimes are now a few months. The temptation to press the BB View 7" LCD back into service became irresistible. I think my problem was I used the kernel patches with a later, 2014 version of Debian while the patches were mid-2013. The beaglebone black could recognize the cape and read its eeprom, but the LCD stayed blank, and the backlights kept blinking in perfect unison with the beaglebone CPU LED.<br /><br />While no walk in the park, I thought it should possible to get it working. After all I have source code and it should only be a matter of time. And given the pandemic, I have four weeks of lockdown time, to be precise. And hopefully I should learn a little about kernel display drivers too.<br /><br />First you need a beefy 5V power supply. I used a 5V@3A one. While the average current draw of the BB View LCD is not that high at 240mA, there are regular nasty spikes. I got the occasional CPU crash along with sdcard errors. <br /><br /><br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirq2mNEDQ2pXC-s8xaH7NZJipKfXlJYREQ06Nkhl4gRRjQ3r4zKTN06BtygPmSHNXVPeCpzJuHus0hPgQHlDLOlg0Rd5JKdbIzvPWYx0WAgOimrfIOzuyIJ1QsgSJISNeZWnWrwEzYYYrN/s677/bbb-serialdebug.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="425" data-original-width="677" height="343" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirq2mNEDQ2pXC-s8xaH7NZJipKfXlJYREQ06Nkhl4gRRjQ3r4zKTN06BtygPmSHNXVPeCpzJuHus0hPgQHlDLOlg0Rd5JKdbIzvPWYx0WAgOimrfIOzuyIJ1QsgSJISNeZWnWrwEzYYYrN/w546-h343/bbb-serialdebug.jpg" width="546" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Beaglebone Black Serial Debug Header: Pin 1 is on the right</td></tr></tbody></table><p>You also need to connect to the serial debug port. Any USB serial TTL adapter will do. The pinout is:</p><p><br />Beaglebone<span> </span>Pin Description USB Serial TTL Adapter<br />1 <span> </span><span> </span><span> </span><span> </span><span> </span> Gnd Gnd<br />4 <span> </span><span> </span><span> </span><span> </span><span> </span> TX RX<br />5 <span> </span><span> </span><span> </span><span> </span><span> </span> RX TX<br /><br />The Beaglebone Black manual specified an FTDI USB adapter, but I used a cheap CH340, which worked well enough. The baud rate is 115200, 8-bits and 1-stop with no hardware flow control.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf"><img border="0" data-original-height="499" data-original-width="849" height="326" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIfhkUQf7YEMcl_s1ur2i92qOtR702q_im9A6H8yGY0xCRMDz_o8BiDW6cwMWAYq2O2JqQS4Ma2R_bsPc6iuGZTRCKC6ViXxm65p3Sp5LHcJc1RihUn0mVySZDriGaEGwDr4kmyO5aMPRg/w555-h326/debug-pinout.jpg" width="555" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf">FTDI Serial Debug cable. Click on picture for datasheet</a></td></tr></tbody></table><br /><br />The terminal program I use is minicom, set to 115200 baud, 8-bits, 1-stop and without hardware flow control. If you have the proper FTDI cable, you <b>should</b> use hardware flow control.<div><br /></div><div>This may be a no-brainer to some, but an LCD's size is measured at its diagonal. The BB View LCD comes in 2 software-incompatible sizes, 4.3" and 7". For the unwary, a 7" LCD measures close to 4.3" on one side.</div><div><br /></div><div>Also, the FPC cable is inserted with the metalled side facing <b>down</b> on both ends. And may not look like the picture on top. Each matching connector has a little lever which you pull up. Do not force the FPC cable.</div><div><br /></div><div><div>The Debian image I used was the latest as of this writing, which is <a href="https://beagleboard.org/latest-images">bone-debian-10.3-iot-armhf-2020-04-06-4gb.img.xz</a>. </div><div><br /></div><div>To transfer the image to sdcard, I did:</div><div><br /></div><div># xzcat bone-debian-10.3-iot-armhf-2020-04-06-4gb.img.xz | dd of=/dev/sdb</div><div><br /></div><div>Do take care to ensure /dev/sdb is the sdcard else you might end up wiping the drive on your laptop/desktop.</div><div><br /></div>The changes to the sdcard /boot/uEnv.txt boot config file are:<br /><br />dtb_overlay=/lib/firmware/BB-VIEW-LCD7-01-00A0.dtbo<br /><br />disable_uboot_overlay_video=1<br /><br />disable_uboot_overlay_audio=1<div><br /></div><div>You can download the uEnv.txt file <a href="https://github.com/cmheong/bbview/blob/main/uEnv.txt">here</a>. Notice that it specifies a binary device tree overlay file, BB-VIEW-LCD7-01-00A0.dtbo. The latest and greatest <a href="https://debian.beagleboard.org/images/bone-debian-10.3-iot-armhf-2020-04-06-4gb.img.xz">bone-debian-10.3-iot-armhf-2020-04-06-4gb.img.xz</a> happened to have them pre-compiled. I have not seen it in earlier debian images, so this is indeed a stroke of luck. I have uploaded a copy <a href="https://github.com/cmheong/bbview/blob/main/BB-VIEW-LCD7-01-00A0.dtbo">here</a> for your convenience. </div><div><br /></div><div>By the way it also has BB-BONE-LCD7-01-00A0.dtbo which also works except for an annoyingly dim backlight setting and the inability to adjust it.</div><div><br /></div><div>These dtbo files are usually something that you get by recompiling the BB View Debian source files. However, the manufacturer supplied BB View Debian source file BB-VIEW-LCD7-01-00A0.dts did not work for me when compiled to dtbo files. On close examination it is missing pin definitions for 8 LCD panel data pins, lcd_data16 - lcd_data23.</div><div><br /></div><div><div>Typically the beaglebone black boots by default from the eMMC, so you need to hold down the 'Boot' button on the beagleboard before you power on. The BB View cape gets in the way, but it helpfully provides a second 'Boot' button on the cape. </div><div><br /></div><div>Given the power demands of the BB View, I found it more reliable not to boot from the power switch. Rather there is a 'Power' button on the beaglebone black which you can use. <br /><div><br /></div><div>The LCD displayed the login screen for tty1, and you can log in by plugging a USB keyboard into into the USB Host (ie USB Type B) connector.</div><div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOeJrNpL0aubNkBS6d1GnvQNTZ-PK13FipP2SGd8xI7adNbfaKgfNUVgPo4G7FCG1ZUnjx4O2JMMHDHe4RD2BvuUWB7yYPEwg93WhykuOf0XZG6A_adP6mY8X9NrTN1AJOT1nhw8ZC_MiP/s2048/bb-view_done.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="961" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOeJrNpL0aubNkBS6d1GnvQNTZ-PK13FipP2SGd8xI7adNbfaKgfNUVgPo4G7FCG1ZUnjx4O2JMMHDHe4RD2BvuUWB7yYPEwg93WhykuOf0XZG6A_adP6mY8X9NrTN1AJOT1nhw8ZC_MiP/w540-h961/bb-view_done.jpg" width="540" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Working BB View 7" LCD with Debian Buster 10.3</td></tr></tbody></table><br /><div>To display picture files from the command prompt I used fbi with a little help from <a href="https://www.element14.com/community/community/designcenter/single-board-computers/next-genbeaglebone/blog/2015/11/18/beaglebone-black-lcds-with-prebuilt-fbtft-drivers">Drew Fustini</a>:</div><div><div><br /></div><div>root@beaglebone:~# apt-get update</div><div>root@beaglebone:~# apt-get install fbi</div></div><div># wget https://kernel.org/theme/images/logos/tux.png</div><div># fbi -d /dev/fb0 -T 1 -a tux.png</div><div><br /></div><div>For video I used mplayer:</div><div># apt-get install mplayer</div><div><br /></div><div>This worked for me as there is no audio when using the BB View LCD:</div><div><br /></div><div># export SDL_NOMOUSE=1<br /></div><div><div># mplayer -nolirc -vo sdl:driver=fbcon -ao null test.mpg</div></div><div><br /></div><div>My test mpg file happened to have a resolution of 480x360. The BB View 7" LCD is 800x600 but mplayer could not quite get the scaling correct. Whan scaled manually this works:</div><div><div><br /></div><div># mplayer -nolirc -vo sdl:driver=fbcon -ao null -x 800 -y 533 test.mpg</div></div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioaNzDgvfaqzHb_hX4XdnUfIdIEGVTBCjOad8roQKhDSuxthIcIYHu_IeoztXuTt3CuM8uwiYJEMOj-S0rXJfLqr_waQRFIFbCvXjNN1zNdtetrJm8ODVrsm_WAdzvZ2Y7EiHNi8ankPIQ/s2048/mplayer.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioaNzDgvfaqzHb_hX4XdnUfIdIEGVTBCjOad8roQKhDSuxthIcIYHu_IeoztXuTt3CuM8uwiYJEMOj-S0rXJfLqr_waQRFIFbCvXjNN1zNdtetrJm8ODVrsm_WAdzvZ2Y7EiHNi8ankPIQ/w360-h640/mplayer.jpg" width="360" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">mplayer </td></tr></tbody></table><br />Debian 10.3 did not seem to recognise the touchscreen, but a little peek at the decompiled dtbo file mentioned a tscadc kernel modue:</div><div><br /></div><div><div> fragment@5 {</div><div> target = <&tscadc>;</div><div> __overlay__ {</div><div> status = "okay";</div><div> tsc {</div><div> ti,wires = <4>;</div><div> ti,x-plate-resistance = <200>;</div><div> ti,coordinate-readouts = <5>;</div><div> ti,wire-config = <0x00 0x11 0x22 0x33>;</div><div> ti,charge-delay = <0x400>;</div><div> };</div><div> adc {</div><div> ti,adc-channels = <4 5 6 7>;</div><div> ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>;</div><div> ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>;</div><div> ti,chan-step-avg = <16 2 4 8>;</div><div> };</div><div> };</div><div> };</div></div><div><br /></div><div>A search of the dmesg log produced:</div><div><div>[Thu Jun 24 10:21:40 2021] input: ti-tsc as /devices/platform/ocp/44e0d000.tscadc/TI-am335x-tsc.0.auto/input/input0</div></div><div><br /></div><div>Which led me to</div><div><div># ls -l /sys/devices/platform/ocp/44e0d000.tscadc/TI-am335x-tsc.0.auto/input/input0/event0</div></div><div><br /></div><div>A quick check of the shows that tapping the LCD does indeed produce a response:</div><div><div># hexdump -C -v /dev/input/event0</div><div>...</div><div>00000780 81 9f d5 60 e6 e6 06 00 03 00 01 00 2c 08 00 00 |...`........,...|</div><div>00000790 81 9f d5 60 e6 e6 06 00 03 00 18 00 92 03 00 00 |...`............|</div><div>000007a0 81 9f d5 60 e6 e6 06 00 00 00 00 00 00 00 00 00 |...`............|</div><div>000007b0 81 9f d5 60 1f 03 09 00 01 00 4a 01 00 00 00 00 |...`......J.....|</div><div>000007c0 81 9f d5 60 1f 03 09 00 03 00 18 00 00 00 00 00 |...`............|</div><div>000007d0 81 9f d5 60 1f 03 09 00 00 00 00 00 00 00 00 00 |...`............|</div></div><div><br /></div><div>Another bit of electronics rescued from the scrap heap cannot be that bad.</div><div><br /></div><div>Happy Trails.</div><div><br /></div><div>PS</div><div>Why not use the element14 files and go with the <a href="https://github.com/cmheong/bbview/blob/main/BB%20VIEW%20User%20Manual%20V3.pdf">BB View manual</a>? Believe me, I tried. For 14 days. I started off with the oldest <a href="https://beagleboard.org/latest-images">Debian images</a> I could find, co-incidentally the same Debian 7.5 of 2014-05-14 that I used back then. And got the same result. And since there were 3 different patches, one each for Angstrom and TI SDK, I tried them as well but none worked. The Angstrom version was older 2013-06-20 and worked slightly better: the LCD backlight did not blink in concert with he CPU light and was quite controllable on its own. But in all cases the LCD stayed resolutely blank. </div><div><p>There is a wealth of information on the subject, not to mention source code. But there is no schematic, so reading it would be harder. Two weeks later, I could <a href="https://software-dl.ti.com/processor-sdk-linux/esd/docs/latest/linux/Overview/Download_and_Install_the_SDK.html">rebuild the latest TI SDK</a>, or even <a href="https://longervision.github.io/2018/01/10/SBCs/ARM/beaglebone-black-uboot-kernel/">mainline Linux kernel using Linaro</a>, but neither version worked with the BB View LCD. The problem as mentioned earlier was the device tree source code, which I suspect was incomplete for the 7" LCD. The 4.3" version probably worked, but I did not test this. </p><p>It was starting to become clear why there was such heavy development over so many years: there is precious little standardization in ARM systems on how to interface to external boards. Each ARM board basically is unique, and back in 2013 this was <a href="https://elinux.org/BeagleBone_and_the_3.8_Kernel#The_trouble_with_board_files">hardcoded into the kernel source</a>.</p><p>At some point each variation was defined in a '<a href="https://elinux.org/BeagleBone_and_the_3.8_Kernel#The_trouble_with_Device_Tree">device tree</a>' that was compiled separately from kernel. In practice this simply means a separate sub-directory with its own Makefile all under the same master ARM build. </p><p>Eventually, with <a href="https://lkml.org/lkml/2011/3/17/492">a little encouragement from Linus Torvalds</a>, the device tree code was shifted to the ARM bootloader, 'Das U-Boot'. This is where the Beaglebone Debug Serial Port comes in handy. Many of the BB View LCD problems are reported only as system console messages, ie to the Debug Serial Port, and may not even show up in the kernel log. </p><p>Thus, unlike the manufacturer, Debian admirably maintained support for the BB View. As usual, the documentation became hopelessly out of date, as befits abandonware. </p><p>After 2 weeks, Lady Luck took pity on me. I always have a late version of Beaglebone Debian, in this case Debian Buster 10.3 of 2020-04-06. The micro-sdcards are too tiny to label, and I swapped it into the BB View LCD system by mistake. It complained it missed the file BB-VIEW-LCD7-01-00A0.dtbo which just happened to be in the eMMC partition (as /dev/mmcblk1p1). One small change in the boot config file and it worked! Took all of 5 minutes.</p></div><div>Which leaves me 2 more weeks of lockdown time to fill. Maybe it's time to watch 'Das Boot' again ...</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://www.youtube.com/watch?v=MfyzlkzUBSA&ab_channel=RaptoR"><img border="0" data-original-height="377" data-original-width="511" height="349" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD11AcSp-aYnIeecHE0QRsxHKgy1nYYIjZ7Lmj6diHw2WYIBA5stXVUbRPj9CoP5sP4L5dDus8y85UwvHcu3cwukfm5pH_k9WzYtGJNxCAjLdg9jzpccoo5CgaKS9ozSfXT3y_zeIA4UDV/w473-h349/das-boot.jpg" width="473" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.youtube.com/watch?v=MfyzlkzUBSA&ab_channel=RaptoR">Das Boot: Wolfgang Petersen's 1981 classic</a></td></tr></tbody></table><br /><p><br /></p></div></div></div></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com1tag:blogger.com,1999:blog-7125203381804324279.post-27901327269451978062021-05-30T23:30:00.001-07:002021-05-30T23:33:25.445-07:00Repairing the PICkit 2<p> <br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin7A_UUMUuS7dDwQQXnSiGE2DXpx1TnpRDZfrIHrhv8Qn6gXnPR2tbdK-Vy2IPUk-ZnObcUh4yjY1R1eBry5JwLI-DCwR79TSaY6XqLQ7nW21lJhstOEqyF4r5vtq8BHBXlfSDJRXcGOTA/s490/PICkit-2.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="222" data-original-width="490" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin7A_UUMUuS7dDwQQXnSiGE2DXpx1TnpRDZfrIHrhv8Qn6gXnPR2tbdK-Vy2IPUk-ZnObcUh4yjY1R1eBry5JwLI-DCwR79TSaY6XqLQ7nW21lJhstOEqyF4r5vtq8BHBXlfSDJRXcGOTA/w576-h261/PICkit-2.jpg" width="576" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Microchip PICkit 2 Programmer</td></tr></tbody></table><br /><p></p><p>My PICkit 2 failed:</p>$./pk2cmd -PPIC16F1705 -GC<br />Read successfully.<br />Configuration Memory<br />0000 0000<br />VPP Error detected. Check target for proper connectivity.<br /><div><br /></div><div>PICkit 2s are not expensive, more so the China clones now available online. Neither is its successor the PICkit 3, so I could easily have thrown it away. But it came with a great <a href="https://github.com/cmheong/pk2cmd/blob/main/pickit2/pickit2_51553e.pdf">manual</a>, complete with source code and schematics which is uncommon. Plus the original PICkit 2 is getting hard to find these days and PICkit 3 might have issues supporting some legacy CPUs. In any case I could repurpose it: not only it is a USB device, it has a ready-made connector with 2 IO ports and a nifty 12V-0V pin. </div><div><br /></div><div>A VPP error is probably to do with the MCLR pin:</div><br />Pickit2 JTAG Connector Function<br /> Pin 1 MCLR/Vpp <br /> Pin 2 Vdd <br /> Pin 3 Gnd<br /> Pin 4 Data <br /> Pin 5 Clk<br /> Pin 6 N/C<div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsxotf6uc_k0K5a4sQMYZBP6Fnn9TE2zBIAKSVnFSfJWC9A3vxuZhNYkaCPYC5Wb52ofbXCwx_hQ8Y_yNDnE4GLcYUlOfuwjE3fMABYeG6pQQWx98gk_5m_f2xY9gVCsFifEdZ2e36lnxi/s314/6wayheader.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="200" data-original-width="314" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsxotf6uc_k0K5a4sQMYZBP6Fnn9TE2zBIAKSVnFSfJWC9A3vxuZhNYkaCPYC5Wb52ofbXCwx_hQ8Y_yNDnE4GLcYUlOfuwjE3fMABYeG6pQQWx98gk_5m_f2xY9gVCsFifEdZ2e36lnxi/w429-h273/6wayheader.jpg" width="429" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">6-way header</td></tr></tbody></table><br /><div><br /></div><div>To check MCLR(pin 1) I just stuck a 6-pin header into the PICkit 2 connector and measured it with respect to Pin 3 (Gnd). It helps to make a little bash script:</div><div><div><br /></div><div>$cat ./testpickit2</div><div>for i in {1..5..1} </div><div>do </div><div> sleep 5</div><div> ./pk2cmd -PPIC16F1705 -GC</div><div>done</div></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy3V7t9epl_tqmgVoUPPE1PitD6EJ-hiAH8Vl5P6PptjHYQ6w0nh_6Dxr9FVtb-6Sn7p4uFO_Gqh1Gbcii_du0JoUggdL-UMW9ga-pP8KNlr_mU_eX1eg7UmkMNXVDUUxoOqUUtOiccocL/s1089/chargepump.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="748" data-original-width="1089" height="385" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy3V7t9epl_tqmgVoUPPE1PitD6EJ-hiAH8Vl5P6PptjHYQ6w0nh_6Dxr9FVtb-6Sn7p4uFO_Gqh1Gbcii_du0JoUggdL-UMW9ga-pP8KNlr_mU_eX1eg7UmkMNXVDUUxoOqUUtOiccocL/w560-h385/chargepump.jpg" width="560" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">MCLR (or Vpp) schematic diagram </td></tr></tbody></table><br /><div><br /></div><div>The multimeter measures MCLR at 0.15V. A sanity check with a good PICkit 2 showed this goes well up to 12V. The schematic shows an ingenious DC boost converter, using the CPU pin Vpp_Pump to periodically short the inductor L1 to ground. There is even Vpp_FEEDBACK pin to regulate its output. Two additional CPU pins, Vpp_ON and MCLR_TGT are used to switch the resulting regulated high voltage to pin 1 of the JTAG connector (ie the programming port).</div><div><br /></div><div>I pried open the plastic case and the repair job just became a lot simpler. L1 the 680uH surface-mounted inductor fell off the PCB!</div><br /><div><br /></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrAjE7KI6GBw2ra8rr3o0Qe8Ounm-itdvTWW_hySuiGajSWOqiD6hlLcCKPIjdXDm_Y7ayC5b530a1kA3FUxaQQLERabj-CfMqmOl8x3pvSffzKnYF-XyltoOoFRiVFrpewizbjIs3pvyu/s2048/inductor_detached.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="313" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrAjE7KI6GBw2ra8rr3o0Qe8Ounm-itdvTWW_hySuiGajSWOqiD6hlLcCKPIjdXDm_Y7ayC5b530a1kA3FUxaQQLERabj-CfMqmOl8x3pvSffzKnYF-XyltoOoFRiVFrpewizbjIs3pvyu/w556-h313/inductor_detached.jpg" width="556" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Detached inductor L1. The original position is circled in red</td></tr></tbody></table><br /><div>This happens quite a bit with surface-mounted components, particularly when subjected to mechanical stress. The inductor is among the tallest component and would have been compressed by my fingers through the thin plastic case.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj27Bk2pthynWgDGyaTXFR2NyVrY52BeuS3l5w3v0_J6qniXgLu2VvyPOwNPMIvHeGcRCW1auTE7nec75n-YrYjDmojz3tHAIvODUim3COJm8efFtE48gA9cyQ7-BuLBv4lMEfzzNXu0bLE/s2048/680uH_inductor.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="879" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj27Bk2pthynWgDGyaTXFR2NyVrY52BeuS3l5w3v0_J6qniXgLu2VvyPOwNPMIvHeGcRCW1auTE7nec75n-YrYjDmojz3tHAIvODUim3COJm8efFtE48gA9cyQ7-BuLBv4lMEfzzNXu0bLE/w494-h879/680uH_inductor.jpg" width="494" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">680uH Inductor. Note the plastic former is plated at the ends and the inductor wire is then soldered on.</td></tr></tbody></table><br /><div>The plastic, metal-plated lead has snapped off one end. I thought it would be a slam-dunk to solder the unbroken end back on the PCB and solder the broken wire directly to the PCB. Boy I was wrong: the wire was so thin it was hardly visible under high magnification. Worse, when I stripped the enamel insulation using my soldering iron, this made the wire brittle and it eventually broke off. </div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVIE-x7GOTCqm7n-i_kVhx84ruSryuhcEINDCMeOhqiqJvr1CKMn-oapxbaUoCNBsZ8x0X3I2gyL7AjLAhnXRsnBNB6jlGCrJ7h9OlVJfWc4BNYOUsxbkgbhExN5ZbP2Qsn_v5WGBrTqzi/s2048/old_and_new.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVIE-x7GOTCqm7n-i_kVhx84ruSryuhcEINDCMeOhqiqJvr1CKMn-oapxbaUoCNBsZ8x0X3I2gyL7AjLAhnXRsnBNB6jlGCrJ7h9OlVJfWc4BNYOUsxbkgbhExN5ZbP2Qsn_v5WGBrTqzi/w562-h316/old_and_new.jpg" width="562" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">New inductor (bottom left) is larger than the original</td></tr></tbody></table><br /><div><br /></div><div>A new 680uH inductor, 74404054681 INDUCTOR, 680UH, 0.25A, 20%, SEMI-SHLD from element14 cost RM5 (USD1). I chose it to match the leads pitch of 4mm; the other dimensions were uncomfortably larger than the original but this was the only part with a reasonably sane delivery date. I was concerned it might be too tall and prevent the plastic case from snapping shut.</div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV30fBhL8xwqp9IO_X_I-o4QyLvbGjiAt3QwPdsE1VdZ88rgO7zNtf9CRMHtq-1EK5PyUtcm480je880H8tfoVVCdBonHQTkHlLMtvq1gU596eqVI1VhdCdADyU84avpBem2sSI8QaJzYb/s2048/soldered.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV30fBhL8xwqp9IO_X_I-o4QyLvbGjiAt3QwPdsE1VdZ88rgO7zNtf9CRMHtq-1EK5PyUtcm480je880H8tfoVVCdBonHQTkHlLMtvq1gU596eqVI1VhdCdADyU84avpBem2sSI8QaJzYb/w555-h312/soldered.jpg" width="555" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Working PICkit 2</td></tr></tbody></table><br /><div><br /></div><div>Soldering was a little tight: you need to solder the right-hand lead first and slide it right to make room for the iron tip at the left lead. But there was a happy ending: the case snapped shut and the PICKit 2 worked.</div><div> </div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-21908168390898993032021-05-23T01:16:00.005-07:002021-05-23T02:19:09.843-07:00I love cheap thrills: WiFi OTA for Microchip PICs<p> <br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://www.youtube.com/watch?v=nYh-n7EOtMA&ab_channel=SiaSiaVerified"><img border="0" data-original-height="700" data-original-width="994" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMoaMQN88wvinXrn-8y_OAeQAaNlFyqRyXuJ3CRfyQj12m2m9F82D2RiXoXpjOdP1XJRXbsvfcGnPP9zAB2eJPhy1SeWMoK5QspX-KapKpNg7CNAaff8JwWzbuTEG7d_Ka1L6n5NQh40XV/w520-h366/CheapThrills.jpg" width="520" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.youtube.com/watch?v=nYh-n7EOtMA&ab_channel=SiaSiaVerified">Cheap Thrills - Sia</a></td></tr></tbody></table><br /><br /><i>"Come on, come on, turn the radio on<br />It's Friday night, and it won't be long<br />Gotta do my hair, put my make-up on<br />It's Friday night, and it won't be long<br />'Til I hit the dance floor, hit the dance floor<br />I got all I need<br />No, I ain't got cash, I ain't got cash<br />But I got you, baby<br />Baby, I don't need dollar bills to have fun tonight<br />(I love cheap thrills)" - </i>Sia, Cheap Thrills<p></p><p>Firmware <a href="https://en.wikipedia.org/wiki/Over-the-air_programming">Over The Air programming (OTA)</a> is all the rage with <a href="https://en.wikipedia.org/wiki/Internet_of_things">Internet of Things (IoT)</a> devices. Ongoing privacy and security issues make it almost mandatory that they be upgradeable after installation. That usually means OTA upgrades using a smartphone App or a desktop browser.</p><p>For a hobbyist, or just plain fast and cheap development, few systems beat the ESP8266-based IoT OTA, <a href="https://cmheong.blogspot.com/2019/09/arduinoota-programming-of-esp-01s-via.html">ArduinoOTA</a>. The ESP8266 has a few flaws. It is difficult to operate on small batteries: sleep mode still requires milliamps and while using WiFi it can surge to 100mA. Also, executing the WiFi stack takes priority and this sometimes causes interrupt service routines to have unpredictable delays. Most applications are OK with this, unless your code is time-critical like trying to a dimmer triac while connected to WiFi.</p><p>Microchip CPUs in particular shine at low-cost, low-power performance and raw horsepower. But their WiFi OTA solutions tend towards the later, more expensive models. Wouldn't it be great if we can have OTA for the Microchip CPU, say a PIC16F84 or even a PIC16F1705 if you want to roll C code? In particular the latter has a mouth-watering dedicated zero-crossing detect (ZCD) interrupt which would be very handy for a flicker-free dimmer or a heavy-duty switching of inductive loads.</p><p>It turns out this can be done. We build an ESP8266 into a Microchip PIC system and use the former's WiFi capability to program the PIC. WithArduinoOTA, both the ESP8266 and PIC have OTA. Microchip's recommendation is to use a bootloader, ie reserve dedicated program space in the PIC for bootloader so that it can be programmed via its serial port. This possible for the PIC161705 but would would be a very tight squeeze for the PIC16F84 - the low-end PICs are usually short on memory. In addition the bootloader would be unable to change certain startup configuration bits.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglL9dSY8sE2rapfA7pzw-uH7EO-CXxYvSwqEjtbexpPBW1LNsdt9_4dWHZYHDGCp-yRpZWU19s8PdNaIYGg6khUuVpcmcMmUlR_rOJnoTPIeNkoy_WzThOGeBeezybxlHotmaCz5-PbLUj/s647/pickit2.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="348" data-original-width="647" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglL9dSY8sE2rapfA7pzw-uH7EO-CXxYvSwqEjtbexpPBW1LNsdt9_4dWHZYHDGCp-yRpZWU19s8PdNaIYGg6khUuVpcmcMmUlR_rOJnoTPIeNkoy_WzThOGeBeezybxlHotmaCz5-PbLUj/w504-h271/pickit2.jpg" width="504" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">PICkit 2 programmer (left) connected to a target system via its JTAG port</td></tr></tbody></table><p><br />There is another way to do serial programming for a Microchip PIC: most of them support In-Circuit Serial Programming or ICSP. This is the same method a Microchip Programmer like the PICkit 2 uses. An ESP8266 program speaking ICSP to the PIC will be able to program it without resorting to a bootloader. It turns out this has already been done: <a href="https://hackaday.io/project/18340-esppic-esp-based-pic-programmer">mengstr's esppic</a> hackaday project. His <a href="https://github.com/mengstr/esppic">source code is in github</a>.</p><p>This post really has little to add to mengstr's work, except maybe a little documentation on how to get it up and running, and with luck add some support for the PIC16F84 or even the venerable <a href="https://cmheong.blogspot.com/2021/05/development-system-for-ancient.html">PIC16F57</a>.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCaS6XMrNlSDrENkhK5hfH59270axQzUf6BhS1-1l6Ba5GoCsw6asJGVaE1FecnYxKo4xb6jgKkbtIMGWORev61dIvfL95ILo0z0AozG1UGrsRfhM8CnHz44hQtxRc5wAjwv7RCMJQ83DV/s1280/16f1705devsys.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="960" data-original-width="1280" height="393" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCaS6XMrNlSDrENkhK5hfH59270axQzUf6BhS1-1l6Ba5GoCsw6asJGVaE1FecnYxKo4xb6jgKkbtIMGWORev61dIvfL95ILo0z0AozG1UGrsRfhM8CnHz44hQtxRc5wAjwv7RCMJQ83DV/w525-h393/16f1705devsys.png" width="525" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Schematic for target CPU board</td></tr></tbody></table><br /><p>The ESP-12E to JTAG programming connector pinout is:</p><p> Pickit2 ESP-12E</p><p> Pin 1 MCLR/Vpp D0/GPIO16</p><p> Pin 2 Vdd 3V3</p><p> Pin 3 Gnd Gnd</p><p> Pin 4 Dat D1/GPIO5</p><p> Pin 5 Clk D2/GPIO4</p><p> Pin 6 N/C</p>This way the PIC16F1705 development board can be programmed from both the PICkit 2 and the ESP-12E. The JTAG port also lets you run the target system directly from the PICkit 2. Not having to unplug the target system and hooking it up to another power source greatly speeds up the development cycle.<br /><br /><div>PICkit 2 might need an updated <span face="Verdana, Geneva, sans-serif" style="background-color: white; color: #222222; font-size: 14px;">PK2DeviceFile.dat file for the PIC16F1705. In my case I use pk2cmd with Linux. pk2cmd needs to be updated to work with <a href="https://github.com/GBert/misc/tree/master/pickit2/pk2cmd/pk2cmd">Gerhard Bertelsmann's version of pk2cmd</a>. </span> It is tucked away in a gigantic 300MB misc repository, so I copied it <a href="https://github.com/cmheong/pk2cmd">here</a> for your convenience. To compile, simply:</div><div><br /></div><div>$make linux</div><div><br /></div><div>To test, plug the target CPU board into the PICkit 2 JTAG port.</div><div><div>$./pk2cmd -PPIC16F1705 -GC</div><div>Read successfully.</div><div><br /></div><div>Configuration Memory</div><div><br /></div><div>3EFF 3F87</div><div><br /></div><div>Operation Succeeded</div></div><div><br /></div>To program,<div><br /></div><div><div>$./pk2cmd -PPIC16F1705 -Fblink_led.hex -M</div><div>PICkit 2 Program Report</div><div>18-5-2021, 9:38:13</div><div>Device Type: PIC16F1705</div><div><br /></div><div>Program Succeeded.</div><div><br /></div><div>Operation Succeeded</div></div><div><br /></div>To run,<div><br /></div><div><div>$./pk2cmd -PPIC16F1705 -GC -T -R</div></div><div><br /></div>To stop running (in order to unplug)<div><br /></div><div><div>$./pk2cmd -PPIC16F1705 -GC</div><div><br /></div></div><div>To compile my program I used sdcc sample code from <a href="https://github.com/diegoherranz/sdcc-examples/tree/master/pic14/1.blink_led">Diego Herranz</a>. For Debian sdcc installation is simply:</div><div>#apt-get update</div><div>#apt-get sdcc</div><div><br /></div><div>For Slackware it is a little bit more involved. We need the pic14-port ad pic16-port so first get the <a href="https://sourceforge.net/projects/gputils/files/latest/download">gputils source code</a>.</div><div><div>$./configure</div></div><div>$make clean</div><div><div>$make</div></div><div>$su -c "make install"</div><div><br /></div><div>Next get the sdcc source code from <a href="https://sourceforge.net/projects/sdcc/files/latest/download">sourceforge</a></div><div><br /></div><div>Next, untar it:</div><div><div>$tar -xvjf sdcc-src-3.9.0.tar.bz2</div></div><div><br /></div><div>Then build it:</div><div>$./configure</div><div><div>$make -j 10</div></div><div>$su -c "make install"</div><div><br /></div><div>Here is Diego Herranz's pic14/1.blink_led/blink_led.c modified slightly for the PIC16F1705:</div><div><br /></div><div><div>// Copyright (C) 2014 Diego Herranz</div><div><br /></div><div>#define NO_BIT_DEFINES</div><div>#include <pic14regs.h></div><div>#include <stdint.h> </div><div><br /></div><div>// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN),</div><div>// disable watchdog,</div><div>// and disable low voltage programming.</div><div>// The rest of fuses are left as default.</div><div>//__code uint16_t __at (_CONFIG1) __configword = _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _LVP_OFF;</div><div>__code uint16_t __at (_CONFIG1) __configword = _FOSC_INTOSC & _WDTE_OFF & _LVP_OFF;</div><div><br /></div><div>#define LED_PORT PORTCbits.RC0</div><div>#define LED_TRIS TRISCbits.TRISC0</div><div><br /></div><div>// Uncalibrated delay, just waits a number of for-loop iterations</div><div>void delay(uint16_t iterations)</div><div>{</div><div> uint16_t i;</div><div> for (i = 0; i < iterations; i++) {</div><div> // Prevent this loop from being optimized away.</div><div> __asm nop __endasm;</div><div> }</div><div>}</div><div><br /></div><div>void main(void)</div><div>{</div><div> LED_TRIS = 0; // Pin as output</div><div> LED_PORT = 0; // LED off</div><div><br /></div><div> while (1) {</div><div> LED_PORT = 1; // LED On</div><div> //delay(30000); // ~500ms @ 4MHz</div><div> delay(5000); // ~500ms @ 4MHz</div><div> LED_PORT = 0; // LED Off</div><div> //delay(30000); // ~500ms @ 4MHz</div><div> delay(5000); // ~500ms @ 4MHz</div><div> }</div><div>}</div></div><div><br /></div><div>To compile it:</div><div><div>$sdcc -mpic14 -p16f1705 --use-non-free blink_led.c</div></div><div><br /></div><div>If you do not want the hassle of compiling it, here is the hex file:</div><div><br /></div><div><div>:020000040000FA</div><div>:10000000000080310328DE30FB008030FC008030AF</div><div>:100010008031832080312C00A1007C08A000E030DA</div><div>:10002000A2008030A3002C002008A4002108A50015</div><div>:10003000FF30A007031CA10324082504031980280E</div><div>:1000400004302207A400A501A50D2308A507240854</div><div>:10005000FB002508FC0080308031832080312C009B</div><div>:10006000A7007C08A6002208FB002308FC008030C3</div><div>:100070008031832080312C00A900A5007C08A800D5</div><div>:10008000A40002302207A400A501A50D2308A5079E</div><div>:100090002408FB002508FC0080308031832080315B</div><div>:1000A0002C00A500AB007C08A400AA002C002608A8</div><div>:1000B000AA002708AB00FF30A607031CA7032A08E5</div><div>:1000C0002B0403197A282808FB002908FC0080303B</div><div>:1000D0008031A02080312C00AA002408840025084B</div><div>:1000E00085002A088000A80A0319A90AA40A03198E</div><div>:1000F000A50A562806302C00A2070318A30A1328C5</div><div>:100100008031B2280800003A03198B28803A03197D</div><div>:100110009328FC0100347B0884007C0885001200D1</div><div>:10012000FC00000808008031AD20FA00FB0FFC0342</div><div>:10013000FC0A8031AD20F9007A08FC00790808003B</div><div>:10014000003A0319A728803A0319AD2800347B0828</div><div>:1001500084007C088500000808007C088A007B0871</div><div>:100160008200080021000E1020000E1020000E1446</div><div>:100170008830FC0013308031C820803120000E1000</div><div>:100180008830FC0013308031C8208031B628080048</div><div>:100190002C00AD007C08AC00AE01AF012C002D0896</div><div>:1001A0002F02031D02322C082E020318DD28000046</div><div>:1001B0002C00AE0A0319AF0ACE280800013400341F</div><div>:0E01C000E634003430340634013400340034A8</div><div>:020000040001F9</div><div>:02000E00E41FED</div><div>:00000001FF</div></div><div><br /></div><div>Next we move on to the Arduino IDE to compile <a href="https://hackaday.io/project/18340-esppic-esp-based-pic-programmer">mengstr's esppic</a> code over at <a href="https://github.com/mengstr/esppic">his github repository</a>. The ESP8266 code is in https://github.com/mengstr/esppic/tree/master/esppic, and you need to set the compile settings for NodeMCU ESP-12E, CPU speed 80MHz. </div><div><br /></div><div>You will also probably need to pull in a library from <a href="https://github.com/Links2004/arduinoWebSockets">Websockets library from here</a>. In addition you will need to put in the same local Arduino code directory, a sub-directory named <i>data</i> and fill it with the files from mengstr's https://github.com/mengstr/esppic/tree/master/assets. They are necessary for the webserver code for the ESP8266. </div><div><br /></div><div>In the Arduino IDE, go to Tools->ESP8266 Data Upload and program the SPIFFS data/ files. Next, program the ESP8266 NodeMCU via the USB port. It comes up as a WiFi Access Point, so connect to it, maybe with your smartphone or laptop. With a browser, connect to http://192.168.4.1 and type in your WiFi SSID and password.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUud8M5bZ27qe2oxa_mLXbPXvGjxqVR3Xgx-7O_lBJQyJFe8o0ipWalrDtrKjg98cEkD_hThUUOHTmi8CxjP8rKk5sDnCJ7pahf_EvQkMDZ3k2Dl_PBYlfbdK96owev8mfZpXcJBU3ipnM/s2048/targetsystem.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUud8M5bZ27qe2oxa_mLXbPXvGjxqVR3Xgx-7O_lBJQyJFe8o0ipWalrDtrKjg98cEkD_hThUUOHTmi8CxjP8rKk5sDnCJ7pahf_EvQkMDZ3k2Dl_PBYlfbdK96owev8mfZpXcJBU3ipnM/w569-h320/targetsystem.jpg" width="569" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">NodeMCU ESP-12E wired to JTAG port of PIC16F1705 target CPU board</td></tr></tbody></table><br /><div><br /></div><div>Now power off and connect it to the JTAG port of the PIC16F1705 target board. Make sure in Arduino IDE you have the Debug Monitor active at the USB serial port, as it will come up with the IP address as it starts up. Say it is 12.34.56.78. With a browser, connect to http://12.34.56.78.</div><div><br /></div><div>You should see something like this in the Debug Monitor :</div><div><div><br /></div><div>Connecting to wifi using default info</div><div>..</div><div>Successfully connected. IP=12.34.56.78</div><div>handleFileRead(/)</div><div>/index.html (0 bytes) Open:53 Stream:1 Close:0</div><div>handleFileRead(/)</div></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ThnIt-Evsqa68IqegdWQqsbOYy__vEMVzoQfgbZ8nGouqx-v-IuSUBOLettWc40RtiSWSG8dpGA_vdF08ni_lrHZitd5kinFxa2miOdEsdrhgLZU01arqbHQKxxq8-PE8M4AGzKUNTan/s780/webserver.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="507" data-original-width="780" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ThnIt-Evsqa68IqegdWQqsbOYy__vEMVzoQfgbZ8nGouqx-v-IuSUBOLettWc40RtiSWSG8dpGA_vdF08ni_lrHZitd5kinFxa2miOdEsdrhgLZU01arqbHQKxxq8-PE8M4AGzKUNTan/w546-h355/webserver.jpg" width="546" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Screenshot of programming webpage</td></tr></tbody></table><br /><div><br /></div><div>You should first try reading the CONFIG1 and CONFIG2 registers. In my case I had trouble getting a brand-new blank PIC16F1705 to work; I had to first program it with the PICkit 2. If it works, the browser should show:</div><div><br /></div><div><div>MEMORY DUMP</div><div>DEV ID : 3055</div><div>DEV REV: 2003</div><div>CONFIG1: 1fe4 (0001 1111 1110 0100)</div><div>CONFIG2: 3fff (0011 1111 1111 1111)</div><div>USER ID: 3fff 3fff 3fff 3fff</div></div><div><br /></div><div>Followed by a memory dump, something like:</div><div><div><br /></div><div>0000: 0000 3180 2803 30DE 00FB 3080 00FC 3080 3180 2083 3180 002C 00A1 087C 00A0 30E0</div><div>0010: 00A2 3080 00A3 002C 0820 00A4 0821 00A5 30FF 07A0 1C03 03A1 0824 0425 1903 2880</div><div>0020: 3004 0722 00A4 01A5 0DA5 0823 07A5 0824 00FB 0825 00FC 3080 3180 2083 3180 002C</div></div><div>...</div><div><br /></div><div>To program use a browser, or navigator or Konqueror to drag the hex file over to the programming icon. I could not get mine to work with Google Chrome, but Konqueror or Firefox works for me.</div><div><br /></div><div>Sometimes esppic locks up during a memory dump or programming; I find it best to simply power-cycle it and start afresh. For some reason I could not get it to recover from an error condition. Notice the PIC16F1705's programming datasheet recommends using 5V while programming and we are using 3.3V so maybe this caused the flakiness. You can at a pinch wire it to the ESP-12E's 5V, but I would not recommend long-term usage like that as the ESP8266 datasheet says it is a 3.3V device and mught get over-stressed. It would be instructive to try the PIC16LF1705, which is an explicitly low-voltage version.</div><div><br /></div><div>There you have it, WiFi OTA for the Microchip PIC16F1705. <i>I don't need dollar bills to have fun tonight. I love cheap thrills.</i> </div><div><br /></div><div>Happy Trails.</div><div><br /></div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com1tag:blogger.com,1999:blog-7125203381804324279.post-45815727191250338482021-05-12T07:49:00.000-07:002021-05-12T07:50:51.939-07:00Development System for the ancient Microchip PIC16F57 CPU<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF2WWN5Kvoy89gEgkSwbgTjZEW44fLAV2h_YsoRykPrePiY_C71nP-t68K6zb__up1e_2y3MkjJc8DGs1x-coHTQG2pHwExlVO5_F0Zd8xnAyKOVqRBpGjeycaQitO2Rrq4YNZlcch9NRb/s2048/program_n_run.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="834" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF2WWN5Kvoy89gEgkSwbgTjZEW44fLAV2h_YsoRykPrePiY_C71nP-t68K6zb__up1e_2y3MkjJc8DGs1x-coHTQG2pHwExlVO5_F0Zd8xnAyKOVqRBpGjeycaQitO2Rrq4YNZlcch9NRb/w469-h834/program_n_run.jpg" width="469" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Microchip PICkit 2 Programmer with target system</td></tr></tbody></table><br /><p></p><p>The Microchip PIC16F57 is an ancient CPU, long superceded and only grudgingly sold by Microchip Inc. Indeed there is currently a 2-month wait for them. It has a tiny 2K word program memory and a microscopic 72 bytes RAM. Too small to use with C, To program it, you would need assembly language. Why would I want to waste time on something like that? </p><p>I have a <a href="https://cmheong.blogspot.com/2018/11/autogate-adventures-voice-control-via_30.html">remote gate opener ('autogate')</a> which I tinker with unmercifully. It is also underneath an powerhead mains power pole which seems to get struck by lightning a few times a year, so over the years I accumulated a stack of dead S-1 controller boards which I usually repair and reuse. Except for those few which had dead CPUs.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimuwXpEkXBDZxpDDV8cW3oKP4c35Axz4IOJSYiJu_rMEL44KibK7ImNKh8fFMlLcLM0YpFyUe39AkMkINaZcC1xd5Su1cu9TIyo6wWyzs_RP6iHIVkPWwgPA6eQR4CyB48xFnBUOK8WbSm/s400/S-1.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="260" data-original-width="400" height="371" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimuwXpEkXBDZxpDDV8cW3oKP4c35Axz4IOJSYiJu_rMEL44KibK7ImNKh8fFMlLcLM0YpFyUe39AkMkINaZcC1xd5Su1cu9TIyo6wWyzs_RP6iHIVkPWwgPA6eQR4CyB48xFnBUOK8WbSm/w571-h371/S-1.jpg" width="571" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">S-1 Autogate Controller Board</td></tr></tbody></table><br /><p>Now they are cheap enough: RM100 (USD25) will buy you one online. But repairing these last boards meant replacing the CPU, which meant writing the program for it. After some effort, I noticed that the CPU footprint is an exact match for the Microchip PIC16F57, and I even have one in my CPU tray.</p><p>Writing the program also means I can upgrade the CPU to a newer one, and maybe add WiFi connectivity as well. And since the Chinese can <b>sell</b> me the board cheaper than I can make it, it does not make sense to make my own PCB. To upgrade it I would first have to replicate its functions, and that means writing the program from scratch.</p><p>But before I can even do that I have to find an Assembler, device programmer and build a little target system (PIC16F57 CPU board) just to make sure the toolchain works.</p><p>Microchip's MPLAB Version 8.33 (an equally ancient version running on Microsoft Windows XP) works for me. It comes with the MPASM assembler which happened to support the PIC16F57. You can try your luck with the <a href="https://www.microchip.com/en-us/development-tools-tools-and-software/mplab-x-ide">latest and greatest MPLAB</a>, but if it does not work out, you can get Version 8.33 from the <a href="https://www.microchip.com/en-us/development-tools-tools-and-software/mplab-ecosystem-downloads-archive">Microchip MPLAB archive</a>. I run a Windows XP image from a <a href="https://www.qemu.org/">Qemu-KVM</a> virtual machine and use <a href="https://github.com/psmay/pk2cmd">pk2cmd</a> with my <a href="https://www.microchip.com/developmenttools/ProductDetails/PartNO/PG164120">PICkit 2 programmer</a>, but you will probably be quicker off the mark with a Windows XP laptop.</p><p>The next thing you need is a little PIC16F57 (ie target) board just to accept the PICkit 2 connector and also run a small test program. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMf6Y1Z1iYS80vsgeBOtne790FZTUq3igsIuQhMt_aH8CefpuMKhbYI1BP2JKXi57QWKQrPHfyO511XA-jppCUoKgIJQCk1KPOH4QzYhcCRRH_KEH9I5LZPGQvVzQnJ4dYkuR4jIG9OXGZ/s1280/development_system.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="960" data-original-width="1280" height="371" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMf6Y1Z1iYS80vsgeBOtne790FZTUq3igsIuQhMt_aH8CefpuMKhbYI1BP2JKXi57QWKQrPHfyO511XA-jppCUoKgIJQCk1KPOH4QzYhcCRRH_KEH9I5LZPGQvVzQnJ4dYkuR4jIG9OXGZ/w495-h371/development_system.png" width="495" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">PIC16F57 target system</td></tr></tbody></table><br /><p><br /></p><p>Then you need the test program which you feed into your MPLAB assembler and produce the hex file the PICkit 2 needs to program the CPU. Usually you can find such sample programs in the great wide Internet but for some reason, not for the PIC16F57. You can find the schematics, hex file and source code <a href="https://github.com/cmheong/PIC16F57">here in my github repository</a>.</p><p>To program the PIC16F57 I use:</p><p><span face="-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"" style="background-color: white; color: #24292e; font-size: 16px;">$./pk2cmd -PPIC16F57 -Fledblink.hex -M</span></p><p>To run it I use:</p><p><span face="-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"" style="background-color: white; color: #24292e; font-size: 16px;">$./pk2cmd -PPIC16F57 -GC -T -R</span></p><p>Some notes of caution: my experience is a Microchip CPU in a new target system can be hard to start. The combination of your choice of oscillator affects the Power-on Reset Timer delay. The MCLR reset circuit also changes things. You also need to sort out you Reset and Watchdog Timer vectors without which you program will not start. Once you get past that it is usually plain sailing. Using a Microchip Development Kit makes real sense here, but they have long since abandoned the PIC16F57. Also having a known good toy program helps when you are trying to start the CPU.</p><p>Despite having only 2K the PIC16F57's memory is also segmented. The simplest way is to ensure the program sits within page zero 000-1FF. This is because subroutines calls only work within page 0. You can next just 2 levels of subroutines.</p><p>Lastly the digital output pins are set and cleared (ie BSF and BCF) using a Read-Modify-Write mechanism. This means the CPU does not keep a record (ie a register) of your IO bits. It also accesses IO 8 bits at a time and if it executes a write, it will first read the whole byte from the external circuits, modify the read data and writes back the 8 bits. This can have unexpected effects if you are not running within the electrical operating limits (ie driving too much current into an LED). Also a CPU IO write followed immediately by a read may execute too fast for the external circuit.</p><p>The RC system clock circuit is a little hard to time accurately because of its inherent inaccuracy and component tolerances. If your LED does not blink, you might need to adjust the delay intervals. If that fails, seek to dim the LED rather than blink it.</p><p>This is a hard-core RISC instruction set, running in a Harvard Architecture (ie program and data busses are separate). There is usually no substitute to reading every single word in <a href="https://github.com/cmheong/PIC16F57/blob/main/PIC16C57.pdf">the datasheet</a>.</p><p>If this is your first time with assembly language, congratulations. You have talked to a CPU in its own language, <i>mano a silicona</i>, and it understood you. </p><p>Good Luck, and Happy Trails. </p>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-70585635380267939522021-05-05T21:28:00.017-07:002021-05-06T00:40:11.353-07:00SMD Hot-Air Rework Station Repair <p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiwwKZyo7Wr09VYmf9PlfI18HC1b3VnCYZzY_sOgdcI-A_YVac_2Ib2R9Wvv13HoR5lGO_IYDoL8ROaGndD_j0sdkJsTuRnkea1BjP8wdF8e1kVgAE0A6cvkeZjS64R3A4hDTv_hzdSz5z/s2048/assembled_frontpanel.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiwwKZyo7Wr09VYmf9PlfI18HC1b3VnCYZzY_sOgdcI-A_YVac_2Ib2R9Wvv13HoR5lGO_IYDoL8ROaGndD_j0sdkJsTuRnkea1BjP8wdF8e1kVgAE0A6cvkeZjS64R3A4hDTv_hzdSz5z/w553-h311/assembled_frontpanel.jpg" width="553" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Ya Xun Hot-Air Rework Station cost just RM209 (less than USD50) </td></tr></tbody></table><br /><p></p><p>Last year I bought a cheap hot air rework station. It was probably not a good idea - I have never used one before, and this being pandemic season, I would be on my own. My eyesight is not getting any sharper but the electronic components are definitely getting smaller. On the other hand, all the fun stuff nowadays, like ESP8266, Aduino and Raspberry Pi all seem to use Surface Mount Devices. And most compellingly, SMD parts are much cheaper than their through-hole equivalents. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCaXWXzx9nd1bAUWx3i0i6OB6-xojtb-sqokJBhDxmlI24YrJf24VbEkovEqDxKa3yVwmCjkhJ07ScEUOCmmXcGjLtk3gbMNkaoHaiQqxEV0EY2Wr0GTonwzOoGPoDmY4e7l8ruJQyTLsP/s580/smd-components-e1540318482287.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="242" data-original-width="580" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCaXWXzx9nd1bAUWx3i0i6OB6-xojtb-sqokJBhDxmlI24YrJf24VbEkovEqDxKa3yVwmCjkhJ07ScEUOCmmXcGjLtk3gbMNkaoHaiQqxEV0EY2Wr0GTonwzOoGPoDmY4e7l8ruJQyTLsP/w520-h218/smd-components-e1540318482287.png" width="520" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Some SMD components are just about manageable using old-school soldering irons</td></tr></tbody></table><p><br /></p><p>I found myself buying soldering irons with smaller and smaller tips, right down to 0.5mm. With discrete SMD I simply used two irons (I would have used more but I ran out of hands): you can often heat up the entire thing and lift it clean off with two irons. To solder a new SMD part in I used the 0.5mm iron. SMD ICs were a problem: sometimes you just could not heat up all the leads with two irons. But if I had new ICs on hand I would simply cut the IC off the printed circuit board. You then removed each soldered lead one by one. </p><p>You need a small and really sharp pair of micro-cutters. Anything less and the leads tend to get ripped off along with the tiny PCB pads. That cutter you never lend out or use for anything else. You guarded it jealously and threatened anyone with immediate bodily harm if he tried to take it.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPr_4-HPrOAXd9FPK2ZQYNjcqnDxrd5yhqh9DwdULGMDThxtihjmAgYUxXspThNem3dW7EMqiwEqNus_VJhbs-j-NKa5YrcdxtyrEgLWEjZYlT6I3bJUNxgaMUeHCydIwPIdmnlb3eUZOY/s208/microcutter.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="200" data-original-width="208" height="447" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPr_4-HPrOAXd9FPK2ZQYNjcqnDxrd5yhqh9DwdULGMDThxtihjmAgYUxXspThNem3dW7EMqiwEqNus_VJhbs-j-NKa5YrcdxtyrEgLWEjZYlT6I3bJUNxgaMUeHCydIwPIdmnlb3eUZOY/w465-h447/microcutter.jpg" width="465" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Duratool's micro cutter: don't leave home without it. </td></tr></tbody></table><p><br /></p><p>But QFN and BGA SMD packages were quite another thing. The contacts and PCB pads are underneath the body, and only a hot air gun will get them off without damaging the PCB. Well, I could sneak the PCB into the wife's oven in the kitchen, but this tends to remove all the parts. To inspect the soldering, one would need nothing less than an X-ray machine. </p><p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBoOpY-4GaaKyUmiM6L6Dp584HxjLcWYeLvJTmKOvrQb4cEnGYue3uKxc5xonpsephByup_at2ckrafQ22XKlEgB3_VFvleqaISL7oP6z9_IczT4ycM40j8F2TZfGjAkpbW7GaIoKYtdCb/s600/QFN.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="184" data-original-width="600" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBoOpY-4GaaKyUmiM6L6Dp584HxjLcWYeLvJTmKOvrQb4cEnGYue3uKxc5xonpsephByup_at2ckrafQ22XKlEgB3_VFvleqaISL7oP6z9_IczT4ycM40j8F2TZfGjAkpbW7GaIoKYtdCb/w542-h166/QFN.png" width="542" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">QFN (Quad Flat No-lead) IC</td></tr></tbody></table><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiregVkcTs77UipI4RLcOWNIWZ0WP6YwYsNeOGcTsH8-YN9HV2_wz0zYZSSy-bv9Z6JPKnBulPSFdBSmImRlPmUnY5V1mNnHr2wbMVP1LZIhDNPVewXOyVDMG2kliXaMZsCe_AwDhucWFo/s493/BGA.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="219" data-original-width="493" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiregVkcTs77UipI4RLcOWNIWZ0WP6YwYsNeOGcTsH8-YN9HV2_wz0zYZSSy-bv9Z6JPKnBulPSFdBSmImRlPmUnY5V1mNnHr2wbMVP1LZIhDNPVewXOyVDMG2kliXaMZsCe_AwDhucWFo/w570-h253/BGA.png" width="570" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">BGA (Ball Grid Array) IC</td></tr></tbody></table><br /><p>Even when there are no BGA or QFN parts, sometimes there is simply not enough room to place the irons, and neighboring parts may get moved, burnt or worse. But then came a China siren to lead me into temptation: at only RM209 (less than USD50) the Ya Xun 850A+ cost about as much as a Raspberry Pi 4. The clunky box may even be an advantage - it is less likely to use SMD parts, which makes it repairable with soldering irons.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5AoL8f4WzEtRvTjIMaEL4l57za1tvD57y5NrM51LapSCBshsQJkY8Zctsj_qghvjAmxf67KIDOSQ2uUw6mIGAn-v5lkrqVCO0XVH3iLnm1SzAM-OSfz_oCbQMuOeYl6owGuhFmpEJvuie/s500/YX850A.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="500" data-original-width="500" height="494" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5AoL8f4WzEtRvTjIMaEL4l57za1tvD57y5NrM51LapSCBshsQJkY8Zctsj_qghvjAmxf67KIDOSQ2uUw6mIGAn-v5lkrqVCO0XVH3iLnm1SzAM-OSfz_oCbQMuOeYl6owGuhFmpEJvuie/w494-h494/YX850A.jpg" width="494" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">China temptress</td></tr></tbody></table><br /><p>In about a year it failed completely: it blew its fuse. After replacement, its temperature LED no longer lit up and the hot air flow is no longer adjustable. I whipped off the cover and got the PCB out. Usually I could figure put most PCBs but looking at the parts mounted. But only if I am already familiar with them. There is just one problem: I had never worked with triacs before and this board had two, in essentially AC power "dimmer" type circuits. This means to make any sense of it I would need to first trace out the schematic. Oops.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTeLJUO1IrrFz7Ckw_gKnVs7GL0kp-8Qjxa63qBvbnVeIywJ8yASLddTUg8tjOjNo27bhHNGYQMVl2ZpP8XYCjhonu8iP1ZhcFo3zS_GEIUkHS2icH6CsF9ff-pR-F2HpUKnn5NrE2_8Y3/s2048/PCB.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1152" data-original-width="2048" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTeLJUO1IrrFz7Ckw_gKnVs7GL0kp-8Qjxa63qBvbnVeIywJ8yASLddTUg8tjOjNo27bhHNGYQMVl2ZpP8XYCjhonu8iP1ZhcFo3zS_GEIUkHS2icH6CsF9ff-pR-F2HpUKnn5NrE2_8Y3/w550-h308/PCB.jpg" width="550" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">YX850A+ Controller PCB: old-school single-sided PCB with through-hole parts</td></tr></tbody></table><br /><b><span style="color: red; font-size: large;">Warning: this repair deals with lethal voltages. Do not attempt unless you have been properly trained!</span></b><br /><p>The PCB used old-fashioned through-hole components as expected. Even better, the PCB is single-sided: it only has traces on the bottom (ie solder) side. This makes it easy to trace the leads; PCB traces o the component (ie top) side will run under the parts and be obscured. Single-sided PCBs are also easy to desolder. </p><p>Tracing the PCB was not so bad, but having worked with a human PCB designer for over 10 years, hand-drawing schematics felt lame so it seemed like a good idea to install <a href="http://wiki.geda-project.org/">geda</a> again. Two weeks later, armed with the <a href="https://github.com/cmheong/SMDreworkstation">schematics</a> and a wobbly <a href="https://www.electronics-tutorials.ws/power/triac.html">knowledge of triacs and diacs</a>, the repair work began.</p><p>The first problem was the internal wiring was badly crimped; the wires were the wrong sizes and the resulting crimped joints were loose, in particular those at the front panel switch.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMUxBY3dZN8IccWiNnoN-CjCIDedIPE8rlsKD_1KA6fFQwO-EPEUbLYR7XKGvqN7_FQ-o4Pk33TMOT2orD4v9H2tgtZ_2C_VuhBU8jku6D2Ek8GbawvJ5adPQJOaQsUXfXPV-nsxul09-E/s2048/frontswitch_wiring.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMUxBY3dZN8IccWiNnoN-CjCIDedIPE8rlsKD_1KA6fFQwO-EPEUbLYR7XKGvqN7_FQ-o4Pk33TMOT2orD4v9H2tgtZ_2C_VuhBU8jku6D2Ek8GbawvJ5adPQJOaQsUXfXPV-nsxul09-E/w360-h640/frontswitch_wiring.jpg" width="360" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Loose crimp connectors at the panel switch (top) and temperature sensor wiring (bottom)</td></tr></tbody></table><br /><p>The front panel main switch switches in both mains AC and 12V DC to the PCB and loose joints here cannot be healthy for the triacs. And sure enough the triac Q2 BT136-600 is shorted Gate to T2. The LED D1 which indicates airflow was also shorted, together with its series rectifier D2 (1N4007). Unusually, the LED appeared to be driven directly by the triac output AC and is probably more sensitive to line surges. The PCB trace from D2 to Neutral was melted a good 4mm. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggmIQyq1e7Zu_Emf4DmKmv4vv6Vw91d3S-FuQfLcLCvcoWmvmBWEdzVZa8Jxl2rCyJLTGx_E2exM4nYFG6S5ajCAz9WBzXPUoLhso8ms5cABKdMooUDbJbYh_3wjFBUVMGGAdTBfenn81G/s604/triac1_circuit.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="574" data-original-width="604" height="461" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggmIQyq1e7Zu_Emf4DmKmv4vv6Vw91d3S-FuQfLcLCvcoWmvmBWEdzVZa8Jxl2rCyJLTGx_E2exM4nYFG6S5ajCAz9WBzXPUoLhso8ms5cABKdMooUDbJbYh_3wjFBUVMGGAdTBfenn81G/w485-h461/triac1_circuit.jpg" width="485" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">BT136 triac and associated components</td></tr></tbody></table><br /><p>The gate drive diac, D4 (DB3) and its series capacitor C5 (120nF polyfilm) were also shorted. Now triacs are turned on using the gate, but can only be turned off by letting its load current drop to zero, which means interrupting its input mains. This is done using a relay K1 (HK4100F-DC12V-SHG an Omron G5V-1 equivalent). The relay is powered from 12V output from U3, an LM7812 linear regulator which was also shorted input to output.</p><p>The other triac, a BTA12-600 supplying the heater seems to be fine. The heater LED failure was due to a loose temperature sensor wire. The heater is probably a lot less inductive than the air pump motor. It also helps it is triggered from another optically-isolated triac U2, an MOC3023. Interestingly the MOC3023 drives the main triac's gate using a series rectifier D4 (1N4007) which means it only puts out half the AC waveform and pretty much guarantees the BTA12 turns off during the other half cycle. The MOC3023 is in turn driven by the temperature sensor via U1, an HA17358 (probably an LM338 workalike) which seems none the worse for wear despite being exposed to unregulated 25Vdc from the shorting LM7812. The 40V maximum of the LM338 probably helps.</p><p>Repair was easy. The parts easily dismounted and replaced. The dodgy crimp connectors were soldered to their wires. Replacement parts were cheap and arrived quickly despite the pandemic-induced parts shortage. The <a href="https://my.element14.com/">Malaysian branch of Element14</a> in particular offered free delivery, in contrast Digikey wanted USD89 to deliver a USD2 part.</p><p>To test, I used a 300VA isolation transformer dialed down to 220Vac (China boards are rated for 220V; Malaysian grid is 230V but I am at the very end of the mains power line at a feisty 240V). For additional safety I also used a portable ELCB (RCD to Americans). Since some semiconductors (usually mains bridge rectifiers) are connected directly to mains AC sometimes there is a short from Live to DC ground, and an ELCB will pick this up.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFRVUDs3TliGHn_w_3Ruxwzsh27Cg6ZVWf-657SVqFswKKvJOJqAODZP5_H0LYCol_9v41ZHiAh_FSz-mm7QH-FTWqpEbnTeLojCkLZQWGJsheje9YRjfyz47s24vXLY4okyw7XQUgprqq/s640/portable_ELCB.jpeg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="640" data-original-width="557" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFRVUDs3TliGHn_w_3Ruxwzsh27Cg6ZVWf-657SVqFswKKvJOJqAODZP5_H0LYCol_9v41ZHiAh_FSz-mm7QH-FTWqpEbnTeLojCkLZQWGJsheje9YRjfyz47s24vXLY4okyw7XQUgprqq/w348-h400/portable_ELCB.jpeg" width="348" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Portable ELCB</td></tr></tbody></table><br /><p>An isolation transformer is a two-coil transformer (ie not an autotransformer) putting out the same voltage level as its input. If the output is shorted, the current is limited by the magnetic flux saturating in its core, limiting power delivered to its VA rating. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4ZGW3HLRQhFDjaykN2uI52pVhP48T94sfbYI_WkbLS7145TpZ1lOmKvGY66K4-Mcj22kESJzfD_AvWoalbusNiJ30v3wvRzWhHXk53jX1-JEICN0umM_NOg_81JbTn05xL4oJxjQ9S4a3/s250/isolation_transformer_schematic.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="175" data-original-width="250" height="417" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4ZGW3HLRQhFDjaykN2uI52pVhP48T94sfbYI_WkbLS7145TpZ1lOmKvGY66K4-Mcj22kESJzfD_AvWoalbusNiJ30v3wvRzWhHXk53jX1-JEICN0umM_NOg_81JbTn05xL4oJxjQ9S4a3/w596-h417/isolation_transformer_schematic.jpg" width="596" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">110Vac Isolation Transformer. Note the Earth line passes through but Live and Neutral are isolated. </td></tr></tbody></table><br /><p><br /></p><p>It often lets you diagnose faulty boards before it completely burns out. 60VA, or even 30VA are very handy ratings, and the idea is to progressively work up to the full device rating. I always make my own; a handy way is to use two regular (ie step-down) transformers connected back to back. To dial down the output voltage you will need to use a variable transformer to drive the isolation transformer.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinBC9KART_2GtLT7NEfLeW2qt1HObOn27F7stvcdcHbY7UQUlvv3RN78Lz5trpz3HUC3adaRfNpI3sskJPxMMZMA4TsqfzfknnCMlFYCjwot6NjkFtlcBXl8rnx2MkkmwAH1nOtafzT955/s376/isolation_transformer.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="353" data-original-width="376" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinBC9KART_2GtLT7NEfLeW2qt1HObOn27F7stvcdcHbY7UQUlvv3RN78Lz5trpz3HUC3adaRfNpI3sskJPxMMZMA4TsqfzfknnCMlFYCjwot6NjkFtlcBXl8rnx2MkkmwAH1nOtafzT955/w393-h369/isolation_transformer.jpg" width="393" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">2000VA Isolation transformer from Carroll & Meynell</td></tr></tbody></table><p><br /></p><p>Testing was straightforward except for one thing: the air pump continued to run despite the panel power switch being turned off. Despite having used it for a whole year, I did not really notice if it did that before. My excuse was I was struggling with tiny SMD parts. Having the air pump run meant the BT136 is on. Was the relay turning off?</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivp32vThUtW2e0UPkgmwSJnlIsGhyTlERe301aaRxvmoHqcG0Mh_qAoC2lzCW5WHPNMTaO-QE5hKpOwrjsFiP96tGurQhk27BxQYamqBcZSltPXddws71IhRo17oU6wR92byOfL_bCzEos/s657/airpump_relay_circuit.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="499" data-original-width="657" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivp32vThUtW2e0UPkgmwSJnlIsGhyTlERe301aaRxvmoHqcG0Mh_qAoC2lzCW5WHPNMTaO-QE5hKpOwrjsFiP96tGurQhk27BxQYamqBcZSltPXddws71IhRo17oU6wR92byOfL_bCzEos/w437-h332/airpump_relay_circuit.jpg" width="437" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Air pump relay circuit</td></tr></tbody></table><br /><p>I needed to make some live measurements. This is never a good idea when dealing with stuff connected to mains AC. The isolation transformer protects the repair item but will easily deliver a fatal shock to a human (50mA or 15VA will ruin your day, probably your life) . The mounting wires are short and the board has to be mounted vertically which means reaching past exposed live bits to probe. </p><p>Thus far I had looked for defective parts the safe and preferred way: offline, unpowered and using a digital multimeter. If you suspected something you took it out and make some more measurements. When testing I powered up at low VA, operated the panel knobs and switches and avoided touching exposed parts. </p><p>NPN transistor Q6 (SS8050) was an immediate suspect - with the panel switch off, its collector was 6V, way lower than the 12V if it were off. Maybe it was leaking? It tested OK dismounted: both semiconductor diode junctions seemed OK, but maybe it was partially leaking? I replaced it with a generic 2N2222 (watch it: ON Semi produces a PN2222 with reversed leads unlike my KSP2222A), but there was no change; the air pump kept running even though the panel switch is off.</p><p>An examination of the circuit provided a clue. In addition to switching in mains voltage, it also switched on 12V to Q6 (and the opamp). The capacitor C6 is 220uF and will store a walloping charge and R19_2 measures about 100K in-situ but is probably higher (the color codes are faded with heat). When switched off, it will ensured it discharged slowly into the base of Q6. The time constant is in the order of 22 seconds. And always fearing a defect I had been quick to cut off power to the isolation transformer while testing.</p><p>Using <a href="https://www.ibiblio.org/kuphaldt/electricCircuits/DC/DC_16.html">this formula</a>, my Change is 95% (12V to 0.6V) at time constant 22 will result in a delay time of 64.8s. I assembled and tested it again; and sure enough after a long minute the air pump went off. But why would it want do that? It is somewhat misleading to have the power on even after the panel switch is off. The <a href="https://www.aoyue.eu/media/manuals/90/90850/EN/90850_Aoyue_Hot_Air_Station_en.pdf.pdf">manual for a similar system</a> yielded this clue:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrL54M529U08nyAUHrnPcraQUo4lFlEM5ADJ1o9p7ihLEE8eY7Pswct50U75adSsgeTk571PkoPmgDcXERCixGVF1_94j6QYfn3BgadTSbfwNLjfi3pf5H0sNPN2TQH-340MmIYDtafDuX/s627/manual_autocool.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="100" data-original-width="627" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrL54M529U08nyAUHrnPcraQUo4lFlEM5ADJ1o9p7ihLEE8eY7Pswct50U75adSsgeTk571PkoPmgDcXERCixGVF1_94j6QYfn3BgadTSbfwNLjfi3pf5H0sNPN2TQH-340MmIYDtafDuX/w565-h90/manual_autocool.jpg" width="565" /></a></div><br /><p>Ah, that was unexpected, but at least it was not broken. I would recommend you spend that minute, set the airflow to maximum and wait for the air pump to finish doing its thing, and then turn the YX850A+ off at the power socket, for the manual goes on to say:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEge_3eIc-Pjk6onL2QVU-jkCDIkZhNVNqK9lbV6DPP1OSnsVwKKSKLR_XEwHIXsxnLMd9c2PSgQuB5qIiMxuHntGIXQ7gBT5jzYeRw12sXjqJPdzHERqoRH5-wyhhUKQHOoWH9gZMi8Lc0l/s618/manual_turnoff.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="66" data-original-width="618" height="58" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEge_3eIc-Pjk6onL2QVU-jkCDIkZhNVNqK9lbV6DPP1OSnsVwKKSKLR_XEwHIXsxnLMd9c2PSgQuB5qIiMxuHntGIXQ7gBT5jzYeRw12sXjqJPdzHERqoRH5-wyhhUKQHOoWH9gZMi8Lc0l/w551-h58/manual_turnoff.jpg" width="551" /></a></div><br /><p>An auto-disconnect would be nice, maybe a few seconds after the air pump turns off. So would a thermal cutoff switch. And the triac heatsinks looked puny with the cooling fins horizontal instead of vertically where they would do most good. But that is a project for another day. </p><p>There you have it: Hot-Air SMD Rework Station Repair.</p><p>Happy Trails.</p><p><br /></p>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-89704287149622357282021-04-16T07:26:00.001-07:002021-04-16T07:29:59.943-07:00USB over IP: How to remote-access your USB devices over the network<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG_dn8hUHUA0dlrQnHa3U4H3BTL4YZPH05u_362eFn1oHeJ9oZVN8XRdw_b7S0n_8R74iU36W6OYKAtFhFToftFViAHvEY_c9FWZCXcK7UPtSDPcAsBBje-0JRzO-4A-CHSQB0gU5i-Dj2/s800/800px-Usbip.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="353" data-original-width="800" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG_dn8hUHUA0dlrQnHa3U4H3BTL4YZPH05u_362eFn1oHeJ9oZVN8XRdw_b7S0n_8R74iU36W6OYKAtFhFToftFViAHvEY_c9FWZCXcK7UPtSDPcAsBBje-0JRzO-4A-CHSQB0gU5i-Dj2/w576-h254/800px-Usbip.png" width="576" /></a></div><br /><p></p><p>First appearing in 2005 in <a href="https://www.usenix.org/legacy/events/usenix05/tech/freenix/hirofuchi/hirofuchi.pdf">Takahiro Hirofuchi's kickass paper</a>, there are much better guides on USB/IP, like <a href="https://www.linux-magazine.com/Issues/2018/208/Tutorial-USB-IP">Linux Magazine's</a>, <a href="https://developer.ridgerun.com/wiki/index.php?title=How_to_setup_and_use_USB/IP">Ridgerun</a>'s, etc. From 2009 USB/IP was accepted into mainline Linux kernel and up-to-date documentation on it tends to get lost in the Linux haystack. The wrinkle here is USB/IP running on Slackware 14.2-current as of July 2019. Unlike Debian/Ubuntu you cannot usually seamlessly install USB/IP (or most other things) on Slackware. A little DIY is in order.</p><p>I know that is cold comfort compared to Debian's 'apt install'. Indeed, Slackware too has its (a little rickety) SlackBuild scripts. But in USB/IP case there is no SlackBuild as it was already included in the kernel. Well, after a fashion.</p><p>But take heart: in 30 years of Slackware I seldom fail to install the things I want. This is a chance to poke a little into the innards of Linux. You have the source code in all its glory. And it is built beautifully - I say this as one who has seen Microsoft Windows NT source code [shudder]. </p><p>And the experience will prove useful in the rare instances Debian's installs fail, like the time I installed the Java development kit and could no longer log into my desktop. This means when things fail the same methods work: paste the error into google and look for the patches and workarounds. But I digress; back to USB/IP. </p><p>I should test my Acer aspireM3's USB webcam before the install breaks things:</p><p># mplayer tv:// -tv driver=v4l2:width=640:height=480 -vo xv -tv device=/dev/video1</p><p>Let's verify that my Slackware kernel actuall has USB/IP:</p><div style="text-align: left;">root@aspireM3:~# ls -lR /usr/src/linux/ | grep -i usbip<br />-rw-r--r-- 1 root root 1172 Jan 26 2019 sysfs-platform-usbip-vudc<br />-rw-r--r-- 1 root root 23365 Jan 26 2019 usbip_protocol.txt<br /><div style="text-align: left;">drwxr-xr-x 2 root root 4096 Jan 26 2019 usbip/<br />/usr/src/linux/drivers/usb/usbip:<br />-rw-r--r-- 1 root root 18694 Jan 26 2019 usbip_common.c<br />-rw-r--r-- 1 root root 10117 Jan 26 2019 usbip_common.h<br />-rw-r--r-- 1 root root 3969 Jan 26 2019 usbip_event.c<br />drwxr-xr-x 3 root root 4096 Jan 27 2019 usbip/</div><div style="text-align: left;"><br /></div></div><div>Looks good. A look at the kernel's config file shows that the binary has not been left out at compile time:</div><div><br /></div><div><div>root@aspireM3:~# grep -i usbip /usr/src/linux/.config</div><div>CONFIG_USBIP_CORE=m</div><div>CONFIG_USBIP_VHCI_HCD=m</div><div>CONFIG_USBIP_VHCI_HC_PORTS=8</div><div>CONFIG_USBIP_VHCI_NR_HCS=1</div><div>CONFIG_USBIP_HOST=m</div><div># CONFIG_USBIP_DEBUG is not set</div></div><div><br /></div><div>And finally, locate the kernel modules (ie device drivers) themselves:</div><div><div># ls -l /lib/modules/4.19.18/kernel/drivers/usb/usbip</div><div>total 128</div><div>-rw-r--r-- 1 root root 22576 Jan 27 2019 usbip-core.ko</div><div>-rw-r--r-- 1 root root 42480 Jan 27 2019 usbip-host.ko</div><div>-rw-r--r-- 1 root root 58016 Jan 27 2019 vhci-hcd.ko</div></div><div><br /></div><div>And it runs OK:</div><div><div># modprobe -v usbip-core</div><div>insmod /lib/modules/4.19.18/kernel/drivers/usb/usbip/usbip-core.ko</div></div><div><br /></div><div>Let's launch the USB/IP server daemon:</div><div><div># usbipd -D</div><div>-su: usbipd: command not found</div></div><div><br /></div><div>Oops. The userspace binaries are not installed. Let's see if my Slackware installation has the userspace source code:</div><div><div># ls -l /usr/src/linux/tools/usb/usbip/src</div><div>total 96</div><div>-rw-r--r-- 1 root root 440 Jan 26 2019 Makefile.am</div><div>-rw-r--r-- 1 root root 4406 Jan 26 2019 usbip.c</div><div>-rw-r--r-- 1 root root 1292 Jan 26 2019 usbip.h</div><div>-rw-r--r-- 1 root root 5404 Jan 26 2019 usbip_attach.c</div><div>-rw-r--r-- 1 root root 5169 Jan 26 2019 usbip_bind.c</div><div>-rw-r--r-- 1 root root 2922 Jan 26 2019 usbip_detach.c</div><div>-rw-r--r-- 1 root root 9713 Jan 26 2019 usbip_list.c</div><div>-rw-r--r-- 1 root root 6179 Jan 26 2019 usbip_network.c</div><div>-rw-r--r-- 1 root root 5295 Jan 26 2019 usbip_network.h</div><div>-rw-r--r-- 1 root root 1536 Jan 26 2019 usbip_port.c</div><div>-rw-r--r-- 1 root root 3494 Jan 26 2019 usbip_unbind.c</div><div>-rw-r--r-- 1 root root 15083 Jan 26 2019 usbipd.c</div><div>-rw-r--r-- 1 root root 1630 Jan 26 2019 utils.c</div><div>-rw-r--r-- 1 root root 863 Jan 26 2019 utils.h</div></div><div><br /></div><div>Yes, I do. I just need to compile it but it fails:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip# ./autogen.sh</div></div><div>/usr/src/linux/tools/usb/usbip# ./configure</div><div><div>/usr/src/linux/tools/usb/usbip# make</div><div>make all-recursive</div><div>make[1]: Entering directory '/usr/src/linux-4.19.18/tools/usb/usbip'</div><div>Making all in libsrc</div><div>make[2]: Entering directory '/usr/src/linux-4.19.18/tools/usb/usbip/libsrc'</div><div> CC libusbip_la-usbip_device_driver.lo</div><div>usbip_device_driver.c: In function �..read_usb_vudc_device�..:</div><div>usbip_device_driver.c:106:2: error: �..strncpy�.. specified bound 256 equals destination size [Werror=stringop-truncation]</div><div> strncpy(dev->path, path, SYSFS_PATH_MAX);</div><div> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</div><div>usbip_device_driver.c:125:2: error: �..strncpy�.. specified bound 32 equals dest</div><div>ination size [-Werror=stringop-truncation]</div><div> strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE);</div><div> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</div><div>cc1: all warnings being treated as errors</div><div>make[2]: *** [Makefile:471: libusbip_la-usbip_device_driver.lo] Error 1</div><div>make[2]: Leaving directory '/usr/src/linux-4.19.18/tools/usb/usbip/libsrc'</div><div>make[1]: *** [Makefile:497: all-recursive] Error 1</div><div>make[1]: Leaving directory '/usr/src/linux-4.19.18/tools/usb/usbip'</div><div>make: *** [Makefile:365: all] Error 2</div></div><div><br /></div><div>It does not look serious. What used to be a compiler warning has now been classified as an error so the compiler obligingly stops. A quick google comes up with a patch:</div><div><br /></div><div><div>https://patchwork.kernel.org/project/linux-usb/patch/20180721021232.GR14131@deca</div><div>dent.org.uk/</div><div><br /></div><div>> +++ b/tools/usb/usbip/libsrc/usbip_common.c</div><div>> @@ -226,8 +226,8 @@ int read_usb_device(struct udev_device *</div><div>> path = udev_device_get_syspath(sdev);</div><div>> name = udev_device_get_sysname(sdev);</div><div>></div><div>> - strncpy(udev->path, path, SYSFS_PATH_MAX);</div><div>> - strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);</div><div>> + snprintf(udev->path, SYSFS_PATH_MAX, "%s", path);</div><div>> + snprintf(udev->busid, SYSFS_BUS_ID_SIZE, "%s", name);</div></div><div><br /></div><div>So I just edit usbip_device_driver.c:</div><div><div># vi libsrc/usbip_device_driver.c</div><div><br /></div><div> And at line 106</div><div> strncpy(dev->path, path, SYSFS_PATH_MAX);</div><div> Is changed to</div><div> // strncpy(dev->path, path, SYSFS_PATH_MAX); cmheong 2021-03-27</div><div> snprintf(dev->path, SYSFS_PATH_MAX, "%s", path);</div></div><div><br /></div><div>At line 125:</div><div><div>strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE);</div><div> Became</div><div>snprintf(dev->busid, SYSFS_BUS_ID_SIZE, "%s", name);</div></div><div><br /></div><div>Anow for the file usbip_common.c line 230:</div><div><div> // strncpy(udev->path, path, SYSFS_PATH_MAX); // cmheong 2021-03-27</div><div> // strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);</div><div><br /></div><div>Becomes</div><div> snprintf(udev->path, SYSFS_PATH_MAX, "%s", path);</div><div> snprintf(udev->busid, SYSFS_BUS_ID_SIZE, "%s", name);</div></div><div><br /></div><div><div>Now some Slackware versions, depending on the date of your install, you might get an additional error:</div><div><br /></div><div><div> CC usbip_network.o</div><div>usbip_network.c: In function âusbip_net_pack_usb_deviceâ:</div><div>usbip_network.c:91:32: error: taking address of packed member of âstruct usbip_</div><div>usb_deviceâ may result in an unaligned pointer value [-Werror=address-of-packed</div><div>-member]</div><div> 91 | usbip_net_pack_uint32_t(pack, &udev->busnum);</div><div> | ^~~~~~~~~~~~~</div></div><div><br /></div><div>We just need to tell the compiler not to freak out and treat the warning as an error. This can be done by changing line 12174 of the 'configure' file:</div><div><div><br /></div><div>/usr/src/linux/tools/usb/usbip$vi configure</div></div><div><br /></div><div><div>EXTRA_CFLAGS="-Wall -Wno-error=address-of-packed-member -Werror -Wextra -std=gnu</div><div>99"</div></div><div><br /></div></div><div>After which the compile completes successfully:</div><div><div># make</div><div>make all-recursive</div><div>make[1]: Entering directory '/usr/src/linux-4.19.18/tools/usb/usbip'</div><div>Making all in libsrc</div><div>make[2]: Entering directory '/usr/src/linux-4.19.18/tools/usb/usbip/libsrc'</div><div> CC libusbip_la-usbip_common.lo</div><div> CC libusbip_la-usbip_host_common.lo</div><div> CC libusbip_la-vhci_driver.lo</div><div> CC libusbip_la-sysfs_utils.lo</div><div> CCLD libusbip.la</div><div>make[2]: Leaving directory '/usr/src/linux-4.19.18/tools/usb/usbip/libsrc'</div><div>Making all in src</div><div>make[2]: Entering directory '/usr/src/linux-4.19.18/tools/usb/usbip/src'</div><div> CC usbip.o</div><div> CC utils.o</div><div> CC usbip_network.o</div><div> CC usbip_attach.o</div><div> CC usbip_detach.o</div><div> CC usbip_list.o</div><div> CC usbip_bind.o</div><div> CC usbip_unbind.o</div><div> CC usbip_port.o</div><div> CCLD usbip</div><div> CC usbipd.o</div><div> CCLD usbipd</div><div>make[2]: Leaving directory '/usr/src/linux-4.19.18/tools/usb/usbip/src'</div><div>make[2]: Entering directory '/usr/src/linux-4.19.18/tools/usb/usbip'</div><div>make[2]: Leaving directory '/usr/src/linux-4.19.18/tools/usb/usbip'</div><div>make[1]: Leaving directory '/usr/src/linux-4.19.18/tools/usb/usbip'</div></div><div><br /></div><div>Now the server daemon runs:</div><div><div># /usr/src/linux/tools/usb/usbip/src/usbipd -D</div></div><div><br /></div><div>A quick check:</div><div><div>/usr/src/linux/tools/usb/usbip# ps -ef | grep -e usbip</div><div>root 23597 2 0 14:57 ? 00:00:00 [usbip_event]</div><div>root 23608 1 0 19:53 ? 00:00:00 /usr/src/linux/tools/usb/usbip/src/.libs/lt-usbipd -D</div><div>root 23835 1533 0 19:54 pts/0 00:00:00 grep -e usbip</div></div><div><br /></div><div>Next we list the USB devices available to the server:</div><div><div>/usr/src/linux/tools/usb/usbip# /usr/src/linux/tools/usb/usbip/src/usbip list --local</div><div> - busid 1-3.1 (0835:8501)</div><div> Action Star Enterprise Co., Ltd : unknown product (0835:8501)</div><div><br /></div><div> - busid 1-3.2 (046d:c077)</div><div> Logitech, Inc. : M105 Optical Mouse (046d:c077)</div><div><br /></div><div> - busid 1-3.3 (13ba:0017)</div><div> PCPlay : PS/2 Keyboard+Mouse Adapter (13ba:0017)</div><div><br /></div><div> - busid 1-3.4 (10c4:ea60)</div><div> Cygnal Integrated Products, Inc. : CP2102/CP2109 UART Bridge Controller [CP21</div><div>0x family] (10c4:ea60)</div><div><br /></div><div> - busid 1-3.5.1 (0835:8502)</div><div> Action Star Enterprise Co., Ltd : unknown product (0835:8502)</div><div><br /></div><div> - busid 1-3.5.2 (046d:0829)</div><div> Logitech, Inc. : unknown product (046d:0829)</div><div><br /></div><div> - busid 1-3.5.4 (0c45:62f1)</div><div> Microdia : unknown product (0c45:62f1)</div><div><br /></div><div> - busid 2-1.3 (04f2:b300)</div><div> Chicony Electronics Co., Ltd : unknown product (04f2:b300)</div><div><br /></div><div> - busid 2-1.4 (04ca:3006)</div><div> Lite-On Technology Corp. : unknown product (04ca:3006)</div></div><div><br /></div><div>Using the displayed busis, we use 'lsusb -v' to zero in on the webcam:</div><div><div><br /></div><div>Bus 002 Device 003: ID 04f2:b300 Chicony Electronics Co., Ltd</div><div> iManufacturer 1 Chicony Electronics Co., Ltd.</div><div> iProduct 2 HD WebCam</div><div> iSerial 3 SN0001</div><div> - busid 2-1.3 (04f2:b300)</div><div><br /></div></div><div>Now I need to launch another kernel module:</div><div><br /></div><div><div># modprobe -v usbip-host</div><div>insmod /lib/modules/4.19.18/kernel/drivers/usb/usbip/usbip-host.ko</div></div><div><br /></div><div>We now have the USB/IP server grab the webcam:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip# /usr/src/linux/tools/usb/usbip/src/usbip bind --busid=2-1.3</div><div>usbip: info: bind device on busid 2-1.3: complete</div></div><div><br /></div><div>Now we move over to the other (ie client) computer, and repeat the process of installing USB/IP. We then launch the USB/IP kernel client modules:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip$modprobe -v vhci-hcd</div><div>insmod /lib/modules/4.19.62/kernel/drivers/usb/usbip/usbip-core.ko</div><div>insmod /lib/modules/4.19.62/kernel/drivers/usb/usbip/vhci-hcd.ko</div></div><div><br /></div><div>Let's say the server's IP address is 12.34.56.78. We can see what USB device on the server is available over IP:</div><div><br /></div><div>/usr/src/linux/tools/usb/usbip$src/usbip list --remote=12.34.56.78</div><div>Exportable USB devices</div><div>======================</div><div> - 12.34.56.78</div><div> 2-1.3: Chicony Electronics Co., Ltd : unknown product (04f2:b300)</div><div> : /sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1/2-1.3</div><div> : Miscellaneous Device / ? / Interface Association (ef/02/01). </div><div> </div><div>Ah it is a webcam ;7) We attach to it:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip# /usr/src/linux/tools/usb/usbip/src/usbip attach -debug --remote=12.34.56.78 --busid=2-1.3</div></div><div><br /></div><div>And we play the remote (ie server) webcam by using mplayer:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip$ mplayer -cache 128 -tv device=/dev/video2:driver=v4l2:width=640:height=480:outfmt=i420 -vo xv tv://</div></div><div><br /></div><div>Note that here I access /dev/video2, since my client laptop also has a webcam at /dev/video1, and the USB/IP attach made a new one at /dev/video2. Also the server webcam resolution is 1080 x 720 but that seemed to mave maxed out my old 100Mbps fiber link. Dropping the resolution down to 640 x 480 worked out well.</div><div><br /></div><div>You can see your attached USB device using:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip$src/usbip port --remote=12.34.56.78</div><div>Imported USB devices</div><div>====================</div><div>Port 00: <Port in Use> at High Speed(480Mbps)</div><div> Chicony Electronics Co., Ltd : unknown product (04f2:b300)</div><div> 3-1 -> usbip://192.168.1.4:3240/3-1.3</div><div> -> remote bus/dev 003/003</div></div><div><br /></div><div>Notice the port number 00. We will be needing it. Lastly once you are through with the webcam you release it so another computer can use it:</div><div><br /></div><div><div>/usr/src/linux/tools/usb/usbip$src/usbip detach --port=00</div><div>usbip: info: Port 0 is now detached!</div></div><div><br /></div><div>There you have it. USB/IP comes standard with Linux, and lets you access USB devices remotely. I had great fun spending an afternoon doing this to the <a href="https://www.youtube.com/watch?v=sKjvfiF1_9I&list=PLTwAHaEBSqOZwI674CcP2HD2slre3s1PO&index=1&ab_channel=LesiniBluesDimitrisGreece">boogie blues</a>. Here's a video of Daisy tapping her feet to it:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://www.youtube.com/watch?v=34_XulMe03w&ab_channel=heongcm"><img border="0" data-original-height="507" data-original-width="700" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKgC6Mk6iuRNIN659iW1H5_DMIru7Yv_3osROTrL1nl1XjxMjA0Spn4RZDFjgIxj4b0tH34nmHHthPa3mXdUUI5zhjpDuF6xNwyfUIVjFGxplZlFpkU6KzNI0twMa0NroK7GDE2YdUOtJJ/s320/Daisy_BoogieBlues.jpg" width="320" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.youtube.com/watch?v=34_XulMe03w&ab_channel=heongcm">Click on picture for the video</a></td></tr></tbody></table><br /><div><br /></div><div>Happy Trails.</div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-29039986752533087452021-03-10T01:49:00.003-08:002021-03-12T23:42:44.544-08:00Turning laptop into a keyboard: USB CDC Serial port to USB HID Keyboard Emulator<p> Why on earth would I want to turn my laptop into a keyboard & monitor for another computer? It is easier to buy a usb keyboard and mobile monitor. Indeed <a href="https://cmheong.blogspot.com/2018/02/maintaining-headless-linux-embedded.html">I did exactly that</a>. Years of dutifully humping keyboard, monitor, laptop and toolbox makes you dream of lightening the load. After all, the laptop already has a keyboard and screen; why carry more?</p><p>Most of the time <a href="https://cmheong.blogspot.com/2017/08/3g-mifi-modem-car-wifi-router-and.html">I log into the onsite computers remotely</a> via ssh (Teamviewer for Windows), but sometimes you need to debug the POST process or change the BIOS settings, before your OS is running.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXMdWwGBMj2akryD1dkLU5azleN7A8VaNMDqhaonIBEufGis5rJSaMAXRETaIn2TnQamEIW-zWh0I3ogQvtWmofiEdBsQBuhlEsAW4YxF35h71OlG07KbjQ-1mhyr3k9qJU2gYeReR5LdS/s1464/USBkeyboard_emulator.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="456" data-original-width="1464" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXMdWwGBMj2akryD1dkLU5azleN7A8VaNMDqhaonIBEufGis5rJSaMAXRETaIn2TnQamEIW-zWh0I3ogQvtWmofiEdBsQBuhlEsAW4YxF35h71OlG07KbjQ-1mhyr3k9qJU2gYeReR5LdS/w545-h170/USBkeyboard_emulator.jpg" width="545" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Serial to USB HID Keyboard Emulator</td></tr></tbody></table><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p>My solution is to use a USB framegrabber for the monitor and a USB keyboard emulator. </p><p><br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><span style="margin-left: auto; margin-right: auto;"><a href="https://www.youtube.com/watch?v=jUqGSsHYgzE"><img border="0" data-original-height="676" data-original-width="1060" height="255" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkDuQHM-i20Q-hfo2v0Tv9wKNDWedgM-XvdoncNEVLArK10Meljwn8m9AUgw-Wcw8IPbkVIIB9b-xGnq8CvjVMccR9sREnOwKFUiNDXX8DOkvtUJ-Z2GWG1BIedZKI8hni_Ed5H_rrbqlu/w400-h255/youtube.jpg" width="400" /></a></span></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.youtube.com/watch?v=jUqGSsHYgzE">Watch video demo on youtube</a></td></tr></tbody></table><p><br /></p><p>You can of course buy a UART to USB Keyboard Converter like <a href="http://www.intelletto.com/products?id=3001">Inteletto</a>'s. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjahqm1MzCOvFV2ZouH8sFczUXkKkmvvtErKQ_iijFwX7kTwf1GPeW0o2Zz-ftP3zVHes8evM9VvzWHsSwwklnPo-lTon8SeTw68gIl8KaNIl-CpD6y6yugte-YFZwUMJsaDboQffjNRmX4/s162/Interletto_hid_keyboard_cable_small.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="130" data-original-width="162" height="321" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjahqm1MzCOvFV2ZouH8sFczUXkKkmvvtErKQ_iijFwX7kTwf1GPeW0o2Zz-ftP3zVHes8evM9VvzWHsSwwklnPo-lTon8SeTw68gIl8KaNIl-CpD6y6yugte-YFZwUMJsaDboQffjNRmX4/w400-h321/Interletto_hid_keyboard_cable_small.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Interletto RS232 to USB Keyboard cable</td></tr></tbody></table><p><br /></p><p>You can even build a superior one using the <a href="https://learn.adafruit.com/introducing-bluefruit-ez-key-diy-bluetooth-hid-keyboard/sending-keys-via-serial">Bluefruit EZ-Key</a>. But the Inteletto costs USD99 and the EZ-Key (USD20) is discontinued. and I already have the parts to build my own.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyKr0jhQDypxtn1ZdDdn7QBeGEHR0jWpedJzaoGDSHlNiYcxhcPZde7TcZDCYRh7a54qKuuNaD1ypPL5STkYGUM7wd6qo3dczjMyqFeP9KPWuxzjwmNCM9uLt4fNmRigf4_Mu3gmgyr-Wi/s970/Bluefruit_EZkey.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="728" data-original-width="970" height="449" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyKr0jhQDypxtn1ZdDdn7QBeGEHR0jWpedJzaoGDSHlNiYcxhcPZde7TcZDCYRh7a54qKuuNaD1ypPL5STkYGUM7wd6qo3dczjMyqFeP9KPWuxzjwmNCM9uLt4fNmRigf4_Mu3gmgyr-Wi/w599-h449/Bluefruit_EZkey.jpg" width="599" /></a></div><br /><p><br /></p><p>Enter the <a href="https://www.microchip.com/wwwproducts/en/PIC18F14K50">Microchip PIC18F14K50</a>. More importantly the <a href="https://github.com/mentatpsi/Microchip/tree/master/USB">free USB source code in MPLAB</a>. I used my own miniaturized, code-compatible version of the <a href="https://www.microchip.com/Developmenttools/ProductDetails/DM164127">Microchip Low Pin Count Development Kit</a>. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3lT8wKDx_HVlirXFqgzdoYBV6gKyyUhXIuEN9KaAXwuuXx0t48b5cgcD66p8eF5Rth3Xn6irQRQv2uOsnLEwyyx6_MgGKGRK6nOKHNguaExOO-LBQCEX8UALXAc3VQmS6R6AHMBxKT9G4/s508/LowPinCountDevKit.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="420" data-original-width="508" height="445" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3lT8wKDx_HVlirXFqgzdoYBV6gKyyUhXIuEN9KaAXwuuXx0t48b5cgcD66p8eF5Rth3Xn6irQRQv2uOsnLEwyyx6_MgGKGRK6nOKHNguaExOO-LBQCEX8UALXAc3VQmS6R6AHMBxKT9G4/w537-h445/LowPinCountDevKit.jpg" width="537" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Microchip PIC18F14K50 Low Pin Count Development Board</td></tr></tbody></table><br /><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiHCKc8CPmQmxZ6-OhB0Dvl2V2kBy5Pwvyqo3FbdbM4fLlSNWOosatIUvhLQJIN3OI_VpSRydguWi9TBc7q5HQtI8nOrj8AQKDnAjySCWjfqPJNj0QArwHq4n7vuC-hcMMYU86hZcKeCik/s2125/rs485_pic.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="621" data-original-width="2125" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiHCKc8CPmQmxZ6-OhB0Dvl2V2kBy5Pwvyqo3FbdbM4fLlSNWOosatIUvhLQJIN3OI_VpSRydguWi9TBc7q5HQtI8nOrj8AQKDnAjySCWjfqPJNj0QArwHq4n7vuC-hcMMYU86hZcKeCik/w448-h132/rs485_pic.jpg" width="448" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Miniaturized PIC18F14K50 Low Pin Count Development Board </td></tr></tbody></table><p><br />The <a href="http://ww1.microchip.com/downloads/en/devicedoc/40001356c.pdf">schematics is in the User Guide</a>. Unlike the Bad Old Days there is even a <a href="https://www.microchip.com/en-us/development-tools-tools-and-software/mplab-x-ide#tabs">Linux version of MPLAB</a> now. My programmer is a <a href="https://en.wikipedia.org/wiki/PICkit">PICkit 2</a>.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMHQBkaKOeKHyyIWPb98CkDVtuY833ZeUFVAk9faiEuE6mQKdNtilEzW5Z2_msFDg5DfxP9BsORvu2iywc7hi61rwx0vMxNDvNbACdRlP1xRz7RFe5igIS8s6Wyanuh7Cm-W25-UjxSXbz/s662/LowPinCountDevKit1_schematics.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="662" data-original-width="504" height="760" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMHQBkaKOeKHyyIWPb98CkDVtuY833ZeUFVAk9faiEuE6mQKdNtilEzW5Z2_msFDg5DfxP9BsORvu2iywc7hi61rwx0vMxNDvNbACdRlP1xRz7RFe5igIS8s6Wyanuh7Cm-W25-UjxSXbz/w579-h760/LowPinCountDevKit1_schematics.jpg" width="579" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Low Pin Count Development Board schematics</td></tr></tbody></table><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzvFLsbIyi578K_FChfDtA3i77afWBXQRVR5SABmE3aXiWfPtx9G2cFR6vQWmnpDXHO0d_Jg5HRSb8nigqd2CszydEnxRYXx5NoV5DKAZP__EhL3D5FEVBJIeu9QFSbHUjAS9v5lv3EXVx/s1024/PICkit2.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="797" data-original-width="1024" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzvFLsbIyi578K_FChfDtA3i77afWBXQRVR5SABmE3aXiWfPtx9G2cFR6vQWmnpDXHO0d_Jg5HRSb8nigqd2CszydEnxRYXx5NoV5DKAZP__EhL3D5FEVBJIeu9QFSbHUjAS9v5lv3EXVx/w572-h444/PICkit2.jpg" width="572" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">PICKit 2 Programmer (bottom)</td></tr></tbody></table><br /><p><br /></p><p>The idea is to use <b>two</b> Low Pin Count Development boards connected back-to-back via Serial TTL or RS485; one programmed as <a href="https://en.wikipedia.org/wiki/USB_communications_device_class">USB CDC</a> Serial Port and the other as <a href="https://en.wikipedia.org/wiki/USB_human_interface_device_class">USB HID</a> Keyboard.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ628_anUsh21LClFBr11HI-PiqszdvqFk5AOorZJAO1_DFrGED2tbpEwGXp4fghyHB7BcRkZGUK3BxLbJ3tWycP7sEi728XDqRmrIWjCTomWgcc8twST38vpz2VtwQL-Q5DcWai2TBhpR/s2048/20180201_201308.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="964" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ628_anUsh21LClFBr11HI-PiqszdvqFk5AOorZJAO1_DFrGED2tbpEwGXp4fghyHB7BcRkZGUK3BxLbJ3tWycP7sEi728XDqRmrIWjCTomWgcc8twST38vpz2VtwQL-Q5DcWai2TBhpR/w542-h964/20180201_201308.jpg" width="542" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Two PIC18F14K50 boards back-to-back connected via 2-wire RS-485</td></tr></tbody></table><br /><p>You plug the serial port into your development system (ie main computer) and in a Linux system it comes up as /dev/ttyACM0. For Windows user, there is a device driver in the MPLAB library. You point <a href="https://www.cyberciti.biz/tips/connect-soekris-single-board-computer-using-minicom.html">minicom</a> to /dev/ttyACM0, set the baudrate to 19200 1-stop no parity with no hardware flow control. You plug the USB 'Keyboard' into the target computer. Keys typed into minicom appears at the other end, the USB Keyboard.</p><p>Now this sounds expensive but a stripped-down and miniaturized PCB for is quite cheap to make, even in small quantities, and the PIC138F14K50 (SOIC-20 package) is only RM11 (USD2.76) at <a href="https://www.digikey.com/en/products/detail/microchip-technology/PIC18F14K50T-I-SO/2002543">Digikey</a>. You can also use any standard USB serial dongle, like the CH340. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUcUSW5F0ONWQTY3ljoCHVNix1eqnfMFQPq_TNPjlDdZZyNKbG_HO6V8Kq38bb7TJMp3ZUIKAWZczB2MRGQt9icuG2J7ZuvCIyr8vAkuOddMqkTh0Cj7e4nQKeZI1raMgsdkd-yVvLvW4z/s600/ch340_usb_to_ttl_converter.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="600" data-original-width="600" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUcUSW5F0ONWQTY3ljoCHVNix1eqnfMFQPq_TNPjlDdZZyNKbG_HO6V8Kq38bb7TJMp3ZUIKAWZczB2MRGQt9icuG2J7ZuvCIyr8vAkuOddMqkTh0Cj7e4nQKeZI1raMgsdkd-yVvLvW4z/w400-h400/ch340_usb_to_ttl_converter.jpg" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">CH340 USB Serial TTL Dongle</td></tr></tbody></table><p><br />I settled on the venerable <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> as the serial protocol. It is easy to debug. This means minicom sends ASCII to the keyboard UART and this then needs to be translated to the corresponding USB Keyboard scancode. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNsr8LREXEEVAtIUdusn8ZpqmstIH_IrY4WSOmxSrHoCMo7fl-JKtI1UUOrXS_VhyphenhyphenzQYZmm69OvCJtQ0taFZ_VNlp26OW1ByoNI5u-KAsDKhhwumtfbrJXRup9rlhrRv3vyXUmvMD97B2N/s715/asciifull.gif" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="488" data-original-width="715" height="412" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNsr8LREXEEVAtIUdusn8ZpqmstIH_IrY4WSOmxSrHoCMo7fl-JKtI1UUOrXS_VhyphenhyphenzQYZmm69OvCJtQ0taFZ_VNlp26OW1ByoNI5u-KAsDKhhwumtfbrJXRup9rlhrRv3vyXUmvMD97B2N/w605-h412/asciifull.gif" width="605" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Full ASCII table</td></tr></tbody></table><p>You can get the USB HID Keyboard whole nine yards from <a href="https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf">usb.org</a>, but I used a handy summary from <a href="https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2">MightyPork</a>. </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRdiVjui8Ku8hAeysvHmURvuTZthD3ZBfAJOyP_89FSpOK95zoyJfrEOuJZVVkmExw06F-tGeU0N-VqcIEq4wCV_Fr9IEt81dD9WB7lJQP43aX_cTYefp14WAqxFhMALp0mKFPbgCVLbqH/s727/USB_keyboard_scancodes.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="727" data-original-width="453" height="828" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRdiVjui8Ku8hAeysvHmURvuTZthD3ZBfAJOyP_89FSpOK95zoyJfrEOuJZVVkmExw06F-tGeU0N-VqcIEq4wCV_Fr9IEt81dD9WB7lJQP43aX_cTYefp14WAqxFhMALp0mKFPbgCVLbqH/w515-h828/USB_keyboard_scancodes.jpg" width="515" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">A small part of USB Keyboard scancodes</td></tr></tbody></table><br /><p>For example, ASCII code for 'A' is (hexadecimal) 0x41 and this is translated to 0x04. The software is a slightly modified version of Microchip's source code from the Low Pin Count Development Kit. A similar (but not identical) version is <a href="https://github.com/mentatpsi/Microchip/blob/master/USB/Device%20-%20HID%20-%20Keyboard/Firmware/Keyboard.c">Microchip/USB/Device - HID - Keyboard/Firmware/Keyboard.c</a></p><p>You can download the file from <a href="https://github.com/cmheong/serial2USBkeyboard">my github repository</a>. Notice my code uses a MAX323 RS485 to TTL converter IC, but this should be compatible with the schematic above. Minicom actually does not have enough keys to emulate a full-sized USB keyboard, so what you have here is a minimum subset of keystrokes needed to sucessfully change a BIOS. For example, the CapsLock key is emulated as 'Ctrl-N'. Other notable mappings:</p><p></p>CapsLock - Ctrl N<br />Ctrl-Alt-Del - Ctrl O<br />F1 - Ctrl Q<br />F2 - Ctrl R<br />F5 - Ctrl S<br />F6 - Ctrl T<br />F9 - Ctrl U<br />F10 - Ctrl V<br />Left Arrow - Ctrl W<br />Down Arrow - Ctrl X<br />Right Arrow - Ctrl Y<br />Up Arrow - Ctrl Z<br /><div><br /></div><div>If you do not have access to MPLAB there is a <a href="https://github.com/cmheong/serial2USBkeyboard/blob/main/keyboard.hex">binary file keyboard.hex</a> compatible with the PICKit 2.</div><div><br /></div><div>To compile, I ran MPLAB from a qemu-kvm Virtual Machine running Windows XP. Using <a href="https://www.putty.org/">puTTY</a> I sshfs into the MPLAB working directory to extract the binary file for programming.</div><div> </div><div><div>$ sshfs -o reconnect -C user@12.34.56.78:c:/Program\ Files/ICW/home/user/keyboard/USB\ Device\ -\ HID\ -\ Keyboard/Firmware $HOME/pic18f14k50/keyboard/source</div></div><div><br /></div><div>$ cp source/*.hex .</div><div><br /></div><div>I use <a href="https://github.com/psmay/pk2cmd">pk2cmd</a> to program my PICkit 2:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1dHlBXAewPvPvqVp9n9hjRd23NcjmboWu_a9IRrvIQb2vGhJ8possYGt2AEjmGtwpOecwjRHaNHj5zn5-EQkt8pi4QqmRbnjDZAbW0HtXZKjUxa3EMQDcEnRoPImmEdUYhm9BjDz_xhBP/s2817/rs485_pic_pickit2.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2817" data-original-width="1057" height="957" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1dHlBXAewPvPvqVp9n9hjRd23NcjmboWu_a9IRrvIQb2vGhJ8possYGt2AEjmGtwpOecwjRHaNHj5zn5-EQkt8pi4QqmRbnjDZAbW0HtXZKjUxa3EMQDcEnRoPImmEdUYhm9BjDz_xhBP/w359-h957/rs485_pic_pickit2.jpg" width="359" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">PICkit 2 mounted on JTAG programming port</td></tr></tbody></table><div><br /></div><div><br /></div><div><div>$./pk2cmd -PPIC18F14K50 -Fkeyboard.hex -M </div><div>PICkit 2 Program Report</div><div>7-3-2021, 14:57:12</div><div>Device Type: PIC18F14K50</div><div><br /></div><div>Program Succeeded.</div><div><br /></div><div>Operation Succeeded</div></div><div><br /></div><div>There you have it- USB CDC Serial to USB HID Keyboard simulator. Happy Trails.</div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-89996692672837329132021-02-22T23:59:00.004-08:002021-06-29T01:55:58.128-07:00Hacking Trendnet TV-IP422WN IP Camera to use with Linux program<p>There are many good IP Cameras now, and I can replace them at very reasonable prices, but my 11 year old Trendnet TV-IP422WN cameras just keep running. Which surprised me considering I mounted them outdoors and the resident zebra doves use them as a convenient potty/perch.</p><p> <br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNaXNjleTI8gqdNLXfN9sa4tuzmYdkKZWlBjfsh6V06ULzKSQSt9zwpT29T5REFqM7Jl-opg2qf3cL3Uyh5U34N0AIVrHfC9GzVhA0QautFiDrqQ2r5qomnlJKy1XHg6UBWuUB1uTH2cPh/s400/TV-IP422WN.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="400" data-original-width="400" height="414" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNaXNjleTI8gqdNLXfN9sa4tuzmYdkKZWlBjfsh6V06ULzKSQSt9zwpT29T5REFqM7Jl-opg2qf3cL3Uyh5U34N0AIVrHfC9GzVhA0QautFiDrqQ2r5qomnlJKy1XHg6UBWuUB1uTH2cPh/w414-h414/TV-IP422WN.jpg" width="414" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Trendnet TV-IP422WN IP Camera</td></tr></tbody></table><br /><p></p><p>Resolution is only 640x480, and worse, the webpage uses ActiveX. But if I can use it from Linux then I can make my own webpage. And even consolidate several of them into one page, just like those CCTV screens.</p><p>Or perhaps a passive infrared sensor can be used to trigger a spotlight and cause the camera to capture a short video. All via <a href="https://cmheong.blogspot.com/2019/11/lightning-detector-as3935-adding-serial.html">MQTT</a>. I found this really useful as it reduces the time required to view alarm footage.</p><p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHym4dq1AEm1M1JAtvYRqnjxdpvqW_KMVslBKIMKSeccgXu8jvOW59gZ6xIetRX7DT5_rvSgA_-uKyETQBC-oRJFUwPoS9pv7Gw5CUt-quWQjzhZ7W_hV6AOrthNeMm2eqFgjtZoqc6QIl/s714/activex.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="661" data-original-width="714" height="458" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHym4dq1AEm1M1JAtvYRqnjxdpvqW_KMVslBKIMKSeccgXu8jvOW59gZ6xIetRX7DT5_rvSgA_-uKyETQBC-oRJFUwPoS9pv7Gw5CUt-quWQjzhZ7W_hV6AOrthNeMm2eqFgjtZoqc6QIl/w495-h458/activex.jpg" width="495" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Webpage viewed with Microsoft Internet Explorer: the live video display needs ActiveX</td></tr></tbody></table><br /><p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMDFoKHHfwHUBp4LX-7dtFMT1aY7GDCfVKZvtqux5GBO72P8qhVyT4tOBc22NRMWSZkIaiqz6ncTptlx2KquuPTj8m81awVEUu4dGVtlyqN3qgWLq6Dg0TaBLdTknGXkAMyENzWmChSFDC/s917/chrome.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="719" data-original-width="917" height="389" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMDFoKHHfwHUBp4LX-7dtFMT1aY7GDCfVKZvtqux5GBO72P8qhVyT4tOBc22NRMWSZkIaiqz6ncTptlx2KquuPTj8m81awVEUu4dGVtlyqN3qgWLq6Dg0TaBLdTknGXkAMyENzWmChSFDC/w496-h389/chrome.jpg" width="496" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">TV-IP422WN webpage using Google Chrome</td></tr></tbody></table><br /><p>Getting it to work in Linux bash turned out to be surprisingly easy. From <a href="https://wiki.zoneminder.com/Trendnet#TV-IP422">zoneminder</a>, type this into your browser (I used Chrome):</p><p>http://192.168.10.30/cgi/mjpg/mjpg.cgi</p><p>Note if you did a factory reset the default IP address is 192.168.10.30 user is admin and password is admin. You will need to change all three for security reasons.</p><p>From Linux bash I used:</p><p>$curl -m 5 -u admin:admin -o cctv_video.mpg -k http://192.168.10.30/cgi/mjpg/mjpg.cgi</p><p>Now this gives me an output file which I can view with mplayer. The '-m 5' option is used to record a 5-second video; otherwise the curl command will never exit. This is especially useful if you trigger recording with another sensor, maybe a passive infrared sensor.</p><p>If, instead of video record, you just want a live view,</p><p>$mplayer -fps 20 -demuxer lavf -user admin -passwd admin http://192.168.10.30/cgi/mjpg/mjpg.cgi</p><p>If you want a still snapshot, you aim your browser at:</p><p>http://192.168.10.30/cgi/jpg/image.cgi</p><p>Or from bash, you can use lynx:</p><p>$lynx -dump -auth=admin:admin http://192.168.10.30/cgi/jpg/image.cgi > image.jpg</p><p>Usually, you will need different video settings for night and day. I could not find the settings I need on the Internet, but I got lucky: if I used the 'Debug' (ie F12) feature in Google Chrome, under the menu 'Network' with filter 'All', I was able to discern the url:</p><p>http://192.168.10.30/cgi/setup.cgi?page=camera</p><p>The data is in a Form posted as:</p><p>brightness=8&contrast=32&saturation=36&flicker=0&osd_enable=1</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimBnSfFmHnb0HWMYcFtoUGFpYdHx6FmDsKhVia0O-z9vYkslRLYhtMZktxLG4JYAgY_7An3IhCCINOxmRW1O_j7H7s2k6zRjNGstKOvC0qvz4JPVnXmheq4XLGtPEXrO5LAhXK1sxE76BC/s1256/settings_debug.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="648" data-original-width="1256" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimBnSfFmHnb0HWMYcFtoUGFpYdHx6FmDsKhVia0O-z9vYkslRLYhtMZktxLG4JYAgY_7An3IhCCINOxmRW1O_j7H7s2k6zRjNGstKOvC0qvz4JPVnXmheq4XLGtPEXrO5LAhXK1sxE76BC/w565-h291/settings_debug.jpg" width="565" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Google Chrome Debug mode for Video Settings page</td></tr></tbody></table><br /><p>My curl command for day then becomes:</p><p>$curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -u admin:admin -d "brightness=8&contrast=32&saturation=36&flicker=0&osd_enable=1" http://192.168.10.30/admin/camera.cgi</p><p>And for night:</p><p>$curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -u admin:admin -d "brightness=100&contrast=80&saturation=64&flicker=0&osd_enable=1" http://192.168.10.30/admin/camera.cgi</p><p>There is also a 'Night Mode' radio button which in bash is replicated as:</p><p>curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?night=1</p><p>Conversely 'Day' Mode is:</p><p>curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?night=0</p><p>Using the same method, the pan commands are:</p><p>$curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?move=left</p><div><p>$curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?move=right</p><div>Tilt commands are:</div></div><div><p>$curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?move=up</p><div><p>$curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?move=down</p><div>To center the camera:</div><div><p>$curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?move=h</p></div><div>If you want to set a particular camera angle at for example position 1 and name it 'Left':</div></div></div><div><br /></div><div>http://192.168.10.30/admin/ptctl.cgi?position=0&positionname=Left</div><div><br /></div><div>Note the position '1' is numbered as '0'. Again the data is uploaded as a Form:</div><div><br /></div><div>$curl -u admin:admin -H "Content-Type: application/x-www-form-urlencoded" -d "position=0&positionname=Left" -k http://192.168.10.30/admin/ptctl.cgi</div><div><br /></div><div>Thereafter to return to your preset position at '1' you need to</div><div><br /></div><div><div>$curl --connect-timeout 2 -u admin:admin -k http://192.168.10.30/admin/ptctl.cgi?move=p0</div></div><div><br /></div><div>To get audio, go to Menu 'Video/Audio' then 'Video' and select '3GPP with Audio'. You can get the audio (and video) using:</div><div><br /></div><div><div>mplayer rtsp://192.168.10.30/mpeg4</div></div><div><br /></div><div>There you have it, Trendnet TV-IP422WN hacked. Happy Trails.</div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-54014528704320759822021-01-17T01:33:00.007-08:002021-01-17T01:39:53.692-08:00One rail to rule them all: Powering the NodeMCU ESP-12E with 12V<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKZwHt4woK4q7ZJTX8KDxSqGZN_SEN2HqCpVO1zlMaXih2rrXWsGX1o2yuztf0YcLOdyvQWvIjFQ7bXGdvFvQKQjxkl7YIAqY7JVjb9veP1RJD-3jsmtqQ8atn0Z_tZbY1KxQcLzyoSjN4/s2048/assembled2.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1152" height="909" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKZwHt4woK4q7ZJTX8KDxSqGZN_SEN2HqCpVO1zlMaXih2rrXWsGX1o2yuztf0YcLOdyvQWvIjFQ7bXGdvFvQKQjxkl7YIAqY7JVjb9veP1RJD-3jsmtqQ8atn0Z_tZbY1KxQcLzyoSjN4/w511-h909/assembled2.jpg" width="511" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">NodeMCU Motor Shield with ESP-12E Devkit and 6.8V 1W Zener diode</td></tr></tbody></table><br /><p></p><p>Sometimes it makes sense to use a single power rail, like when I was making an IoT dimmable LED lamp using the NodeMCU ESP-12E Devkit. The strip of LEDs required 12V and I was loath to use a 5V buck converter: it would just be another item to mount. So, can I run the NodeMCU Devkit on 12V?</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkqGEeGVUwktogh1aygw49jDG6OEDq-1SaSS6_3rlmKo31gVVMgNLksQa0bogg1vFGXPiUQW2YfjtkO1GuUd86Y1CMC9QPL2QyyAX5Nn0_eguKVF8yUmkSIVkBzaUq5eGGM1JSVyTAua2x/s616/NodeMCU_Devkit.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="519" data-original-width="616" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkqGEeGVUwktogh1aygw49jDG6OEDq-1SaSS6_3rlmKo31gVVMgNLksQa0bogg1vFGXPiUQW2YfjtkO1GuUd86Y1CMC9QPL2QyyAX5Nn0_eguKVF8yUmkSIVkBzaUq5eGGM1JSVyTAua2x/w569-h480/NodeMCU_Devkit.png" width="569" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">NodeMCU ESP-12E Devkit. Note input power pin Vin at bottom left. Note this PCB version does <b>not</b> bring VUSB to the pins<br /></td></tr></tbody></table><p><br /></p><p>The answer is yes. And not really. Let me explain. You can power it from the input power pins Vin and GND. Or you can use USB port. Or both even of them at once. At a pinch you can even power it from the 3.3V pin. Powering it with 12V at Vin will work, but the AMS1117-3.3 LDO regulator will heat up badly under normal operation. It might even do a thermal shutdown and cause the ESP8266 to reset.</p><p>Powering from the micro USB port is easiest. You attach a smartphone charger cable to it; there is no wiring to do and you can even use it to program the Devkit. The USB port supplies 5V, and the power rail is usually called VUSB.</p><p>The NodeMCU Devkit is usually sold as a 5V device. A quick look at the board shows an AMS1117-3.3 Low Drop-Out linear regulator is connected to Vin. It produces the 3.3V needed by the ESP-12E module. But the AMS1117 datasheet specifies a maximum input voltage of 18V:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM4e9UIjEthsgult4QwCuEuCuI1qzs2mdJCFqn-Qds5WrvGiw_XtJBGXWi3V816pbCweb5iiMy1VDlSbIFU644WpdH8n-h6L-UnoV8jP5Sooi1exkxQcPGumoEh5pwUCuqhSElLs9KeTZc/s706/ams1117.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="598" data-original-width="706" height="482" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM4e9UIjEthsgult4QwCuEuCuI1qzs2mdJCFqn-Qds5WrvGiw_XtJBGXWi3V816pbCweb5iiMy1VDlSbIFU644WpdH8n-h6L-UnoV8jP5Sooi1exkxQcPGumoEh5pwUCuqhSElLs9KeTZc/w569-h482/ams1117.jpg" width="569" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">AMS1117-3.3 maximum input voltage is 18V</td></tr></tbody></table><br /><p>Now it is possible that other components on the Devkit PCB might require Vin to be 5V. A look at the schematic is advisable. I got mine <a href="https://github.com/nodemcu/nodemcu-devkit-v1.0/blob/master/NODEMCU_DEVKIT_V1.0.PDF">from here</a>. The schematic names the Vin voltage rail VDD5V. The USB rail is VUSB and the 3.3V rail is VDD3V3. Happily there are only 3 components that use Vin:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgkAWOJ9LTDbPV99Vu5z3NsWplhsBZ4nyaNyXut4AF4CioDbiaqJaJ6zxOfymKGzje8QZ-H_GVDMi-AFOML3W7tr65t9XH56quOKqDSOeLGvqjZn5pjw99jwJl5UQa_vi-VY3kN1hrl17m/s797/nodemcu_pwr_schematic.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="443" data-original-width="797" height="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgkAWOJ9LTDbPV99Vu5z3NsWplhsBZ4nyaNyXut4AF4CioDbiaqJaJ6zxOfymKGzje8QZ-H_GVDMi-AFOML3W7tr65t9XH56quOKqDSOeLGvqjZn5pjw99jwJl5UQa_vi-VY3kN1hrl17m/w527-h293/nodemcu_pwr_schematic.jpg" width="527" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">NodeMCU Devkit Vin Power schematic </td></tr></tbody></table><br /><p>Note the schematic even specifies a Vin maximum of 20V. This is because it uses an ON Semiconductor NCP1117ST33 LDO which has a maximum of 20V. Notice C7 is rated at 25V. </p><p>VDDUSB and VDD5V are linked via the schottky diode 1N5819. The 1N5819 is not a problem; it is a 40V 1A device. The problem is it comes in a tiny SOD323 package just 1mm by 2mm in size. This is not going to dissipate much heat. Its <a href="http://pdf.eepw.com.cn/s20091109/d106d4fc4b06554d37c1a80f242706ef.pdf">thermal resistance is 380 degrees Celsius per Watt</a>. Its forward voltage drop is 0.6V and if it were to carry just 500mA current the temperature would rise 114 degrees. </p><p>So if you have both Vin and VDDUSB connected, and you did not happen to have Vin turned on, depending on your power supply, VDDUSB might supply too much current to it and burn up. It is probably safer not to use VDDUSB if Vin is much higher than 5V.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg66zoekq1vo0PqwaLY4BFsDupipT9iRQ4tEoddm1pLIuBM0x6qYs0y72ki7jWkpPtPaThBKX0F9GSVVMYG2deXsaaJfFvzJVUxjuuxTDrtfTJfuZjBoH2VA9MWRc9w7EOhDO76_E8O4Gxb/s670/sod323.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="364" data-original-width="670" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg66zoekq1vo0PqwaLY4BFsDupipT9iRQ4tEoddm1pLIuBM0x6qYs0y72ki7jWkpPtPaThBKX0F9GSVVMYG2deXsaaJfFvzJVUxjuuxTDrtfTJfuZjBoH2VA9MWRc9w7EOhDO76_E8O4Gxb/w529-h288/sod323.jpg" width="529" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">SOD323</td></tr></tbody></table><br /><p>The AMS1117-3.3 comes in a SOT-89 package. This looks a lot heftier than SOD323. <a href="https://www.richtek.com/Design%20Support/Technical%20Document/~/media/AN%20PDF/AN044_EN.ashx">From richtek</a>, the thermal resistance is 135 degrees per Watt. Now we are likely to get better performance because the IC is soldered onto PCB copper traces which will help it dissipate heat, but <a href="https://www.torexsemi.com/file/SOT-89-5/SOT-89-5-pd.pdf">from Torex</a> this is no better than 76.9 degrees per Watt.</p><p>Now my NodeMCU Devkit running its IoT program at 80MHz will take 80mA at 3.3V. This is supplied by the AMS1117-3.3. Now if Vin is 12V, the AMS1117-3.3 is a linear (not buck) regulator, and it will have to dissipate a whopping 8.7V at 80mA or 696mW. At 76.9 degrees/W the temperature rise is 53 degrees. My ambient temperature is often 34 degrees in balmy Malaysia, so that makes <b>87 degrees Celsius at best</b>.</p><p>At worst it is 128 degrees Celsius, perilously close to thermal shutdown at 150 degrees Celsius. So that was why Vin was specified as 5V by the manufacturer.</p><p>Since the issue is just heat and not voltage level, instead of using a 5V buck converter to lower my Vin, I could simply put a reverse-biased 6.8V Zener diode in series. Say a hefty 1N4736 weighing in at 1W. This will take 544mW off the AMS1117-3.3 which now should clock in at a comfy 46 degrees (ie 11.7 degrees rise).</p><p>Now many of the super-cheap NodeMCU have, shall we say, quality standards that are somewhat permissive. In my case AMS1117 was used in place of NCP1117, lowering the maximum Vin to 18V. C7 might also be derated to 6.3V. Your mileage may vary.</p><p>Also it is advisable not to debug with the USB port <b>and</b> 12V connected. If you <b>have to</b> do it connect it to your computer using a powered USB hub. That way if things goes South, you do not lose a motherboard. And if like me you develop your gizmos DevOps fashion, it is also advisable to install <a href="https://github.com/jandrassy/ArduinoOTA">ArduinoOTA</a> so you can update the ESP8266 program via WiFi. </p><p>This removes a future temptation to stick a USB debug cable into a 12V system. If you are unlucky and the 1N4736 fails short-circuited (after all, it runs hot) there will be 12V at Vin. A thermally shut down ESP-12E often looks very much like it has faulty software! </p><p>For my 12V LED lamp I used a <a href="https://hackaday.io/project/8856-incubator-controller/log/29291-node-mcu-motor-shield">NodeMCU L293 motor shield</a> with my Devkit so I mounted the 1N4736 zener directly to the 12V and Vin terminals (see photo above). It worked well for me. After 3 hours at 33 degrees Celsius ambient, the zener diode got pretty hot; too hot to touch, but the ASM1117 was only slightly warm.</p><p>Happy Trails.</p><p> </p><p> </p>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-230086072020887642021-01-03T03:50:00.007-08:002021-02-15T06:26:15.166-08:00Fiber optics for the Home Network<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3m63bJGgZ608Td01Z6J0B1d_89VU7Z6MAWWKLtXyx6ntmV5Io14mQhDjQl2nRFwOlSH0gmojzZQ6zwqXXL9wVBt20T1j5qivp08qie29Mj-idDUBRD_pkEWbYDB78SamA7eytb-OaGamP/s500/fiberoptics.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="275" data-original-width="500" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3m63bJGgZ608Td01Z6J0B1d_89VU7Z6MAWWKLtXyx6ntmV5Io14mQhDjQl2nRFwOlSH0gmojzZQ6zwqXXL9wVBt20T1j5qivp08qie29Mj-idDUBRD_pkEWbYDB78SamA7eytb-OaGamP/w496-h273/fiberoptics.png" width="496" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="text-align: start;">“We cannot live only for ourselves. A thousand fibres connect us with our fellow men; and among those fibres, as sympathetic threads, our actions run as causes, and they come back to us as effects. ” – Henry Melville</span></td></tr></tbody></table><p></p><p>Fiber optics networking, is normally expensive and fragile. Telecoms-grade equipment come to mind. Maybe we even have a broadband fiber to the house (helpfully called FTTH). This usually ends in a telecoms-supplied box, Passive Optical Network (PON) into which we plug out usual copper (ie RJ45 UTP) LAN cable.</p><p><br /></p><p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGUdjjy3WdeQp_BRzsiOMt_efhfpN0BPbv-zBYI6CQfoviYw_D8xseDRuLVl5rsA6spWR5EGrV1HF75JVYHhoCGdTXgx9OB6e_Qui9Z6Xd_GK04vhiKDBIpXZZbL3LWHx9rlhMj0qp9xmt/s768/PON-768x648.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="648" data-original-width="768" height="481" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGUdjjy3WdeQp_BRzsiOMt_efhfpN0BPbv-zBYI6CQfoviYw_D8xseDRuLVl5rsA6spWR5EGrV1HF75JVYHhoCGdTXgx9OB6e_Qui9Z6Xd_GK04vhiKDBIpXZZbL3LWHx9rlhMj0qp9xmt/w571-h481/PON-768x648.png" width="571" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Fiber broadband usually ends in copper LAN connection</td></tr></tbody></table><br /><br /><br />But why would I even want fiber for home LAN? Regular readers will know my house is on a hill which <a href="https://cmheong.blogspot.com/2019/10/thunderbolts-and-lightning-detector.html">regularly gets struck by lightning</a>. We get used to being off-grid for the duration of the storm, which happily is not usually long. But it would be nice not to have damaged electronics. Even better if we can <a href="https://cmheong.duckdns.org/work/matrix3000.html">cut over to UPS</a> and keep watching IP TV or <a href="www.youtube.com">youtube</a>. If my copper LAN cable runs are too long (maybe 30m) lightning often damages the network switches, or even fuse the UTP connectors together.<p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD894lJwF39vFx9KxNwkh-ZAxgyxq6cK_GN5fG5d3ybZioYxPDhuP-58fFRgAev9-eqp7A-oceceTjJnA9OXyrUaKtip5wIUDRdHSSxEqpuvCgU2VfeaF6SFmu1Vo7FkLHd8yQErtTJT6f/s876/huawei_ont.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="529" data-original-width="876" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD894lJwF39vFx9KxNwkh-ZAxgyxq6cK_GN5fG5d3ybZioYxPDhuP-58fFRgAev9-eqp7A-oceceTjJnA9OXyrUaKtip5wIUDRdHSSxEqpuvCgU2VfeaF6SFmu1Vo7FkLHd8yQErtTJT6f/w435-h263/huawei_ont.jpg" width="435" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">A Huawei ONT 'fiber modem' commonly supplied with Unifi fiber broadband</td></tr></tbody></table><br /><div><br /></div><div>Or you might want more reliable and secure links for your security cameras/CCTVs which are often outdoors and at the end of long cable runs. Maybe you want to share your neighbor's broadband connection. </div><div><br /></div><div>Or maybe you simply want to speed up/secure that wireless WiFi repeater for when you are at one end of the garden. High speed WiFi is well and good, but once your neighbors have theirs installed the airways can get pretty crowded. </div><div><br /></div><div>Fiber LAN often means using telecoms equipment which are not only expensive but often not available to the general public. First, the fiber optic cable. Your best chance would be to use the type that your local telecoms monopoly/behemoth uses. High manufacturing volumes usually mean lower prices. Here in Malaysia it is <span face="arial, helvetica, sans-serif" style="background-color: white; color: #030000; font-size: 16px;"> </span>G.657 Class A single mode fiber. A 1000m roll of outdoor cable costs less than RM200 (USD50) and even RM100 (USD25) if you are willing to order from mainland China. That is comparable to a <b>300m</b> roll of copper Cat 5 UTP LAN cable. </div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrAM4M4373t3TleP2vjlCzndolMuY3FykGx7Ns86fuOYwVMdx_rTPyqPH_WH6u-yrtRDyimUd7a9hgS36JCHraPAZZ2bCeNa7-YIBpd_SS4EiAmBfoRls1Ulw8y8RHQbbfzJwP6NfBuCRp/s1071/unifi1000mcable.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="595" data-original-width="1071" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrAM4M4373t3TleP2vjlCzndolMuY3FykGx7Ns86fuOYwVMdx_rTPyqPH_WH6u-yrtRDyimUd7a9hgS36JCHraPAZZ2bCeNa7-YIBpd_SS4EiAmBfoRls1Ulw8y8RHQbbfzJwP6NfBuCRp/w438-h243/unifi1000mcable.jpg" width="438" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">1km roll of G.657 Class A single mode fiber</td></tr></tbody></table><br /><br />But fiber cable is more fragile? Yes, if you used the equivalent indoor drop cable. The outdoor cable is often extremely strong. Mine consisted of not one but 3 steel cables reinforcing the fiber cable. I have had tree branches pulling it almost to the ground and the fiber core remained unbroken. They are often stronger than the copper UTP cables.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWA7167pbFXeIymEVZXWq35L5D-ZUL_wOKV6KIk0U5dqQTfg0N_csUOWy7dAgAih_buRUjWcifuSkrZHe-eMdH0fR-eqF1HiSmaGM2jKRwDgoh-g-kD0sR1qgcoNpLSbF577qK8NiAATcb/s512/unifi1000mcable_stripped.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="366" data-original-width="512" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWA7167pbFXeIymEVZXWq35L5D-ZUL_wOKV6KIk0U5dqQTfg0N_csUOWy7dAgAih_buRUjWcifuSkrZHe-eMdH0fR-eqF1HiSmaGM2jKRwDgoh-g-kD0sR1qgcoNpLSbF577qK8NiAATcb/w501-h358/unifi1000mcable_stripped.jpg" width="501" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Outdoor fiber cables are often extremely strong</td></tr></tbody></table><br /><div>The outdoor fiber cable is far more heavy but they are still smaller than the Cat 5 or 6 copper cable. It is surprisingly bendable, considering fiber optics is a glass. And since there is no ohmic contact, you can run the cable parallel to the mains cables, in the same cable trays or conduits. This greatly reduces cabling costs.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUkJbeab8e-Dwhg4VesSFDmcIA_R-kbsWaAcgeFfiGcnZJYHPilS8Ev_mo03gxXlvBOgx8_pXCFZxHUMFJxfAeRr9P225_jGJpMOiLSaq46-7s6AOVS7023Q24o7AixF23ogyi9eGxfwIP/s500/fiberpatchcable.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="500" data-original-width="500" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUkJbeab8e-Dwhg4VesSFDmcIA_R-kbsWaAcgeFfiGcnZJYHPilS8Ev_mo03gxXlvBOgx8_pXCFZxHUMFJxfAeRr9P225_jGJpMOiLSaq46-7s6AOVS7023Q24o7AixF23ogyi9eGxfwIP/w426-h426/fiberpatchcable.jpg" width="426" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Most indoor fiber is limp and frail</td></tr></tbody></table><br /><div><br /></div><div><br /></div><div>OK, but what about the fiber optic interface to the computer? A single mode single core fiber cable specifications are something like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEim_5BtgeVC-Tzv4vmClrQkZigyPy4aKgX0cwEsO_Dr3aBukV0TFTFtewM-cl5WI1Xfw_u8Iml6YZfHlxjF84h40x7mdO8DwGjHVYGUgcei5dxakVz0fJieQafTflgG0D7Dvn9p0_fU3NQJ/s973/cablespecs.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="337" data-original-width="973" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEim_5BtgeVC-Tzv4vmClrQkZigyPy4aKgX0cwEsO_Dr3aBukV0TFTFtewM-cl5WI1Xfw_u8Iml6YZfHlxjF84h40x7mdO8DwGjHVYGUgcei5dxakVz0fJieQafTflgG0D7Dvn9p0_fU3NQJ/w569-h198/cablespecs.jpg" width="569" /></a></div><br /><div>The last line reads 850/1300nm: it carries just 2 light frequencies. If you need more channels you need to run another cable. The traditional multi-mode cables carries lots of frequencies, but with a price tag to match.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCeF2Psy2Ff0N3we0C9TwgJiw0mBQVezLufryFMU18ID52EWgTEjTsTodvFb9QMhnZMX5AH6fY-A1BGBtKZG00QLPZl6v2Js1ktO6nYbQWeCV2ZRD2vqeabDLypT6BqqgUHfrkRFzO_Xib/s345/Singlemode-Multimode-image-TWO.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="301" data-original-width="345" height="457" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCeF2Psy2Ff0N3we0C9TwgJiw0mBQVezLufryFMU18ID52EWgTEjTsTodvFb9QMhnZMX5AH6fY-A1BGBtKZG00QLPZl6v2Js1ktO6nYbQWeCV2ZRD2vqeabDLypT6BqqgUHfrkRFzO_Xib/w524-h457/Singlemode-Multimode-image-TWO.jpg" width="524" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Poor cousin: single-mode versus multi-mode fiber</td></tr></tbody></table><br /><div><br /></div><div>We will be needing something to convert between UTP and fiber: two fiber modems, one at each end. As usual the Chinese have something cheap and cheerful (only RM25/USD5) called a media converter: the HTB-3100.</div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBsbAFJgpVm0MEwcHSt_zV8hXG7CTnUQfdUtAF47QyrpZ734sql8qJqc7DF4FeHx4XhEJe_hez56NfjTyI6jyPve1zDUL54aumUYXuuIBMu0n01v0uzFRAYD28DcUsrifzQz4_KCaXBWxu/s516/htb-3100AB.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto; text-align: center;"><img border="0" data-original-height="516" data-original-width="391" height="739" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBsbAFJgpVm0MEwcHSt_zV8hXG7CTnUQfdUtAF47QyrpZ734sql8qJqc7DF4FeHx4XhEJe_hez56NfjTyI6jyPve1zDUL54aumUYXuuIBMu0n01v0uzFRAYD28DcUsrifzQz4_KCaXBWxu/w559-h739/htb-3100AB.jpg" width="559" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The HTB-3100A and HTB-3100B are sometimes sold as a matched pair</td></tr></tbody></table></div><div><br /></div><div>Now this being a Chinese no-name box, be careful to look for a media converter that has <b>only one fiber SC UPC port</b>. The picture above shows <b>two</b> (marked TX and RX) but only the TX port can be uncovered. If you, like me, happen to buy the dual-port box by mistake you will need to lay 2 fiber cables for every copper UTP connection. You want to look for WDM (Wavelength Division Multiplexing). To carry 2 channels in one fiber, it transmits in one wavelength, 1550nm and receives at another, 1310nm. That is Type A. Type B is just the reverse, transmitting at 1310nm and receiving at 1550nm. You will be needing one unit of each type. They are often sold in matched pairs.</div><div><br /></div><div>Both the single fiber and dual fiber media converters might be labelled as Half/Full Duplex. My guess is this refers to the UTP (ie RJ45 or copper) end. These days most CAT5 or CAT6 copper LAN cables come with both TX and RX pairs, and Half Duplex might be when Ethernet is negotiated down to CSMA/CD. </div><div><br /></div><div>Last but not least there is the complex matter of cutting, splicing and terminating your fiber optic cable. Years ago, it took expensive equipment, highly-trained operators and extremely clean conditions, which are sometimes difficult to do on-site. But for now there is and end-run, a workaround. Again from the Chinese. You can buy the cables already terminated for very low prices. Like RM36 for 50m. That is just USD9.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmnaZXgS5f_rNe8Q_BZJb3fjUUDpmrzCpnfNSFajjpIVYGfD7IJJjxejLuPN9gnNtDgIR9OvkXtvfBkhTWgPog6tO4njb2Ke9IMyfEzTAfzm4yBj8TN5BpzXCH6yyPv_2QjY-e_k6iUvWF/s1135/50m_cable_terminated.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="723" data-original-width="1135" height="323" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmnaZXgS5f_rNe8Q_BZJb3fjUUDpmrzCpnfNSFajjpIVYGfD7IJJjxejLuPN9gnNtDgIR9OvkXtvfBkhTWgPog6tO4njb2Ke9IMyfEzTAfzm4yBj8TN5BpzXCH6yyPv_2QjY-e_k6iUvWF/w506-h323/50m_cable_terminated.jpg" width="506" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Pre-terminated outdoor single mode fiber cable.</td></tr></tbody></table><br /><div>Some suppliers will do it to a custom length. Just make sure the connector is SC UPC (it is easy to specify the incompatible SC APC or LC connectors). Now I had coax 10Base2 concealed LAN wiring installed in my house (yes, yes I am a dinosaur), so it was an easy matter to rip it out of the conduits and install the smaller fiber cable in it place.</div><div><br /></div><div>The aim is to replace your long copper cable runs with fiber. One benefit is if the cable run is over 100m you do not need to install the repeaters (ie LAN switches) that UTP Ethernet needs. If you add in the cost of the power wiring, enclosures, the savings quickly pile up.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbaxLB9nzsmiArKULQqASZQXrbsLcjBipS_LZqxe89Aacb9DU4hiF-AiUJg4T5t9f86jUA0O3PIivxxj5GL6shKbZYfhZVq0fgug1wKZXIqfIDEmIf9TvkVqOrGs-gWsDLMVJyUc_w55nX/s1453/media-converter-diagram.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="517" data-original-width="1453" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbaxLB9nzsmiArKULQqASZQXrbsLcjBipS_LZqxe89Aacb9DU4hiF-AiUJg4T5t9f86jUA0O3PIivxxj5GL6shKbZYfhZVq0fgug1wKZXIqfIDEmIf9TvkVqOrGs-gWsDLMVJyUc_w55nX/w564-h200/media-converter-diagram.jpg" width="564" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The aim is to replace long copper LAN cable runs with fiber (in red)</td></tr></tbody></table><br /><div><br /></div><div><br /></div><div>It worked so well I ran another 100m fiber cable outdoors to my home office so I can share the broadband. The system has been in place through several violent thunderstorms and one fallen tree and did not miss a beat.</div><div><br /></div><div>If you live in Malaysia, you are in luck, for Talikom Malaysia, the telecoms monopoly mostly uses sub-contractors to install your FTTH fiber cable. For a very reasonable fee, not exceeding the cost of a roll of fiber cable, they can be persuaded to do your internal house fiber cabling. In my case it was money well spent for much of the work involved climbing onto the roof. A huge advantage is they will splice and terminate your fiber cable using proper equipment, resulting in a very good connection.</div><div><br /></div><div>The only thing left would be an inexpensive way to cut, join and terminate a fiber cable myself. But that is for another post.</div><div><br /></div><div>Happy Trails. </div><p> <br /> </p><div class="separator" style="clear: both; text-align: center;"><br /></div><br />cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0tag:blogger.com,1999:blog-7125203381804324279.post-34962665589583019382020-12-17T06:02:00.003-08:002020-12-18T17:40:50.011-08:00RESTful IoT with privacy & security: How to set up a Debian HTTPS Server<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj26k0u5O3Ta27V3GHPJ0lpypCIo-syhQX635WtG_7gpiqLnUNLv9Uw2MnsClaanwXHyHyA-qjFPgDWqLnK0rO7A62uq2Nljtdv8lwdvf1Qpjm3XhdRX_NJ6VAL1dbQ8XRluqeJKoAW7VeL/s1600/robot-resting-on-beach.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1089" data-original-width="1600" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj26k0u5O3Ta27V3GHPJ0lpypCIo-syhQX635WtG_7gpiqLnUNLv9Uw2MnsClaanwXHyHyA-qjFPgDWqLnK0rO7A62uq2Nljtdv8lwdvf1Qpjm3XhdRX_NJ6VAL1dbQ8XRluqeJKoAW7VeL/w570-h388/robot-resting-on-beach.jpg" width="570" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">"It is quiet here and restful, and the air is delicious. There are gardens everywhere and police spies lie in the bushes ... " - Maxim Gorky</td></tr></tbody></table><br /><p></p><p>It is very tempting to use the ubiquitous HTTP web protocol for <a href="https://en.wikipedia.org/wiki/Internet_of_things">IoT</a>. It is easy to test, and lets you operate your IoT from smartphones, tablets, desktops and even a computer program. Such a setup is called <a href="https://en.wikipedia.org/wiki/Representational_state_transfer">RESTful</a>. It simply means your IoT device speaks the language of the web browser and web server. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjleRe_ybELpA30kY8gzfiw1DazQDXrMRL1NC4cZzm9bEUu4hwV8W2bYMpvyFPUhOxYPSiZ3FzQmXNWoBj1SyAZuh1twi60lxbNYz2C7Q13g0bQ-gbZG8zaW_8z5h6ZloO06TXdlAZ5T8sY/s608/RESTFul-Web-Service-Architecture.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="288" data-original-width="608" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjleRe_ybELpA30kY8gzfiw1DazQDXrMRL1NC4cZzm9bEUu4hwV8W2bYMpvyFPUhOxYPSiZ3FzQmXNWoBj1SyAZuh1twi60lxbNYz2C7Q13g0bQ-gbZG8zaW_8z5h6ZloO06TXdlAZ5T8sY/w528-h250/RESTFul-Web-Service-Architecture.png" width="528" /></a></div><br /><p><br /></p><p>So we rush ahead with our RESTful API, and the IoT device is soon working and indispensable. Pretty soon we realize we need security and privacy: it won't do to have a hacker open the voice-controlled garage door ...</p><p>Our first line of defense is our WiFi password. It is reasonable to assume those living in the house should have access to WiFi and IoT. But what if we had guests or lodgers? Changing WiFi passwords can be a real bear, especially if you have 20-odd IoT devices. In fact it makes sense to localize the changes to a dedicated IoT server. RESTful, naturally. </p><p>We will be needing some form of authentication: account names and passwords should do for now. Next we will need a reasonable amount of privacy, i.e., encryption so that someone else should not be able to lift the IoT password off the WiFi. That means HTTPS, or HTTP with SSL.</p><p>We start by implementing HTTPS server on a Linux system. The ESP8266 is known to be a little wobbly running HTTPS. ESP32 is better, but we can do without the complication for now. The traditional way is to use <a href="https://en.wikipedia.org/wiki/Apache_HTTP_Server">Apache</a>. There are other, easier ways (like nginx, nodejs and even python) but Apache lets you run multiple servers right off the bat. This means you can keep your bad old HTTP server, add another HTTPS server on top of that and lets you support both your HTTP and HTTPS IoT devices.</p><p>From a bog-standard Debian (mine is a <a href="https://en.wikipedia.org/wiki/BeagleBoard#BeagleBone">Beaglebone</a> on <a href="https://cmheong.blogspot.com/2020/08/if-at-first-you-dont-succeed-try-try.html">eMMC</a>), do the usual:</p><p># apt-get update</p><p># apt-get upgrade</p><div>Next, <a href="https://www.raspberrypi.org/documentation/remote-access/web-server/apache.md">get Apache</a>:</div><div><br /></div><div># apt install apache2</div><div><br /></div><div>And while you are at it, you might as well <a href="https://phoenixnap.com/kb/how-to-enable-ssh-on-debian">make sure you have ssh</a>. I got my <a href="http://www.duckdns.org/">DNS from duckdns</a>.</div><div><br /></div><div>Apache should come up complete with the stock webpage at http://localhost. Put your webserver files at /var/www/html/<br /><br />To access the webserver from outside your WiFi access point, you will need a DNS server, but once you get it organized, a bog standard browser will display a warning before it will display your home page:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWbpxyw5DV3E1J42HD2dEFf74ZcrIVCNSrHTtxqnjSM6FAgkhgpowLrQkLw-So_Y_MY0009zh5HY8CB2YaqHGXjOAufZ539w1WBjzTKlAFjiQGDlEeDS2HS1aTOL2U32bJxA9vLFJ2Xr3a/s561/notprivate.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="347" data-original-width="561" height="354" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWbpxyw5DV3E1J42HD2dEFf74ZcrIVCNSrHTtxqnjSM6FAgkhgpowLrQkLw-So_Y_MY0009zh5HY8CB2YaqHGXjOAufZ539w1WBjzTKlAFjiQGDlEeDS2HS1aTOL2U32bJxA9vLFJ2Xr3a/w571-h354/notprivate.jpg" width="571" /></a></div><br /><div>That means you need SSL, which usually costs money. You can opt for a self-signed certificate but this will produce a warning with most browsers. You then elect to disregard the warning and proceed, but this is a real problem if you are trying to sell the IoT device.</div><div><br /></div><div>One way out is to get a 90-day certificate free from <a href="https://www.sslforfree.com/">sslforfree</a>. You just have to register, input your domain name and prove that you have access to the webserver, usually by uploading an sslforfree file to it. After it checks out the certificates can be downloaded. <a href="https://www.youtube.com/watch?v=orF39piVlIc&ab_channel=%E6%9B%BE%E5%82%91%E6%B0% 91">sslforfree links to a youtube video</a> describing the process.</div><div><br /></div><div>Do check out the video. I will simply list the differences relevant to a Debian installation. In Debian it is a simple:</div><div><br /></div><div><div># a2enmod ssl</div><div>Considering dependency setenvif for ssl:</div><div>Module setenvif already enabled</div><div>Considering dependency mime for ssl:</div><div>Module mime already enabled</div><div>Considering dependency socache_shmcb for ssl:</div><div>Enabling module socache_shmcb.</div><div>Enabling module ssl.</div><div>See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create s</div><div>elf-signed certificates.</div><div>To activate the new configuration, you need to run:</div><div> systemctl restart apache2</div></div><div><br /></div><div>I now need a configuration file for my HTTPS (or SSL) webserver. There is a template in Debian:</div><div><br /></div><div># cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/secure.cmheong.duckdns.org.conf</div><div><br /></div><div>secure.cmheong.duckdns.org being the domain name of my new HTTPS server. The parameters for the new server are put in:</div><div><br /></div><div><div># cat /etc/apache2/sites-available/secure.cmheong.duckdns.org.conf | head -n 16</div><div><IfModule mod_ssl.c></div><div> <VirtualHost _default_:443></div><div> ServerName secure.cmheong.duckdns.org</div><div> ServerAlias www.secure.cmheong.duckdns.org</div><div> ServerAdmin webmaster@secure.cmheong.duckdns.org</div><div><br /></div><div> DocumentRoot /var/www/html</div><div><br /></div><div> # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,</div><div> # error, crit, alert, emerg.</div><div> # It is also possible to configure the loglevel for particular</div><div> # modules, e.g.</div><div> #LogLevel info ssl:warn</div><div><br /></div><div> ErrorLog ${APACHE_LOG_DIR}/secure.cmheong.error.log</div><div> CustomLog ${APACHE_LOG_DIR}/secure.cmheong.access.log combined</div></div><div><br /></div><div>You then check your configuration and do not proceed further until this passes:</div><div><br /></div><div><div># apachectl configtest</div><div>Syntax OK</div></div><div><br /></div><div>Make sure your webserver is now accessible from the Internet. Usually this means setting up Port Forwarding in your gateway to forward all port 443 traffic to your server IP address.</div><div><br /></div><div># systemctl restart apache2</div><div><br /></div><div>You will then need to prepare for the sslforfree test of webserver and domain name ownership:</div><div><br /></div><div># mkdir /var/www/html/.well-known</div><div># mkdir /var/www/html/.well-known/pki-validation</div><div><br /></div><div>Register with sslforfree, download the challenge file they provided and put it in the new directory. This is where the Debian ssh installation comes in handy. </div><div><br /></div><div>If the sslforfree challenge succeeds, then the certificates and private key will be generated as a zip file.</div><div><br /></div><div><div># unzip secure.cmheong.duckdns.org.zip</div><div>Archive: secure.cmheong.duckdns.org.zip</div><div> extracting: certificate.crt</div><div> extracting: ca_bundle.crt</div><div> extracting: private.key</div></div><div><br /></div><div>You then move them to their final secure directories:</div><div># cp -v ./sslforfree/*.crt /etc/ssl/certs</div><div><div>'./sslforfree/ca_bundle.crt' -> 'certs/ca_bundle.crt'</div><div>'./sslforfree/certificate.crt' -> 'certs/certificate.crt'</div></div><div><br /></div><div><div># cp ./sslforfree/private.key /etc/ssl/private/private.key</div></div><div><br /></div><div>Remember to delete the ./sslforfree directory. If you want to put the certificates in a different place you will need to update the site config file accordingly:</div><div><br /></div><div># cat /etc/apache2/sites-available/secure.cmheong.duckdns.org.conf | grep -i SSLCerti</div><div> # SSLCertificateFile directive is needed.</div><div> #SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem</div><div> #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key</div><div> SSLCertificateFile /etc/ssl/certs/certificate.crt</div><div> SSLCertificateKeyFile /etc/ssl/private/private.key</div><div> SSLCertificateChainFile /etc/ssl/certs/ca_bundle.crt</div><div><br /></div><div>As usual test the Apache configuration:</div><div><br /></div><div># apachectl configtest</div><div><br /></div><div>And then restart Apache:</div><div><br /></div><div># systemctl restart apache2</div><div><br /></div><div>The just aim your Chrome browser at https://www.yoursecureserver.com. If it worked you get something like this:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /> </div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX9uzVjqMByqkdNN6peGQTRRov47RAauicQY5icLWsbbZHvipKRj7K0VyJTKzQhzqSCKtQUcdH-1W0hXW_JoPwFo1-2KdyuzaIFYzFRbjEUWDelymCiAZy4oJ5tikXBIYdZ8Ja_Zw7SDZU/s547/success.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="328" data-original-width="547" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX9uzVjqMByqkdNN6peGQTRRov47RAauicQY5icLWsbbZHvipKRj7K0VyJTKzQhzqSCKtQUcdH-1W0hXW_JoPwFo1-2KdyuzaIFYzFRbjEUWDelymCiAZy4oJ5tikXBIYdZ8Ja_Zw7SDZU/w423-h254/success.jpg" width="423" /></a></div><br /><div>Now the traffic to and from the IoT RESTful server is encrypted. Note the sslforfree certificates expire in 90 days, but you are free to generate a new set. They will even email you a reminder. </div><div><br /></div><div>There you have it: a secure Internet-facing RESTful IoT server.</div><div><br /></div><div>Happy Trails.</div>cmheonghttp://www.blogger.com/profile/08031087126084889161noreply@blogger.com0