tag:blogger.com,1999:blog-66502040293115062672024-02-19T14:32:04.178-08:00Dev with AlexAlexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-6650204029311506267.post-3057107751413151572020-11-29T18:52:00.010-08:002021-04-11T08:35:11.642-07:00HelloTwo<div class="separator" style="clear: both;"><h3 style="clear: both; text-align: left;">Overview</h3><div class="separator" style="clear: both; text-align: left;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9M0p-YiDT8epOP1V7a7nzQJIE_WWPt5tef9TWkw-m_L_s0fBXuqnyvu-e-ZCEf2elOOOyvjBS7X_utwNEL5tX-C_axgLBumPSaZu9grOxzL1gseJIbJe2_IyvDRV9LtJi8K92LKQotVY/" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img data-original-height="873" data-original-width="1552" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9M0p-YiDT8epOP1V7a7nzQJIE_WWPt5tef9TWkw-m_L_s0fBXuqnyvu-e-ZCEf2elOOOyvjBS7X_utwNEL5tX-C_axgLBumPSaZu9grOxzL1gseJIbJe2_IyvDRV9LtJi8K92LKQotVY/w320-h181/image.png" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Kickstarter promo image, ©Hello</td></tr></tbody></table><div style="text-align: justify;">In 2014 a startup called Hello launched their first product on <a href="https://www.kickstarter.com/projects/hello/sense-know-more-sleep-better" target="_blank">kickstarter</a> the "Sense". This little orb of intricate injection moulded plastic was easily the most fully featured sleep tracking device available to consumers. The business model was solely based around sales with no ongoing service fees. This made the business very unsustainable. After attracting quite a lot of success and breaking into mainstream retail sales Hello <a href="https://medium.com/@hello" style="text-align: justify;">folded in 2017</a><span style="text-align: justify;">. </span></div><span style="text-align: justify;"><br />Unfortunately, this left the hardware unsupported with no servers to process it's data. The Hello company did initially offer some support for the idea of <a href="https://github.com/oaeide/hello-sense-server">open sourcing</a> support for their devices but this never got off the ground. Fast forward to 2020 and it has become obvious no one is going to get the original hardware working again. It simply wouldn't make sense in the days of $4 WiFi enabled MCUs to put the effort into reverse engineering the software stack on the Sense. What does make sense is scavenging some of the amazing industrial design and sensors and building a new data logging solution.</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: justify;">The original Sense offers 6 environmental sensors: illumination, humidity, temperature (<a href="https://cdn-shop.adafruit.com/datasheets/1899_HTU21D.pdf">HTU21D-F</a>), sound, dust (Sharp GP2Y10), and motion, via a bluetooth dongle. I'm only interested in air quality so my work only involves those sensors.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><h3 style="clear: both; text-align: left;">Hardware</h3><div class="separator" style="clear: both; text-align: justify;">Before tearing my device to pieces, I had a look around the internet and stumbled onto <a href="http://lyndsaywilliams.blogspot.com/2015/07/hello-sense-sleep-computer-under.html " target="_blank">Lyndsay Williams' Blog</a>. Lyndsay did a great teardown and inspection of the Sense back in 2015 and his images were a great help to me.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGHzgewdBXu3WktBamlMresfzH6CFysp5Q-rdUe-O9yOVpm2V7vtc6WQFM10F7LxsD10xSf9e11j9NzOmHAfb0d1gjjg5xVaBGRF5cJ19iii9e2Q7YkeJ-ambrxZjEP2ngXxZauKEKtiA/" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img alt="" data-original-height="751" data-original-width="1000" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGHzgewdBXu3WktBamlMresfzH6CFysp5Q-rdUe-O9yOVpm2V7vtc6WQFM10F7LxsD10xSf9e11j9NzOmHAfb0d1gjjg5xVaBGRF5cJ19iii9e2Q7YkeJ-ambrxZjEP2ngXxZauKEKtiA/w320-h240/PXL_20201129_155313675-01.jpeg" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><span style="font-size: x-small;">Power board pictured later</span></td></tr></tbody></table><div style="text-align: justify;">To summarize, the Sense is built with 4 PCBs. From bottom up: power conditioning, LEDs, processor, and finally sensor board.</div><br /><div style="text-align: justify;">Between the LED board and the processor sits the <a href="https://www.sparkfun.com/datasheets/Sensors/gp2y1010au_e.pdf">Sharp GP2Y10</a> dust sensor.</div><br /><div style="text-align: justify;">To avoid self heating, the HTU21D-F is mounted at the bottom of the device near the input air vents. The intent here seems that any heat generated in the device will create an updraft. Any resulting airflow would contribute to keeping the temperature and humidity values reasonably true. Reviewing the layout of the sensors shows that for this project only the power conditioning board is needed. All the others can be removed. This leaves plenty of space to fit a NodeMCU board inside the Sense.</div></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"></div></div><div class="separator" style="clear: both; text-align: left;"><div style="text-align: right;"><br /></div><div style="text-align: justify;">In order to power the replacement MCU and talk to the HTU21D-F, there needs to be several connections to the power conditioning board. Originally, these were made with a flex PCB ribbon cable. Not having access to an appropriate header, the obvious solution was to take inspiration from the insanity that is the Wii Modding community and break out the <a href="https://twitter.com/GingerOfMods/status/1143526714179330048?s=20">magnet wire</a>.</div><br /><div style="text-align: justify;">Using a multimeter in continuity mode, I probed around the power board and found pads which carried the I2C signals from the HTU21D-F and the USB power signals. The same process could be carried out to interface with other sensors in the device, but as previously mentioned I was only interested in air quality. After soldering magnet wire to each of the pads, I applied a couple of dabs of enamel nail polish to relieve the wires and avoid having to do any later rework.</div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho5kUbQJXKQy3XNQfj1jUp8D6ZJf7qrxznZn66Q328NDnvMoxpPzjvaJK5OwlCagfSVKedjBS_fog7WaAHLussl9mwbk0Ye__uxloPT15VRI736Sz2keRGkDPLEj_s-uPYaWqEkIr0Q1o/s2048/PXL_20201114_162510571.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1536" data-original-width="2048" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho5kUbQJXKQy3XNQfj1jUp8D6ZJf7qrxznZn66Q328NDnvMoxpPzjvaJK5OwlCagfSVKedjBS_fog7WaAHLussl9mwbk0Ye__uxloPT15VRI736Sz2keRGkDPLEj_s-uPYaWqEkIr0Q1o/w640-h480/PXL_20201114_162510571.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: justify;">Wiring to the Sharp GP2Y10 was somewhat simpler. Again the connection is made with a ribbon cable. However, in the case of the Sharp sensor this is a regular wire cable. The MCU end of this cable can be snipped off and soldered to. The Sharp GP2Y10 is a really frustrating device. It's apparently calibrated at factory but relies on two external components (a resistor and capacitor) to control the sensing and readout. This means that the sensor can never be more calibrated than the tolerance of the external components. It would have been extremely easy for Sharp to have integrated these and calibrated the system as a whole. With the magnet wire mess already well underway from interfacing the temperature sensor, I decided to simply float the support components for the Sharp sensor.</div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjLSl6V4FZk9ZDKU3gby53i9whvzgyeS3qrEYaZxyLxeu3Vvmt2KRDpHGhNBD7WoB5-pks6diUOwlpQBhbUqIdoDbf8TeWxMmQNJCArN7ImgZimrgrFDCEHoXHKzo7cL9JFL-IdD9yVrc/" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"><img alt="" data-original-height="641" data-original-width="759" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjLSl6V4FZk9ZDKU3gby53i9whvzgyeS3qrEYaZxyLxeu3Vvmt2KRDpHGhNBD7WoB5-pks6diUOwlpQBhbUqIdoDbf8TeWxMmQNJCArN7ImgZimrgrFDCEHoXHKzo7cL9JFL-IdD9yVrc/w320-h270/image.png" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcL28f0kez-kB4imtS25ggWaFpKb6LNRBEa3TWVhsWcdU9H8dG9pFVNLBWgUTGlRR-a1_VXxctAsKUo5WbS1Bqbj185hVpOJhXeFN8UzJPAzJNl0rDG1AHMek5S4_lSYIAovKTRhe8OG0/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="2048" data-original-width="1536" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcL28f0kez-kB4imtS25ggWaFpKb6LNRBEa3TWVhsWcdU9H8dG9pFVNLBWgUTGlRR-a1_VXxctAsKUo5WbS1Bqbj185hVpOJhXeFN8UzJPAzJNl0rDG1AHMek5S4_lSYIAovKTRhe8OG0/w240-h320/PXL_20201114_171602269.jpg" width="240" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheAyVEExS_NFn-hT13VOdsu4mBafE7XBVxyiQQ1PVp3SjH98jrKAUp76UpA_TQr6vbAuciVTe_rtsfRuBPW4fAA9NYVMhaVdlawD0-qN5ffkR5hPwZ4V9gnSkMSKG5Klm5Fnha_ncfMNE/" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="" data-original-height="2048" data-original-width="1536" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheAyVEExS_NFn-hT13VOdsu4mBafE7XBVxyiQQ1PVp3SjH98jrKAUp76UpA_TQr6vbAuciVTe_rtsfRuBPW4fAA9NYVMhaVdlawD0-qN5ffkR5hPwZ4V9gnSkMSKG5Klm5Fnha_ncfMNE/w240-h320/PXL_20201114_172017575.jpg" width="240" /></a><div style="text-align: justify;">With all the sensors wired up, I powered up the board by the USB port on the NodeMCU and tested out my interface code. It turned out that several of the digital pins broken out the NodeMCU have odd reservations and the trigger pin for the Sharp sensor had to be moved. </div><br /><div style="text-align: justify;">After this was complete the sensors worked as expected. The only issue was the really intense LED on the NodeMCU. </div><br /><div style="text-align: justify;">The Sense was designed to include a ring of LEDs and as such, the whole thing lights up blue. That wasn't desirable so the LED was quickly desoldered. After carefully reassembling the device, the hardware work was complete. (I did not bring the USB data lines from the power board up to the NodeMCU so the device must be opened to update the firmware via USB).</div></div><div class="separator" style="clear: both; text-align: left;"><br /></div></div></div><div class="separator" style="clear: both; text-align: center;"><img alt="" border="0" data-original-height="2048" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_-udmi6RcGtYqQg1RidUmm0OfDVwFwPh7H9dpZrUVf16lh7thzzeBiOrA_BJiCBQzerVV6NwX7kaSv1uEXqskzqDj2bPz_NjcoObl_4CvmpymDp1pscHTUxpgQS23Lm8bHCvYKsVtVZo/s320/PXL_20201114_191000815.jpg" width="320" /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlnr9LpVPltRAhmaMODPTmfcLWmoerg0yRBe7ZO_x3scWtwlXVNbEM4nGv98mXfhBZmRfrwQqxQksI12wsop99oB3Td9NThu9mZhmYalbBkwxErphT5xqiwOuLPPf14v2kCqJFwpWaz90/s2048/PXL_20201114_191746642.jpg" style="display: inline; padding: 1em 0px; text-align: left;"><img alt="" border="0" data-original-height="2048" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlnr9LpVPltRAhmaMODPTmfcLWmoerg0yRBe7ZO_x3scWtwlXVNbEM4nGv98mXfhBZmRfrwQqxQksI12wsop99oB3Td9NThu9mZhmYalbBkwxErphT5xqiwOuLPPf14v2kCqJFwpWaz90/s320/PXL_20201114_191746642.jpg" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd_JmlC3pxXRNSYc_4uz_30cAGNZPYMrPKgKRkgwBpyZ8-PpvXPHIlEurYUHrI9LSy4Ex6D0_fwddXi4fM_6Ic9YsiTxSG156Rj1ykF8JoVD9Yv3bSN7XFLHZZ2lifU98HQFf5d5q22tY/s2048/PXL_20201114_192127006.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1536" data-original-width="2048" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd_JmlC3pxXRNSYc_4uz_30cAGNZPYMrPKgKRkgwBpyZ8-PpvXPHIlEurYUHrI9LSy4Ex6D0_fwddXi4fM_6Ic9YsiTxSG156Rj1ykF8JoVD9Yv3bSN7XFLHZZ2lifU98HQFf5d5q22tY/w640-h480/PXL_20201114_192127006.jpg" width="640" /></a></div><div class="separator" style="clear: both;"><br /></div><h3 style="clear: both; text-align: left;">Software</h3><div class="separator" style="clear: both; text-align: justify;">For collecting and monitoring the data I looked into a lot of solutions. For this project I wanted long term data storage, low cost, and MQTT as the data transfer mechanism. Adafruit and Particle offer hosted services which meet two of these conditions, but fail to provide the full package. Turning to DIY solutions ELK(Elasticsearch, Logstash, and Kibana) was my first thought. However, while searching around on GitHub I found similar <a href="https://github.com/Nilhcem/home-monitoring-grafana">datalogging project by Nilhcem</a>. He uses MQTT, InfluxDB, and Grafana. This is a much better stack and thanks to Nilhcem, you can stand up his logging solution from a Docker Compose file in about 5 minutes. A couple of simple Grafana graph configurations later, and you should have a dashboard like this.</div><div class="separator" style="clear: both;"><br /></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc4XoSoNBJaHpIAoRRvEZ08LtiSD9UvvMSUTLxrbttwXho0BGalyJEa7uJUZuvGuT7E8MCqGTnynOUbU09de-wghx4Tk6hzMsrRnuwmwOdmLof_nRJqsBFRr9lFwON4z3XU7-kJi9H_Jw/s1357/Untitled.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="949" data-original-width="1357" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc4XoSoNBJaHpIAoRRvEZ08LtiSD9UvvMSUTLxrbttwXho0BGalyJEa7uJUZuvGuT7E8MCqGTnynOUbU09de-wghx4Tk6hzMsrRnuwmwOdmLof_nRJqsBFRr9lFwON4z3XU7-kJi9H_Jw/w640-h448/Untitled.jpg" width="640" /></a></div><p style="text-align: justify;">If you have a Hello Sense sitting around and want to replicate what I built, you can pull the Arduino code from my GitHub here: <a href="https://github.com/Bostwickenator/HelloTwo">https://github.com/Bostwickenator/HelloTwo</a>.</p><p style="text-align: left;"><br /></p><h3 style="text-align: left;">Troubleshooting</h3><div><ul style="text-align: left;"><li>Pin reservations on the NodeMCU. GPIO 9 and 10 are special and you need to be careful using them <a href="http://smarpl.com/content/esp8266-esp-201-module-freeing-gpio9-and-gpio10">http://smarpl.com/content/esp8266-esp-201-module-freeing-gpio9-and-gpio10</a></li><li>Timing for the Sharp GP2Y10 is very dependant on capacitor value. I suggest graphing the sensor response and picking the highest point of the curve for your individual circuit instead of relaying on the 280 microseconds specified in the datasheet.</li><li>Docker for windows does not boot on startup. <a href="https://stackoverflow.com/q/51252181/1239196" target="_blank">solution on StackOverflow</a></li><li>Accidentally using 3 instead of D3 for a pin operation on the NodeMCU will compile and will hard reset your device each time it is executed.</li><li>Self heating. The NodeMCU produces a surprising amount of heat. With the device in full powered up state the temperature reported was 3 degrees centigrade higher than the true value. To combat this I put the WiFi module into forced power down this reduced the temperature offset to 1 degree which I compensated for in software.</li><li>The Sharp GP2Y10 response values are incredibly noisy. The values bounce around with a standard deviation of at least 3 bits in the 10 bit ADC on the ESP8266. To get around this, I had to collect a lot of samples and apply a <a href="https://en.wikipedia.org/wiki/Gaussian_filter">Gaussian filter</a> </li><li>The Sparkfun library for the HTU21D-F crashes the ESP8266.The Adafruit library works perfectly.</li></ul></div></div>Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com5tag:blogger.com,1999:blog-6650204029311506267.post-13549659000660184952020-09-19T13:23:00.012-07:002020-09-22T20:17:46.925-07:00Zoom like it's 1988 with the Mitsubishi VisiTel<p>
<span style="font-size: large;">W</span>ell here we are in 2020, remote work
is finally here and after decades of marketing by every major
telecommunication company, my mum knows how to make a video call.
Unfortunately this sudden enthusiasm caused unprecedented
<a href="https://www.tomshardware.com/news/logitech-webcam-shortage-update" target="_blank">shortages of webcams</a>. We can't let this slow us down as there are important calls to be made and
I have the solution. Introducing the Mitsubishi VisiTel!
</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSBogZikiiND4hYnCI2EIp-q4_4z0OzbbZfLQvbFnmiX5pf3RXSm_OurNXuhDH-stJpS3AAZIWF8fZ8T31xcTWB7FooSmIUkykF4nL1E9PqZsqNX3mLotznXEifcJC9MkQNJpIDf11pqk/s1200/DSC08053w.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1200" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSBogZikiiND4hYnCI2EIp-q4_4z0OzbbZfLQvbFnmiX5pf3RXSm_OurNXuhDH-stJpS3AAZIWF8fZ8T31xcTWB7FooSmIUkykF4nL1E9PqZsqNX3mLotznXEifcJC9MkQNJpIDf11pqk/w640-h426/DSC08053w.jpg" width="640" /></a>
</div>
<p></p>
<div class="separator" style="clear: both; text-align: center;"><br /></div>
<div class="separator" style="clear: both; text-align: left;">
This definitely was The Future™, and for the low low price of $399 how could
this not catch on immediately?! <a href="https://books.google.com/books?id=HOQDAAAAMBAJ&lpg=PA50&ots=tzSafLrM-K&dq=visitel%20mitsubishi&pg=PA50#v=onepage&q=visitel%20mitsubishi&f=false" target="_blank">Popular Mechanics Feb 1988</a> carried a full page description with a surprising amount of technical
detail. Meanwhile the hosts of Gadget Guru on WSMV asked the most profound
question about video calling within seconds of being introduced to it "Can I
still use the phone without this?".
</div>
<div class="separator" style="clear: both; text-align: center;"><br /></div>
<div class="separator" style="clear: both; text-align: center;">
<style>
.embed-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; } .embed-container iframe, .embed-container object, .embed-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
</style>
<div class="embed-container">
<iframe allowfullscreen="" frameborder="0" src="https://www.youtube.com/embed/sK6x_R3svzk"></iframe>
</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://youtu.be/sK6x_R3svzk?t=777"><span style="font-size: x-small;">https://youtu.be/sK6x_R3svzk?t=777</span></a>
</div>
<p></p>
<p>Well it has taken almost 30 years and a global pandemic, but we finally have
accepted the inevitable fact that we are going to have to take a shower before
talking to our colleagues on the phone. Video telephony is here in
force.
</p>
<p>
I am not the first person to think there is something specially kitsch
about the VisiTel. People have been tinkering around with these for a while
and despite not having motion video, it is one of those products which was
clearly a feat of engineering and massively ahead of its time.
</p>
<p></p>
<p></p>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="BLOG_video_class" height="172" src="https://www.youtube.com/embed/yFwxhc9d3Zc" width="208" youtube-src-id="yFwxhc9d3Zc"></iframe><iframe allowfullscreen="" class="BLOG_video_class" height="172" src="https://www.youtube.com/embed/kJBZP7LrQyc" width="207" youtube-src-id="kJBZP7LrQyc"></iframe><span style="font-size: xx-small;"><iframe allowfullscreen="" class="BLOG_video_class" height="172" src="https://www.youtube.com/embed/3qJ8mOeO27E" width="208" youtube-src-id="3qJ8mOeO27E"></iframe></span>
</div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small; text-align: left;"><a href="https://www.youtube.com/watch?v=yFwxhc9d3Zc " target="_blank">https://www.youtube.com/watch?v=yFwxhc9d3Zc </a></span>
</div>
<div class="separator" style="clear: both; text-align: center;">
<span style="text-align: left;"><span style="font-size: x-small;"><a href="https://www.youtube.com/watch?v=3qJ8mOeO27E">https://www.youtube.com/watch?v=3qJ8mOeO27E</a></span></span>
</div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small; text-align: left;"><a href="https://www.youtube.com/watch?v=kJBZP7LrQyc">https://www.youtube.com/watch?v=kJBZP7LrQyc</a></span>
</div>
<p>
Japhy Riddle's video is what got me really interested in the VisiTel. He
pointed out that by slowing down or speeding up the recording of an image sent
to the VisiTel the image skewed on the screen. Immediately I knew this meant
the device used a simple AM modulation scheme. With that knowledge in hand, I
jumped on eBay and picked up a unit to play with. My goal: to make this
glorious time capsule of late 80s tech work with 2020's work from home
platform of choice, Zoom, so I can chat with my colleagues. Moreover I want to
do this without modifying the hardware because these things are just too cool
to butcher.
</p>
<h3 style="text-align: left;">Step 1: Electrical interfacing</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh29hzxF_QFmFhK3sVjlDHuaf2Xnhm4hB8KTGPtyLMiGcTNBE0X3elfUeRkTwIcXnlWsNOyIwii06oIkDsK4uSobJRuZ8_uBt6mRmAYTKwJLENLhMW8mtm_2k2ty26fQ7a55S8kA-1bDCI/s1526/blog9.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1304" data-original-width="1526" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh29hzxF_QFmFhK3sVjlDHuaf2Xnhm4hB8KTGPtyLMiGcTNBE0X3elfUeRkTwIcXnlWsNOyIwii06oIkDsK4uSobJRuZ8_uBt6mRmAYTKwJLENLhMW8mtm_2k2ty26fQ7a55S8kA-1bDCI/w400-h341/blog9.jpg" width="400" /></a>
</div>
<p>
The VisiTel is extremely easy to set up. On the back of the device is one long
cable with a Y joint near the end (more on this in a minute) and two plugs.
One plug is a 2.1mm DC barrel jack with which the device is powered. It
expects 15 volts center positive. Oddly they chose to write the number 15 on
the device in a font that makes it appear to read "IS Voltage". The second
plug is an RJ11 connector with two of the pins populated. This is the standard
layout for a telephone handset. If you remember corded phones you might also
remember that the receiver was connected to the dialy bit (technical term) by
means of an RJ9 connector and the dialer to the wall with an RJ11 connecter.
The intent being that you could plug other accessories into your dialer, or
replace the receiver | cable if something went wrong. Not that the latter
problem would happen often because telephone handsets used a
<a href="https://en.wikipedia.org/wiki/Tinsel_wire" target="_blank">special kind of wire</a> which is extra flexy.
</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3JCASdBbOMqiP67O_Z5aiT7zXHLI5ODNfK3feo_7Q7Q8Doj13LrLU9-fWqVT1abRI0al-jy_5dwSq1hLTMyjICEA1uIDYUtkFcg4H2lDlja8jYmxvOd1IeWnOLkY16WUbhM9aQESbJOQ/s1097/PXL_20200921_155044634.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="689" data-original-width="1097" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3JCASdBbOMqiP67O_Z5aiT7zXHLI5ODNfK3feo_7Q7Q8Doj13LrLU9-fWqVT1abRI0al-jy_5dwSq1hLTMyjICEA1uIDYUtkFcg4H2lDlja8jYmxvOd1IeWnOLkY16WUbhM9aQESbJOQ/s320/PXL_20200921_155044634.jpg" width="320" /></a>
</div>
<div class="separator" style="clear: both; text-align: center;"><br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitrvQycbuBpR0oOvznj73XM9bXRUdIgJSd9jxszVLyGVmreXn9ORVY0_196_xiBLjrd90UzWjFkqBRjaRgcyBfqLsWahIXOnK_4Grv88FaMDdZZhiBF4b_hGyCNlAQqEHk1JV0oRth8jA/s2048/PXL_20200921_154959242.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1244" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitrvQycbuBpR0oOvznj73XM9bXRUdIgJSd9jxszVLyGVmreXn9ORVY0_196_xiBLjrd90UzWjFkqBRjaRgcyBfqLsWahIXOnK_4Grv88FaMDdZZhiBF4b_hGyCNlAQqEHk1JV0oRth8jA/s320/PXL_20200921_154959242.jpg" width="320" /></a>
</div>
<p>
Returning to the back of the VisiTel, along with the cable there is also a
RJ11 socket. After scratching my head for a while the obvious dawned on me.
The VisiTel is designed to <i>man in the middle</i> your telephone so that it
can listen or transmit whilst you make calls. That leads to an obvious
problem, as the VisiTel unit is sharing the wiring in parallel with the
telephone the user is going to hear images being received and transmitted.
Well the engineers at Mitsubishi thought of that and whenever you receive an
image or transmit one there is a loud click from the device as a relay
disconnects the handset. For our application we aren't interested in listening
to the audio signal, so we aren't going to plug anything into that RJ11 socket
on the back of the device. This makes the isolation relay superfluous meaning
it could be removed for clickless image sending.
</p>
<p>
So how do we communicate with this device? My computer for one doesn't have an
RJ11 socket on it.
<strike>No worries, apparently there is a market for
<a href="https://www.amazon.com/SinLoon-Telephone-Adapter-Female-Headset/dp/B07H873C61/ " target="_blank">adaptors</a> to connect your RJ9 telephone handsets to smartphones.</strike>
Or you can simply snip off the RJ11 connector and solder on a mono 3.5mm jack.
<span style="font-size: x-small;">Note: I originally thought the VisiTel had an RJ9 connector not an
RJ11.</span>
</p>
<p>
With your 3.5mm jack in place connecting couldn't be simpler. Get a USB sound
adaptor with separate microphone and headphone output jacks (not TRRS) and
plug the VisiTel into the appropriate socket.
</p>
<p>
I said that I'd get back to the Y joint on that cable. On my device the wires
in that joint had failed, not a nice solid "it's broken" failure, but one of
those nasty types of failure where everything works when you go to bed and the
next morning it doesn't. If only the VisiTel team had used some of that
special extra flexible wire. This intermittent failure cost me days of staring
blankly at screens, fruitlessly
<a href="https://youtu.be/r1wfa5XPbsE" target="_blank">looking for thermal issues</a>, and triple checking my sound card settings. Eventually I discovered the
failure when in frustration I picked the device up during a test and saw a
crackle of static on my recording. If there is a lesson about old hardware to
be learned here it might be to perform a "jostle" test once you have
everything working and see if anything suddenly doesn't.
</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBxE_PlCylEDMdavLLlDjWOkbwHWz4USNyK6bUET7bSOlRUFYWbCsKmSPDYQx06FAH4YXe2p1v27y1SoeEgKJJXydjljQ7z1sWRw3SlVSUFP3TNNMfjROv0AVBMv_7Zx6rCjr7r7gDFyU/s1357/blog8.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="881" data-original-width="1357" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBxE_PlCylEDMdavLLlDjWOkbwHWz4USNyK6bUET7bSOlRUFYWbCsKmSPDYQx06FAH4YXe2p1v27y1SoeEgKJJXydjljQ7z1sWRw3SlVSUFP3TNNMfjROv0AVBMv_7Zx6rCjr7r7gDFyU/w400-h260/blog8.jpg" width="400" /></a>
</div>
<div class="separator" style="clear: both; text-align: center;"><br /></div>
<h3 style="text-align: left;">Step 2: Understand the protocol</h3>
<div>
Dodgy wires aside now that we have the the hardware interfaced with the
computer it's time to dig into what the protocol looks like. As we can tell
from the videos and articles about the VisiTel, the image is encoded using AM
modulation on an audio frequency carrier. AM stands for
<a href="https://www.electronics-notes.com/articles/radio/modulation/amplitude-modulation-am.php" target="_blank">Amplitude Modulation</a>
and describes the process of encoding information in the amplitude (volume) of
a waveform. Normally it is used to encode audio onto radio waves, however
there is no reason you can't encode images on to radio waves or even images
onto audio waves. <a href="https://medium.com/@nabanita.sarkar/simulating-amplitude-modulation-using-python-6ed03eb4e712" target="_blank">@nabanita.sarkar</a> has a great description of this process with more detail and some
Python example code for people who learn by doing.
</div>
<div><br /></div>
<div>
Knowing the data was AM encoded in the audio domain, the first step was to
record the transcription of some sample images with known properties. To
capture these I used my go application for audio processing
<a href="https://www.audacityteam.org/" target="_blank">Audacity</a>.
</div>
<div><br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx6Ko2x-EIoauAkjnRfITdCcPMqSTsSIgwTdrn0aXoqP0ijWxKVZOUhH4tksZhMn6j2bd3ZVeQqtZdkqXr49x10r11bHBPeHW8EGbUYSe-D4Izw2Ve1IiWx6nOpnHOVVl1rWY_iQKi9SM/" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="810" data-original-width="1800" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx6Ko2x-EIoauAkjnRfITdCcPMqSTsSIgwTdrn0aXoqP0ijWxKVZOUhH4tksZhMn6j2bd3ZVeQqtZdkqXr49x10r11bHBPeHW8EGbUYSe-D4Izw2Ve1IiWx6nOpnHOVVl1rWY_iQKi9SM/w640-h288/image.png" width="640" /></a>
</div>
<br />As you can see above I wanted to validate my understanding of how data
was encoded, so I sent some very simple sample images from the VisiTel. These
were made by holding colored pieces of card in front of the camera one piece
black and one piece white.
</div>
<div><br /></div>
The input image for the trace labeled blackWhiteV looked roughly like this.
<div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMAn5awUXafzz0KdwqnPatpJiaxS5aX3tvmb9GqLDwbTLyacs5MEzJX14qJskTpehzcTxxtssLfLdr2cxx79ItqlyCLNYqMO6sZaLEuxDYOEw4nAlfdNwIQc23pPDlx3_Gz5KNOU-Xcoc/s119/blog3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="119" data-original-width="112" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMAn5awUXafzz0KdwqnPatpJiaxS5aX3tvmb9GqLDwbTLyacs5MEzJX14qJskTpehzcTxxtssLfLdr2cxx79ItqlyCLNYqMO6sZaLEuxDYOEw4nAlfdNwIQc23pPDlx3_Gz5KNOU-Xcoc/s0/blog3.png" /></a>
</div>
<div class="separator" style="clear: both; text-align: center;"><br /></div>
<div>Let us examine the result a little closer</div>
<div><br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbSODlkiD0GCQ4V_i0hjfLOjv9vnLii5pJiWXAuB81ASbumKWVs7bPKEOcsXvGUQAJsLTXUPSxr9YmdEC0lJ6LAO5Ditd7hiKFhv7v7bOHDak96Mg_WRGd0ymi4ilrtjKiWIGkvqWel2M/" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="810" data-original-width="1800" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbSODlkiD0GCQ4V_i0hjfLOjv9vnLii5pJiWXAuB81ASbumKWVs7bPKEOcsXvGUQAJsLTXUPSxr9YmdEC0lJ6LAO5Ditd7hiKFhv7v7bOHDak96Mg_WRGd0ymi4ilrtjKiWIGkvqWel2M/w640-h288/image.png" width="640" /></a>
</div>
<div><br /></div>
<div style="text-align: center;"><audio controls="">
<source src="https://bostwickenator-static-html.s3.amazonaws.com/visitelimage.mp3"></source>
If you cannot see audio controls, your browser does not support the audio element sorry :(
</audio><br />warning loud 1750Hz tone</div>
<br />As you can see, there appears to be some kind of initialization /
header / preamble at the beginning of each image @17.55 to @17.80 in this
example. This allows the receiving device to detect that an image is about
to be sent and determine the maximum amplitude of the signal. This maximum
amplitude is then used as a scale factor during image decoding so that a
lossy quiet phone line doesn't make the images being transferred lose
contrast or brightness. Note: the signal you can see before @17.55 is simply
noise on the line and isn't important for the operation of the VisiTel
protocol.
</div>
<div><br /></div>
<div>
To check that this header establishes an image that is about to be sent, I
played just this small section of audio to the VisiTel and was rewarded with
the sound of the relay clicking on. Clearly this triggers something.
However, when sending just the 30 milliseconds of header the VisiTel seems
to detect that there is no image data being sent and turns the relay back
off a few milliseconds after the header ends. Playing the header and the
first few lines of the image causes the VisiTel to start drawing an image on
the screen. If you stop the audio while an image is being drawn the VisiTel
continues receiving until the image buffer is full. This once again shows
that once the VisiTel is reading pixels it doesn't rely on an external
oscillator to know when to sample data. It has an internal clock source
telling it when to inspect the waveform.
</div>
<div><br /></div>
<div>
As the header simply establishes that a connection is being made and doesn't
need to change along with the image, I didn't feel the need to delve much
deeper into how it works. Knowing that the header establishes a connection
and roughly what it looks like is enough for our purposes.
</div>
<div><br /></div>
<div>
Moving on to the most difficult part, the pixel format. The first step was
to figure out how the pixel data is modulated onto the carrier wave. My
first hunch is that each complete wave represents one pixel. I checked this
by counting the number of waves between repeats of my test pattern. Indeed
it matches what the old advertisements say. 96x96 pixels with a few lines
drawn before the visible image starts.
</div>
<div><br /></div>
<div>
With this we know the amplitude of each wave is sampled and drawn into one
pixel of the digital image buffer contained in the VisiTel. We know from the
marketing material that pixels have 16 shades of grey, however as I am
evaluating pixels from an 'analog' waveform I felt there was no need to
posterize them in my decoding or encoding.
</div>
<div><br /></div>
<div>
Interestingly the pixel brightnesses are inverted before modulation so the
largest waves represent the darkest pixels, they are also mirrored left to
right to give a mirror image. I'd love to know any reader theories on why
the brightness inversion may have been done. My suspicion is that the human
eye is more forgiving of a random black pixel than a random white pixel and
line noise is something which the VisiTel surely had to contend with a lot
back in 1988.
</div>
<div><br /></div>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy6aXKUnW_f8x_I5LAXCk-2H-N1TP2m583lGx9RgOd2Pl0bIxq1DBrKW_gX33MgD8Sn0hmgWCdGdSTX5aoVgF3evJC6Pb3XNPAF2MKS7Anmt_IU3_Tmah6BNXab6QX4Sx7tzZqCFuCUls/" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="810" data-original-width="1800" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy6aXKUnW_f8x_I5LAXCk-2H-N1TP2m583lGx9RgOd2Pl0bIxq1DBrKW_gX33MgD8Sn0hmgWCdGdSTX5aoVgF3evJC6Pb3XNPAF2MKS7Anmt_IU3_Tmah6BNXab6QX4Sx7tzZqCFuCUls/w640-h288/blog4.png" width="640" /></a>
</div>
<div><br /></div>
<div>
There is however an exception to this encoding scheme which eluded me for
weeks. In this inverted encoding scheme, completely white pixels should be
represented as quiescence, no carrier wave should appear on the output at
all. The VisiTel designers seem to have not liked this idea. Instead to
encode a completely white pixel the carrier wave is offset by 1/4 a
wavelength putting it completely out of phase with the wave in the "default"
state. This way the carrier wave can still be sent down the line. At the
receiving end the device receiving this signal is still synchronized with
the "default" waveform and will sample the amplitude right as the wave
passes through the 0 point correctly giving a white pixel. As I previously
mentioned, if the audio is cut off halfway through sending an image the
VisiTel continues drawing white pixels until the frame buffer is full; so
clearly silence can be read as white without the presence of the carrier
wave. I have no idea why the designers decided to complicate their
modulation scheme with this out of phase mode. It seems like a huge amount
of effort to go to for little to no gain.
</div>
<div><br /></div>
<div>
Not having known about this phase shift modulation, my initial approach to
decoding the images involved looking for the maxima of each wave and drawing
that as a pixel. Line steps were emitted after 96 * the number of samples
per wave. This lead to some lines having slightly too many or two few
pixels. Additionally this crude approach was very sensitive to noise as
small spikes in the wave could cause additional pixels to be output. It was
however quite simple to implement and this simple implementation was able to
decode images without having to synchronize clocks. The results
unfortunately just weren't usable.
</div>
<div><br /></div>
<div>
In order to decode images more accurately, we have to do what the VisiTel
does and synchronize with the signal during the header and then continue
sampling at regular intervals after this. As you may expect, this requires
extremely precise timing. For my unit at least when recording at 44100Hz
there are 25.23158 samples per wave (meaning the carrier wave is at
1747.80968929Hz). So each time we read a pixel we set the index of the next
target 25.23158 pixels further into the audio buffer. As we only have audio
samples at integer offsets, we simply round to the nearest sample and take
that one. The key point is we don't allow this rounding error to accumulate
as the sampling position would quickly get out of phase with the wave.
Getting just a little out of phase results in some intense artifacts as
shown below.
</div>
<div><br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn6fNUNctFv7LpN3_4rsQWPLeAffiSMkPfIMbeUdsbbwDSMSfr5XvOMe1Hdo9R1e2XEiJjZupiJumJ8D3kwR9Av0xn2pclOUYE6tAZpSnnV1yv9PE0jlRQex_VewkIYdurxnjMuXmNG8k/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="514" data-original-width="644" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn6fNUNctFv7LpN3_4rsQWPLeAffiSMkPfIMbeUdsbbwDSMSfr5XvOMe1Hdo9R1e2XEiJjZupiJumJ8D3kwR9Av0xn2pclOUYE6tAZpSnnV1yv9PE0jlRQex_VewkIYdurxnjMuXmNG8k/" width="301" /></a>
</div>
</div>
</div>
<div class="separator" style="clear: both; text-align: center;"><br /></div>
<div class="separator" style="clear: both; text-align: left;">
Thankfully this sample per wave value appears to be very stable. It does not
change as the unit warms up which I had been concerned would present an
issue. This invariance allowed me to hardcode a value into the decoding
logic. Ideally the samples per wave value would be derived from the header
data but I found there are not enough samples in order to reach the 5
decimal points of precision with my implementation and the hard coded value
works robustly. With this more accurate implementation line steps are simply
emitted after the draw pixel function has been called 96 times.
</div>
<div class="separator" style="clear: both; text-align: left;"><br /></div>
<div class="separator" style="clear: both; text-align: left;">
Up until now I have been working with pre recorded blocks of audio decoded
from WAV files. In order to operate live and decode images as they are sent
to an audio interface, the decoder needs to be able to detect the header and
calculate where the image data starts. Looking at the header it has three
distinct phases which are easy to detect.
</div>
<div class="separator" style="clear: both; text-align: left;"><br /></div>
</div>
<div class="separator" style="clear: both; text-align: left;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0fcWCN3je529DFYTNvnmGPP7fD0cC-7kP5LZlBfeT5YcpNHDYKX4o6zPONjpWysjjUFSZa3-zsUNpt1JazXgoHyz7xcC77YMklKZy8GlecSZu4HIEyT2JP0yPDVycaA_qdeJ84f54PTM/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="810" data-original-width="1800" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0fcWCN3je529DFYTNvnmGPP7fD0cC-7kP5LZlBfeT5YcpNHDYKX4o6zPONjpWysjjUFSZa3-zsUNpt1JazXgoHyz7xcC77YMklKZy8GlecSZu4HIEyT2JP0yPDVycaA_qdeJ84f54PTM/w640-h288/image.png" width="640" /></a>
</div>
</div>
<div class="separator" style="clear: both; text-align: left;"><br /></div>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: courier;">Carrier wave --> "Silence" --> Carrier wave</span>
</div>
</div>
</blockquote>
<p>
In order to find these I implemented a simple
<a href="https://en.wikipedia.org/wiki/Fast_Fourier_transform" target="_blank">FFT</a> based detector and a finite state machine. First the waveform is
transformed into the frequency domain. The detector then inspects each block
of audio until it finds the carrier a strong signal at 1747Hz. Blocks are then
inspected until the signal disappears and returns again. At this point the
start of a transmission has been found. From here a simple static offset is
used to find the beginning of the image data and the image decoding routines
already discussed are utilized. Once an image has been decoded it is displayed
and the finite state machine is reset in order to listen for the next
transmission.
</p>
<div>
<h3 style="text-align: left;">Step 3: Present the device as a webcam</h3>
<div>
Now that we have managed to decode the images there is one final piece to
this puzzle, presenting the decoded images as video frames to our video
conferencing software. On linux this is surprisingly easy. Video input is
abstracted using the V4L2 interface, unfortunately this still happens in
kernel space. To avoid the complications of making a kernel module you can
use
<a href="https://github.com/umlaeute/v4l2loopback" target="_blank">V4L2 Loopback</a>. This module presents itself as both an input and an output device.
Whatever pixels you publish to it as output it makes available as input for
other programs like Zoom. There are even a few Python packages which further
abstract this to play nicely with OpenCV images and NumPy. Of those packages
I have used <span style="font-family: courier;">pyfakewebcam</span><span style="font-family: inherit;"> for this project. The interface couldn't be </span>simpler. To setup the virtual webcam you do the following:
</div>
</div>
<div><br /></div>
<div>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<div style="text-align: left;">
<span class="pl-k" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #d73a49; font-size: 12px; white-space: pre;">import</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">
</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">pyfakewebcam</span>
</div>
</blockquote>
</div>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<p style="text-align: left;">
<span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">self</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">.</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">camera</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">
</span><span class="pl-c1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #005cc5; font-size: 12px; white-space: pre;">=</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">
</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">pyfakewebcam</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">.</span><span class="pl-v" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #e36209; font-size: 12px; white-space: pre;">FakeWebcam</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">(</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">self</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">.</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">v4l2_device</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">, </span><span class="pl-c1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #005cc5; font-size: 12px; white-space: pre;">640</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">, </span><span class="pl-c1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #005cc5; font-size: 12px; white-space: pre;">480</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">)</span>
</p>
</blockquote>
<p> and whenever a new frame is available :</p>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<p style="text-align: left;">
<span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">self</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">.</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">camera</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">.</span><span class="pl-en" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #6f42c1; font-size: 12px; white-space: pre;">schedule_frame</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">(</span><span class="pl-s1" face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; box-sizing: border-box; color: #24292e; font-size: 12px; white-space: pre;">output</span><span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace" style="background-color: white; color: #24292e; font-size: 12px; white-space: pre;">)</span>
</p>
</blockquote>
<p>
With that simple addition to the decoding program success. Zoom can now
receive images from the VisiTel and we can video chat like it's 1988.
</p>
<div>
<p></p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9XDKPhis9nUN7UnTBTM3UauMoEFY-azOIlODCV1Xw8ooxGFedxD_NB321VZ9eLztLpMs7ETocdLOwPnLVMFw6VmCroqo2K3_NSE24oehLcYXceO6lkpyZi-pb3n27pVjdRD5X0ByqGo8/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="743" data-original-width="1015" height="468" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9XDKPhis9nUN7UnTBTM3UauMoEFY-azOIlODCV1Xw8ooxGFedxD_NB321VZ9eLztLpMs7ETocdLOwPnLVMFw6VmCroqo2K3_NSE24oehLcYXceO6lkpyZi-pb3n27pVjdRD5X0ByqGo8/w640-h468/Screenshot+from+2020-09-17+16-50-06.png" width="640" /></a>
</div>
<p>
Going forward I'd love to setup a linux Direct Rendering Manager driver for
this so that I can output images onto the VisiTel screen as well as
receiving them. For now having the video capture setup and working in Zoom
is enough for me to call this project a success.
</p>
<p>
I hope you enjoyed that write up. Check out the code on GitHub and please
let me know if you setup your own VisiTel webcam <a href="https://github.com/Bostwickenator/VisiTel">https://github.com/Bostwickenator/VisiTel</a><br /><br />
</p>
</div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-25103065099532327932018-03-01T17:04:00.001-08:002018-03-08T12:13:18.190-08:00Reverse Engineering My HeadA few years ago I got my teeth imaged at the dentist. This resulted in two things. My wisdom teeth getting removed and my possession of a medical image viewing tool from <a href="https://www.anatomage.com/" target="_blank">Anatomage</a>. This tool lets you view a single dental <a href="https://en.wikipedia.org/wiki/Cone_beam_computed_tomography" target="_blank">cone beam CT</a> file. The tool ships as a single exe file with a spiffy icon and everything.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUMPlI8LEznGtrIuHrbC56P6scOYvf8gX2kOEOBV9m_hwrtVBc8Jkddc1IXeX_NRGXlcn4xTyvcmC2eBQBzoH6X5xTmByoibcXv2A3LOs8E2GWVhOX2DaZje82M10GOiCL-5n6Iwxk9s4/s1600/Untitled-1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="271" data-original-width="219" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUMPlI8LEznGtrIuHrbC56P6scOYvf8gX2kOEOBV9m_hwrtVBc8Jkddc1IXeX_NRGXlcn4xTyvcmC2eBQBzoH6X5xTmByoibcXv2A3LOs8E2GWVhOX2DaZje82M10GOiCL-5n6Iwxk9s4/s200/Untitled-1.png" width="161" /></a>I was very impressed with the volume visualizations that Anatomage's viewer tool could produce but I wanted more. Not being able to read a file from your own health record with an open source tool didn't strike me as right. So started hacking away at the problem. The first breakthrough is that the Invivo viewer does not memory map part of it's own file directly with the volume data. Instead it extracts that data into your <i>C:\ProgramData\</i> directory as <i>Patient.inv</i> and then loads it from there. A simple copy paste and we have a version of that file to play with.<br />
<br />
Now that we have some data let's figure out what we can about the format. First off I opened <i>Patient.inv</i> up in <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a> which is generally a bad idea for a 70MB file but this showed me that the file started with <a href="https://en.wikipedia.org/wiki/XML" target="_blank">XML</a>. In fact the entire <a href="https://en.wikipedia.org/wiki/Binary_large_object" target="_blank">BLOB</a> of the volume data is included inside the XML. There are also offset values stored in the XML. Presumably the offset values are used to skip the XML parser over binary data to avoid it throwing a fit.<br />
<br />
More good news the XML tells us about the images, their sizes and encodings. However they were all in one large BLOB not one per image. The format specified for the images was <a href="http://fileformats.archiveteam.org/wiki/JPEG_2000_codestream" target="_blank">J2K</a>. This is a stream of <a href="https://en.wikipedia.org/wiki/JPEG_2000" target="_blank">JPEG 2000</a> data without the normal file container around it. I expected that this would mean that I would have to provide metadata to a JPEG 2000 decoder myself however it turns out that the image size is included in the bytestream itself. The only operation needed after some trial and error is to look for the magic bytes at the beginning of each image and chop the file up on those boundaries. This is not a very robust approach and your mileage may vary. With that said for my file it worked. The resulting JPEG 2000 files could then be fed to a decoder. Reading through one of the image files with a <a href="https://en.wikipedia.org/wiki/Hex_editor" target="_blank">hex editor</a> found that they were produced by the <a href="https://www.ece.uvic.ca/~frodo/jasper/" target="_blank">JasPer</a> toolkit. Because of this I decided to choose <a href="http://imagemagick.org/" target="_blank">ImageMagick</a> to decode the images as ImageMagick included JasPer. It turns out that this information is out of date and ImageMagick has swapped to a new library. Luckily this new library handles the JasPer produced files just fine.<br />
<br />
I've created a node script to automate the process of extracting the layers into <a href="https://en.wikipedia.org/wiki/Portable_Network_Graphics" target="_blank">PNG</a> files which you can grab from GitHub <a href="https://github.com/Bostwickenator/InvivoExtractor" target="_blank">here</a>.<br />
<br />
With that done we get exciting images like the one below.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0ZPcz6MFh-8HjyHoiXsZMT64lN2LhuUUmBewqU0AqfmW45o2g5bD_vIOzJsDUKg0oO18qBz_yacHmH97v6TeqlL4UBjja5Itz9mLfHisNd2M4N341ATPWNaLk-cttqg7MXD1A42NGtu8/s1600/axial.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="536" data-original-width="536" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0ZPcz6MFh-8HjyHoiXsZMT64lN2LhuUUmBewqU0AqfmW45o2g5bD_vIOzJsDUKg0oO18qBz_yacHmH97v6TeqlL4UBjja5Itz9mLfHisNd2M4N341ATPWNaLk-cttqg7MXD1A42NGtu8/s400/axial.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A raw PNG file from the stack (exciting right?!)</td></tr>
</tbody></table>
<br />
These images have extremely low contrast but there is data there so now on to creating a 3D model that we can use. At first I was expecting to have to voxalize the data myself. However the Brazilian government came to the rescue with <a href="https://www.cti.gov.br/en/invesalius%C2%A0" target="_blank">InVesalius 3.1</a> an amazing tool for processing medical data. We can simply load our PNG files into InVesalius and use it to produce a STL file. From there we can do just about anything we want with the model.<br />
<span id="goog_1401013803"></span><span id="goog_1401013804"></span><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjFr0xzcgsPHQ1WQxcclo3b3m97TsIMzs8v8qMDlfOtJ1V4VwqykiyzZk0IORE3HhK1JC6dc_x7Fj3pONcWJa3LI1kap1drDqmGa5-Dr1mdHtqwWMKf8GGa2i3I7C6NHSpofNGFyBmpI0/s1600/28161658_10156214846673824_5716542496882191575_o.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1381" data-original-width="1600" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjFr0xzcgsPHQ1WQxcclo3b3m97TsIMzs8v8qMDlfOtJ1V4VwqykiyzZk0IORE3HhK1JC6dc_x7Fj3pONcWJa3LI1kap1drDqmGa5-Dr1mdHtqwWMKf8GGa2i3I7C6NHSpofNGFyBmpI0/s400/28161658_10156214846673824_5716542496882191575_o.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCRMLbHfy1L0tIKt9k2JZbaUo8fgU2fVjQTZCWc68ZyScRx6e503Z8ClOeuh5c_8UUOBMILw9x5SM1lxendxbfkktEdshuYrWZEakcVZlBR0qKb7f5UBvLc2sedfEd0Bm_xOpvHhw5pQg/s1600/IMG_20180301_085703.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1478" data-original-width="1478" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCRMLbHfy1L0tIKt9k2JZbaUo8fgU2fVjQTZCWc68ZyScRx6e503Z8ClOeuh5c_8UUOBMILw9x5SM1lxendxbfkktEdshuYrWZEakcVZlBR0qKb7f5UBvLc2sedfEd0Bm_xOpvHhw5pQg/s400/IMG_20180301_085703.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Spooky Christmas ornament anyone?</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-7863682395704434372017-07-03T17:31:00.000-07:002018-03-08T12:13:34.168-08:00Lomo To GifLomo To Gif is a little tool that I made to process Octomat photos into little gif flipbook like animations. It's super simple and super meh code but it's available on GitHub <a href="https://github.com/Bostwickenator/LomoToGif" target="_blank">here</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Use it in practice <a href="http://lomotogif.s3-website-us-east-1.amazonaws.com/" target="_blank">here</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP9rJoG5R_fKdpBvTnElFawmPObmk9JAzxdiHQ55o4YpZxEogayaLWXI7yFfnwuC_k-8pdgemwoMbJbk5Ia3czwIGliXP6qre0nIAvgcgdgtnlWW7vV39-Dbg2Fb3MGz9LY7IKYYEsFKY/s1600/4e6b90ad-6eca-4113-8566-ece6fc77b8f3.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="95" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP9rJoG5R_fKdpBvTnElFawmPObmk9JAzxdiHQ55o4YpZxEogayaLWXI7yFfnwuC_k-8pdgemwoMbJbk5Ia3czwIGliXP6qre0nIAvgcgdgtnlWW7vV39-Dbg2Fb3MGz9LY7IKYYEsFKY/s1600/4e6b90ad-6eca-4113-8566-ece6fc77b8f3.gif" /></a></div>
<span id="goog_428324342"></span><span id="goog_428324343"></span><br />Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com1tag:blogger.com,1999:blog-6650204029311506267.post-7294507012094571902017-05-11T16:31:00.000-07:002017-05-11T16:31:30.145-07:00Sigma 150-600 Sport Comfort HandleThe Sigma 150-600 Sport lens is a beast at 2.8kg. This makes it very hard to handle handheld and indeed most people will use this lens on a monopod or tripod. I'm more of a run and gun photographer though so I took matters into my own hands, literally. Introducing the Sigma 150-600 Sport Comfort Handle. Now built for humans, you know the things with fingers.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifNbPgV5xhiYgnRjuwy4zb0cRpjAfGInajIp_WEjsSgYT71iyR1a31CqNsQw0t1kmPZJkz0hlXUxAZzDL4FnmMjzMkqRGDaZS111GWJ6TSI1SM-0OVi4507zixDzsbYWbz0EVT1j4x1fE/s1600/grip+v5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifNbPgV5xhiYgnRjuwy4zb0cRpjAfGInajIp_WEjsSgYT71iyR1a31CqNsQw0t1kmPZJkz0hlXUxAZzDL4FnmMjzMkqRGDaZS111GWJ6TSI1SM-0OVi4507zixDzsbYWbz0EVT1j4x1fE/s640/grip+v5.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTT7hJHDf1gsf1p3hPh0KezRjHvyLrH_tSi6MyNpUXC3izXDGLEQQmLJFEsSjRzRUcCbaJw4RKVGKOIyuQiowOahlt59fgZrD8fUmDbCojlii7I6q2KvELrECpneiOOzWqFu7o_4dh0KA/s1600/grip+v51.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTT7hJHDf1gsf1p3hPh0KezRjHvyLrH_tSi6MyNpUXC3izXDGLEQQmLJFEsSjRzRUcCbaJw4RKVGKOIyuQiowOahlt59fgZrD8fUmDbCojlii7I6q2KvELrECpneiOOzWqFu7o_4dh0KA/s640/grip+v51.jpg" width="640" /></a></div>
<br />
<br />
This thing is a pretty large part which would be expensive to print completely solid. If you want to do that however you can buy one on Shapeways <a href="https://www.shapeways.com/product/UR7MNPHAK/sigma-150-600-sport-comfort-handle" target="_blank">here</a>.<br />
<br />
To make a small production run I decided to use a cheap FDM print with low infill to make a mold. This part would not be strong enough to be functional but does a great job of being a positive of the shape. The mold was constructed out of silicone rubber and then a grip was cast with fiberglass reinforced epoxy. The resulting part is EXTREMELY strong and after a coat of paint looks almost exactly like the renders.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHQyUyUYiZjbadc58j103LYbFEDjWTnc1HxptV8v-0r2rc4jCRFcY3FLqFWtmqyB4qJAxao1wuLckzXbwXRySVhaYyWN_Z5ULj0yLz7PDIre-_h4i-o09HK-OB2UGFRhsNllf95aAJhVs/s1600/IMG_20170123_155542.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHQyUyUYiZjbadc58j103LYbFEDjWTnc1HxptV8v-0r2rc4jCRFcY3FLqFWtmqyB4qJAxao1wuLckzXbwXRySVhaYyWN_Z5ULj0yLz7PDIre-_h4i-o09HK-OB2UGFRhsNllf95aAJhVs/s640/IMG_20170123_155542.jpg" width="640" /></a></div>
<br />Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com15tag:blogger.com,1999:blog-6650204029311506267.post-37720522539404830532016-12-20T22:57:00.002-08:002021-04-01T08:32:09.007-07:00Shopping for Frameworks<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; line-height: 22.4px;">
</div>
There is nothing more nerve wracking in a software project than choosing which horse to back, which basket to put your eggs in, and which metaphors to mix. Shopping for frameworks (and it truly is shopping, you are going to spend money) is much like regular shopping. If you get in and out of the store in 10 minutes you've probably not thought through how that jacket is going to match your wardrobe and if you got something cheap you'd better be prepared to stitch the buttons back on. So with no further ado I present my humble advice on the titular topic.<br />
<br />
<h3>
Alex's Framework Wisdom</h3>
<div>
<div style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;">
</div>
<ol>
<li><b>There is no free lunch.</b> You will pay for free frameworks with ongoing development cost working around their oddities and/or contributing upstream. That is to say less CapEx means more OpEx. In the case of subscription licences it's purely OpEx as salaries or as licenses, either way you'll pay.</li>
<li><b>The quality of the vendor is as important as the framework.</b> You are piling your developer hours (your money) on top of these frameworks. The vendor has the ability to kill support at any time and transmute your beautiful codebase into a pile of technical debt with the snap of their fingers. If that worries you, get a contract that stipulates they won't.</li>
<li><b>New isn't automatically better.</b> New languages, new toolchains, new companies. On the surface these may be exciting and they <b>may </b>give you a market edge in some cases. Each one of them is however a double edged sword. These are a lot of companies out there using tried and true technologies because they work and they are known quantities. You should be one of these companies unless there is a pressing market reason that you cannot be. Using new things will make it harder to hire staff. The staff you do hire will create technical debt as they learn what works and what doesn't.</li>
<li><b>Invest in training.</b> When you choose a framework get your development team together to learn about it. It is crucial that this happens as a group. Received wisdom does not work well in the software industry. If all your team learns about something at once it will create homogeneity and accepted best practices. Handing a rulebook to developers will not work well they'll either ignore it or they'll all make disparate readings of it.</li>
</ol>
<br />
<h3>
How to avoid choosing poorly</h3>
<div>
<br />
Congratulations you think you've found just the right combination of lego pieces to solve your business case. Not so fast! Before committing you (and by this I mean <b>not you</b>, I mean your staff) need to take it for a test drive.</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr79cTL457jPNhVUI1ysTJJjtAgof5z6qvsWcFcIFjsq5cvKejwA2rOF1U-Wn1pvqrcU4UAz6qeGMqMxjFj8_uqU2YpAAwXk4UB0PdjoYHUVhj5EN1aC-sA61HYB0Gly4HVlJ-Y1JwckU/s1600/Knight.jpg" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr79cTL457jPNhVUI1ysTJJjtAgof5z6qvsWcFcIFjsq5cvKejwA2rOF1U-Wn1pvqrcU4UAz6qeGMqMxjFj8_uqU2YpAAwXk4UB0PdjoYHUVhj5EN1aC-sA61HYB0Gly4HVlJ-Y1JwckU/s200/Knight.jpg" width="183" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Pooooorly</td></tr>
</tbody></table>
<div>
<ul>
<li>Apply at minimum your own standards. What does the framework's source look like? Is it public? If it's public review it. Makes sure it would pass the standards you set for your own code. If possible try fixing an open bug and getting it accepted upstream. If the framework is closed source you are especially dependent on the vendor. Look at the release notes and review the bug tracker. Make sure things are dealt with in a timely fashion. </li>
<li>Consider the vendor's bus factor (how many of their team could get hit by a bus without impacting their ability to deliver). If it's a small number take this in mind. Will their business model keep them around at least as long as your product?</li>
<li>Check out the debugger. Write something with a bug in it and hand it to a second developer. Their job is to document how the debugging tooling works while they find the bug. Did it run right out of the box or did they have to spend an hour setting up an environment? Does it hit every breakpoint? Are values presented in a useful way? Can it attach to a running process? Plus any other metrics your team might find useful here.</li>
<li>Eyeball the UI. If it has a UI component take it to your UI and branding team. The default themes will not satisfy your business requirements. Get the UI team to specify the changes that will be required and then attempt to implement them. If this is difficult start worrying.</li>
<li>Inspect the toolchain. Does it integrate with your CI setup? Can you make repeatable builds of your code over time. If not what would you have to do to internalize any build dependencies? Does it build in 1 second or 1 hour?</li>
<li>Figure out how to test the end product. Does the framework have interfaces to test tools? Can you write a unit test, a functional test, and an integration test? Are the tests stable? If the framework has a UI component can you automate the UI testing or will you be paying people to click buttons?</li>
<li>Consider reuse. Is the code you write in the framework coupled to it? Will you be able to take code from it to other places in your business? Will you be able to bring code into it?</li>
</ul>
<div>
These are just some high level acid test questions you should be asking yourself when you are looking at a framework. Please take into consideration any other factors important to your staff and your business case.</div>
</div>
<h3>
<a href="https://i.imgur.com/Yl48tQw.jpg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://i.imgur.com/Yl48tQw.jpg" width="243" /></a></h3>
<h3>
</h3>
<h3>
Case study; Death by 1000 cuts (or Appcelerator Titanium)</h3>
<div>
The small issues hurt. It is not the big problems that make you regret your choices. It is the day to day grind. The subtle bug that no one suspected and no one documented. It is the lost hours in every week that your staff could have been doing something that generates revenue. See wisdom #1. Trivial hindrances also create morale issues. Monotonous and frustrating work will demoralize a group of people who typically pride themselves on doing new, interesting, and challenging things. Nothing is less rewarding that realizing you lost your day to a missing semicolon.<br />
<br />
Below are replies to some issues I have personally raised against a particularly hodgepodge framework known as Appcelerator Titanium. They are prime examples of the kind of bugs that will decimate your productivity should they occur with regularity. Also note these aren't even bugs with the framework these are bugs with the associated toolchain, remember to investigate the whole package you are buying into.</div>
<div>
<br /></div>
<div>
<hr />
<a href="https://github.com/appcelerator/titanium/issues/243" target="_blank">https://github.com/appcelerator/titanium/issues/243</a><br />
<br />
<i>It's a little complicated. The available Titanium SDK releases depends on if you're using ti sdk vs appc ti sdk. appc ti sdk shows the latest and greatest SDKs. ti sdk shows the latest release before the switch from the Titanium CLI to the Appcelerator CLI.</i><br />
<i><br /></i>
<i>The list of releases for the Titanium CLI is no longer automatically updated, but rather it's a manual process. Because we haven't determined which past releases should be available to ti sdk, we simply haven't updated the release list.</i><br />
<i><br /></i>
<i>However, the list of releases that appc ti sdk reference is automatically updated and current, so I advise you just use appc ti sdk for now.</i></div>
<div>
<br /></div>
<div>
<b>Time lost: 1 hour</b><br />
<br />
<hr />
<a href="https://github.com/appcelerator/titanium/issues/244" target="_blank">https://github.com/appcelerator/titanium/issues/244</a><br />
<br />
<i>Smart quotes are not valid in XML. I wonder what the XML parser library is doing. I wouldn't be surprised if the platform was being parsed as "“iphone”". I don't think we should naively replace all smart quotes with ascii quotes and properly scrubbing the smart quotes is more effort than it's worth. In other words, I don't think we're going to improve this.</i></div>
</div>
<div>
<br /></div>
<div>
<b>Time lost: Half day</b><br />
<br />
<hr />
<br />
Trivial issues like the ones above and dozens more will slow your development process and make your project management unpredictable. This has a real fiscal impact. If a developer has a high chance of running into a framework bug or a hidden issue they will not be able to provide accurate estimates of effort to management. Without accurate estimates you will either miss release dates and stress your employees trying to make back time or have long release cycles and lose agility. Neither of these is going to help you make money.<br />
<br />
<h3>
Conclusions </h3>
<div>
<br /></div>
<div>
You never know everything about the ship you are getting on board. With that said a few sanity checks may save you <a href="https://en.wikipedia.org/wiki/Imperial_Trans-Antarctic_Expedition#Drift_of_Endurance" target="_blank">months of rowing back to shore</a> or having to listen to an 8 piece band <a href="https://en.wikipedia.org/wiki/Musicians_of_the_RMS_Titanic" target="_blank">play you out</a>. Spend the time up front to get an idea of what is going on, trust the people who will be doing the day to day work, and remember <b>nothing is free</b>.</div>
<br /></div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com1tag:blogger.com,1999:blog-6650204029311506267.post-19680776895252128992016-12-19T20:32:00.001-08:002016-12-20T23:14:53.513-08:00Oven Fresh Nexus 5XWoe and calamity. Yes, I got the dreaded Nexus 5X bootloop issue a couple of weeks back. Having thrown my phone in the freezer (inside a zip-lock bag) I got a boot out of it. That points to the issue being a bad solder joint. Maybe not in the general case but in at least mine. If your device passes a similar test you can try <a href="https://en.wikipedia.org/wiki/Reflow_soldering" target="_blank">reflow soldering</a> your device by following along below. <b>Warning: this process will void any warranty you have, only do this as a method of last resort if Google or LG will not service your phone. You may also want to consider taking it to a professional electronics repair shop for reflow work.</b><br />
<br />
With that warning out of the way and the freezer test having roused my suspicions I pulled the case off and took the motherboard out. iFixit has a great guide <a href="https://www.ifixit.com/Guide/Nexus+5X+Motherboard+Replacement/60278" target="_blank">here</a> for that process.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="clear: right; float: left; margin-bottom: 1em; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiucKx47_NexkOjHd3Za5kE_ikOftor8R4qyZNsaefriyL28BkgOoH2kIEn9cpADqWFQgb3AMdL_KNLI9jAuIgNkiwZjJc6yzZ28I-r_jFaL5fCZZQICtM3wCyyABXDzlw06pGZ-TRl6IE/s1600/IMG_20161218_205932-01.jpeg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiucKx47_NexkOjHd3Za5kE_ikOftor8R4qyZNsaefriyL28BkgOoH2kIEn9cpADqWFQgb3AMdL_KNLI9jAuIgNkiwZjJc6yzZ28I-r_jFaL5fCZZQICtM3wCyyABXDzlw06pGZ-TRl6IE/s400/IMG_20161218_205932-01.jpeg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Time to cook!</td></tr>
</tbody></table>
With the motherboard out I inspected the <a href="https://www.ifixit.com/Teardown/Nexus+5X+Teardown/51318" target="_blank">teardown photos</a> also provided by iFixit and determined which side of the board the packages (chips/black squares) I was interested in were on. The suspect package is the RAM. A Samsung <a href="http://www.samsung.com/semiconductor/products/dram/mobile-dram/K3QF3F30BM-FGCF">K3QF3F30BM-QGCF</a> with CPU the Qualcomm <a href="https://www.qualcomm.com/products/snapdragon/processors/808">Snapdragon 808</a> conveniently located directly beneath it. The constant flexing of the phone in my pocket has most likely cracked one of the tiny BGA solder connectors off the motherboard underneath one of those packages.<br />
<br />
Now that you have your motherboard separated from the phone's chassis preheat your oven to 195 degrees Celsius or 390 Fahrenheit whichever is appropriate for your current locale setting. While your oven is heating take out some aluminum foil and crush it into a ball. Un-crumple it so that there is still a rough texture as shown. This is going to help limit the heat transmission to the underside of the motherboard which we don't want to reflow. Place the motherboard on the foil and press it down. At this point attempt to get the board laying as flat as possible. You don't want parts sliding down the board on an angle if you overcook. Place the foil and motherboard on an oven safe cooking surface, a ceramic casserole dish will do nicely so long as it has a flat bottom, I used the spill tray from a waffle iron. So pick whatever looks good to you. <strike>Season with a twist of lemon and cracked pepper.</strike><br />
<strike><br /></strike>
Now that your oven is up to temperature place the dish into the oven and start a timer for 6 minutes and 30 seconds. Wait anxiously. <i>Note: If your oven is fan forced you may need to make an adjustment to the cooking time.</i><br />
<br />
Remove your motherboard and let it rest until completely cool. Inspect the board for any physical damage, if you've really messed it up be extremely careful with reconnecting the battery. Who knows what you might have shorted out.<br />
<br />
Reassemble your phone following the guide from iFixit and give that puppy a charge. Power it up and hope for the best!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF8ERcbTxmrixEOcxCFgHqR4_czFIEft16o5edkT0ynW7YB8AWUJfcGko2waMizJCcJ52Hc4swUXR_ZVEqyIiUQ11iGLnt41T7jvlflVumUfT2lgErYgQyMLcdpfX1nGoDmFnfE6Nkz-c/s1600/IMG_20161219_083555+%25281%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF8ERcbTxmrixEOcxCFgHqR4_czFIEft16o5edkT0ynW7YB8AWUJfcGko2waMizJCcJ52Hc4swUXR_ZVEqyIiUQ11iGLnt41T7jvlflVumUfT2lgErYgQyMLcdpfX1nGoDmFnfE6Nkz-c/s400/IMG_20161219_083555+%25281%2529.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com93tag:blogger.com,1999:blog-6650204029311506267.post-66313435119349846742016-07-15T21:21:00.000-07:002016-07-15T21:21:11.405-07:00Minolta 7000 Battery Upgrade MK2So my last post was about building a replacement battery pack for the Minolta 7000. Since then I had a much higher quality 3D print made of the housing with some lessons learnt from the first version. This is the result.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4jNnoSmZGJWwQf8v9hGN6RuWfOTfxVqnP4SO7hGoBQqQ8MjqsbrxKYjhnsw3LQ3TLAOEAuBl0blo8rirTex1-twYH_Ifrv-J84uuLuQc2O3n1nbJMOJN_1jS5GFFOhfMoOxtwdr8aimw/s1600/IMG_20160714_234027-01.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4jNnoSmZGJWwQf8v9hGN6RuWfOTfxVqnP4SO7hGoBQqQ8MjqsbrxKYjhnsw3LQ3TLAOEAuBl0blo8rirTex1-twYH_Ifrv-J84uuLuQc2O3n1nbJMOJN_1jS5GFFOhfMoOxtwdr8aimw/s640/IMG_20160714_234027-01.jpeg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This part was ordered from Shapeways and I'm quickly learning that they are so far ahead in this game that you should just go to them straight away. Incidentally you can <a href="https://www.shapeways.com/product/75VZWQ6NM/minolta-7000-lipo-battery-holder" target="_blank">buy this part</a> from there if you want to build this.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Need some help building that? Well tough luck! I present to you the world's worst build log. Seriously everything that could go wrong with this video went wrong. I don't think I even build a single thing on camera.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/PIaMd5p_KQA/0.jpg" frameborder="0" height="360" src="https://www.youtube.com/embed/PIaMd5p_KQA?feature=player_embedded" width="640"></iframe><br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So I might not be a videographer but you have to admit the end product looks pretty nice.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<span id="goog_1667303063"></span><span id="goog_1667303064"></span><br />Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-77458633361558325112016-05-23T21:57:00.002-07:002016-05-24T06:44:34.652-07:00Minolta 7000 Battery Upgrade<div class="separator" style="clear: both; text-align: left;">
Say you've got one of these <a href="http://www.mir.com.my/rb/photography/hardwares/classics/maxxum7k/spec.htm">Minolta 7000</a> cameras. Great camera. Just one problem. Whenever you pick it up the batteries are flat. You've lined up your shot, you press the shutter button, the mirror flips up and nothing happens. </div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV-0iFBLUeLye-mj-eXJynhXy8EjFiP3z3EtOh5H5h6AipRl-jGRyQQN5XZJXjkBEzNElHNWk_9LijPkMTZqjdLWzO8wGUUqauuVIp3tbIN0Z8RwqKrhkrLiHo5wP6RV7o_g-Npj3sohw/s1600/_DSC6940.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="425" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV-0iFBLUeLye-mj-eXJynhXy8EjFiP3z3EtOh5H5h6AipRl-jGRyQQN5XZJXjkBEzNElHNWk_9LijPkMTZqjdLWzO8wGUUqauuVIp3tbIN0Z8RwqKrhkrLiHo5wP6RV7o_g-Npj3sohw/s640/_DSC6940.jpg" width="640" /></a></div>
<br />
What you need is something a little more reliable than these original battery grips. T<span style="text-align: center;">he piles of dead AAA and AA batteries get a little annoying after a while. </span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin9jIlw2SfUXIs-GMKRjrVal84ygWUFzGoYNn5fYS2jJoiiiIN6cj-tcUqJInCVJnQqSOoY8CHOAs6dPgVDl00JoFVYvGw-z38uVNMnyPMuWAM8ZXfZvZe_twi_k3gcWdzS8dhEibx1AA/s1600/_DSC6928.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="425" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin9jIlw2SfUXIs-GMKRjrVal84ygWUFzGoYNn5fYS2jJoiiiIN6cj-tcUqJInCVJnQqSOoY8CHOAs6dPgVDl00JoFVYvGw-z38uVNMnyPMuWAM8ZXfZvZe_twi_k3gcWdzS8dhEibx1AA/s640/_DSC6928.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGQUJEUY8mZtNx30hOsnD2XxSmdNTP-6BeyCrkf7J3p24wlIZeRFmSVBMp2tXDXuuJzX26DCTUfg_RLvOLH2lJF7AxWzGA2LvBNAP-CHN3a-qSAr_Y8M0BkLKQTVKTVAxl6VCYC_aBaNk/s1600/_DSC6929.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGQUJEUY8mZtNx30hOsnD2XxSmdNTP-6BeyCrkf7J3p24wlIZeRFmSVBMp2tXDXuuJzX26DCTUfg_RLvOLH2lJF7AxWzGA2LvBNAP-CHN3a-qSAr_Y8M0BkLKQTVKTVAxl6VCYC_aBaNk/s640/_DSC6929.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The solution as I see it is having a rechargeable battery with a built in charge controller. This means the camera can constantly sit on power while it is at home. Always 100% charged ready to run a few rolls of film. Luckily the engineers at Minolta made this battery pack design very modular and with quite a simple electrical interface. First order of business is to model the battery holder so that we don't have to destroy an original part. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaUSchBzQIaNN1YdHDnkDPTJBlu3JjE8OMV_H6CDKtDGEY7Y2bsXivG0gjIZzWY-FPINXP7O2gzqQ1d9uh9NSRO5qh6yoHkzgmtjeDQ21QRzbUTR8cucTtgzj0zzzh2Nqu4ztXRyUz-84/s1600/grip.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="542" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaUSchBzQIaNN1YdHDnkDPTJBlu3JjE8OMV_H6CDKtDGEY7Y2bsXivG0gjIZzWY-FPINXP7O2gzqQ1d9uh9NSRO5qh6yoHkzgmtjeDQ21QRzbUTR8cucTtgzj0zzzh2Nqu4ztXRyUz-84/s640/grip.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can note the that this design doesn't have any ports or holes. This was because it was being produced before I had the rest of the components in hand. Speaking of components these are the parts that you need:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul>
<li><a href="http://www.dx.com/p/tp4056-4-2w-1-2a-5v-lithium-battery-charging-discharging-protection-module-w-micro-usb-blue-397213">TP4056 based charge controller</a></li>
<li><a href="http://www.dx.com/p/502030-240mah-rechargeable-polymer-li-ion-battery-silver-227107">A lithium battery</a> (This one fits easily)</li>
<li>A couple of 3mm LEDs <a href="http://www.dx.com/p/diy-3mm-led-light-emitting-diode-set-red-yellow-green-30pcs-426866">why not buy 30!</a></li>
<li>Some brass rod to make your contacts. Springs would be even better but good luck buying two of those for anything less than $10. I cant justify that to myself somehow.</li>
<li>And finally some jumper wire for connecting everything up.</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyKp0MuIh8FGL06NU4YLzeJorIMkiMpIOkUd2_HM5RHGSE1zSp-DHgYpup8jqYAivM3j4mLPezregMtR_kRCOd77pzVLLbOdD-MsdJJB0Wx-4z6rROq21fsgsnFIniA3fCm_8tOvc3-Ts/s1600/_DSC6938.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyKp0MuIh8FGL06NU4YLzeJorIMkiMpIOkUd2_HM5RHGSE1zSp-DHgYpup8jqYAivM3j4mLPezregMtR_kRCOd77pzVLLbOdD-MsdJJB0Wx-4z6rROq21fsgsnFIniA3fCm_8tOvc3-Ts/s640/_DSC6938.jpg" width="640" /></a></div>
<div class="" style="clear: both; text-align: left;">
<br /></div>
<div class="" style="clear: both; text-align: left;">
Implementation time! It is a really simple setup. Simply solder the battery to the appropriate terminals. Desolder the existing LEDs from the PCB and replace them with the new 3mm ones. I used the jumper wire to make a flexible connection here. Now drill and rasp out the holes in a spot that you like. The top side of the new battery grip makes the most sense because the camera can sit flat while you are charging it and your hands won't come in contact with the ports while you use the camera.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0iMfyH92l_tXU2IK9YEjVXSkNPCFoz8tFtLssbSKEPkUYfEZysrsuMh7YTvqwEkoabSxWvVbVki-VFnG_1JpJAAOYx8-soi8Z5BKxis7aTpFgXfnBDL56UuEHC_osY8VVkgef6qAw_F0/s1600/IMG_20160523_232353.jpg" imageanchor="1"><img border="0" height="385" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0iMfyH92l_tXU2IK9YEjVXSkNPCFoz8tFtLssbSKEPkUYfEZysrsuMh7YTvqwEkoabSxWvVbVki-VFnG_1JpJAAOYx8-soi8Z5BKxis7aTpFgXfnBDL56UuEHC_osY8VVkgef6qAw_F0/s400/IMG_20160523_232353.jpg" width="400" /></a></div>
Here is the result of this build out. I've filled a lot of the grip with Sugru. This fixes the components in place extremely solidly. This is particularly important for the charge controller as it has to stand up to the force of repeated USB connection and disconnection cycles. The Sugru was also used to fill up void space from the imperfect fit of the part. If you want to do this simply brush vegetable oil onto the side of the void you want to fill attach the Sugru to the other part and press both sides together until they mate the way you want them to.<br />
<br />
One thing to note is the green pin. I originally missed this part. It is used to separate the memory backup battery inside the camera from the circuit when the battery pack is connected. Forgetting this will cause your battery to attempt to charge this little 3V lithium cell which could go badly. Another option is simply to take the backup cell out since you wont need to detach the new battery grip ever again. Luckily the new grip looks much better on the camera than it looks inside.<br />
<br /></div>
<div class="" style="clear: both; text-align: left;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW2RSEEOchakLfBLeCs0MPUy2-7JNrMAPl6p2eGacvAiJuGlwEpTarreWB39pp6uYKZJSAdtFUu9zQkIS1vXGc4sWg5gRWGog3Rmr_kqs9-DdDjdEcp2oUo7ELzk9qNV2Z8jgFraxEtD8/s1600/_DSC6922.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW2RSEEOchakLfBLeCs0MPUy2-7JNrMAPl6p2eGacvAiJuGlwEpTarreWB39pp6uYKZJSAdtFUu9zQkIS1vXGc4sWg5gRWGog3Rmr_kqs9-DdDjdEcp2oUo7ELzk9qNV2Z8jgFraxEtD8/s640/_DSC6922.jpg" width="640" /></a></div>
<br />
<br />
<br /></div>
<div class="" style="clear: both; text-align: left;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn1GTJJg41Ns5Z4IXPaHUEnYKYVUNjm-7Mw82ut4sL1KgGGIj_0IGNpTNW5h18kPi9nmHlrtyoImKn6wdJQpCgj33-R99CN7rXLGEN0czfwEmt7ICaPomDa6To9NAieDSqeWnS-l6kWcI/s1600/_DSC6926.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn1GTJJg41Ns5Z4IXPaHUEnYKYVUNjm-7Mw82ut4sL1KgGGIj_0IGNpTNW5h18kPi9nmHlrtyoImKn6wdJQpCgj33-R99CN7rXLGEN0czfwEmt7ICaPomDa6To9NAieDSqeWnS-l6kWcI/s640/_DSC6926.jpg" width="640" /></a></div>
<br />
Of course there were a few lessons learned along the path of this build.<br />
<br />
For a start voltage wise the camera will accept 4.1V and nothing lower. Below this point it automatically shuts down when you press the shutter button. This was tested on a beefy bench power supply so it's not the battery that causes this behavior. The camera draws about 1.1 amps during it's shutter actuation and frame winding. This load is for a roughly 200 milliseconds. It then returns to it's quiescent draw which is very low. Oh and before I forget the metering system and the LED backlight for the viewfinder together draw around 300mA when they are on. The AF motor also draws around 1 amp.</div>
<div class="" style="clear: both; text-align: left;">
<br /></div>
<div class="" style="clear: both; text-align: left;">
<div style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em; text-align: center;">
<img src="http://www.mpoweruk.com/images/discharge-chemistry.gif" /> </div>
On the topic of current you need to make sure that your battery and current protection circuit will supply just over an amp to the camera at peak load without tripping a short protection feature. This makes small AAA size cells with inbuilt protection a bad choice.<br />
<br />
Earlier I said the camera only accepts >4.1V with the factory manual suggesting a max voltage of 6V be applied to the camera. So how does it work on a LiPo battery, don't they have a voltage of 3.7V? Well not quite they have a nominal voltage of 3.7V their discharge curve is shown to the right. Luckily for this project it starts at 4.2V. Clearly it drops very quickly to the nominal voltage under discharge. However we are using so little of the battery's capacity this is not an issue in practice.<br />
<br />
One thing I learned a particularly hard way about the Minolta 7000 is that they have an internal fuse. The fuse is located inside the hand grip hidden under a film of tape and is formed by a PCB holding a single strand of fuse wire. There is a diode setup to short circuit the battery across this fuse if the polarity is reversed by accident. It's quite a smart setup because in the normal mode of operation you aren't incurring any losses. So if you aren't getting any response from one of these cameras it is a good thing to check before disassembling the entire thing like I did. You can access it by removing a few screws at the bottom of the body and a few inside the front of the grip.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-15959546203038793722016-05-05T17:29:00.000-07:002016-05-05T19:23:38.240-07:003D Printing Round One I've recently gotten excited about the use of 3D printing. Maybe I'm late to the game because the cost of entry outside the USA is much higher. Maybe because I have good luck building things the old fashioned way most of the time.<br />
<br />
Anyway 3D printing or maybe more accurately additive manufacturing is an amazing technology. You can produce complex shapes for practically the same price as a solid block of material. <b>That </b>is the magic thing about it. If you make a more complicated part with less material the price comes down. I've automatically been in the mindset that the more geometrically complex a part the more work goes into producing it. That just isn't true anymore.<br />
<br />
Of course the other thing that 3D printing is enabling is personalized design and low volume production runs that wouldn't be worth doing using traditional systems. For instance I purchased a camera clip (reviewed below) which wasn't in my opinion up to the job it was designed for. The reason? A single part made with too poor a tolerance.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/NB_VwOsfr6Q/0.jpg" frameborder="0" src="https://www.youtube.com/embed/NB_VwOsfr6Q?feature=player_embedded" height="400" width="640"></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Previously I would have either thrown this out or tried to solder together a replacement part myself. Instead I decided to finally learn how to use a CAD package with some degree of confidence. So I pulled down a copy of <a href="http://www.123dapp.com/design">123Design</a> and got cracking. A couple of hours later I had this</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ1wwgiFb_L6Yr7Lg-BeXuZKZvpBhNU4c3YFvf_GmQRrYJc3iSnH6vsq5ZXM4XLayszdfp-fq0VhxsFPGMP-TZBEsCQ1MNKh7ymhrhX3LI2rZNYZQ3vIVeF3ELAI2wOHYdOttgWDqYgZo/s1600/pin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ1wwgiFb_L6Yr7Lg-BeXuZKZvpBhNU4c3YFvf_GmQRrYJc3iSnH6vsq5ZXM4XLayszdfp-fq0VhxsFPGMP-TZBEsCQ1MNKh7ymhrhX3LI2rZNYZQ3vIVeF3ELAI2wOHYdOttgWDqYgZo/s640/pin.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Not that much to look at but it seems about right. Oh and I should say I measured the original part with this.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsjpfihyC0esof6c9yb2Um0e7RkuWQTnKXvqenx-Mk12sTd0Yt5Z4qRrJ0-HMOFPz_W5L4Prn5VXUaOuiDMUgdScZorgPjCoznQ4CezuaXhCZWYvw5h_3Gtc3MnWYd9qOD-kFeIyWaWPY/s1600/IMG_20160505_184458.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="459" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsjpfihyC0esof6c9yb2Um0e7RkuWQTnKXvqenx-Mk12sTd0Yt5Z4qRrJ0-HMOFPz_W5L4Prn5VXUaOuiDMUgdScZorgPjCoznQ4CezuaXhCZWYvw5h_3Gtc3MnWYd9qOD-kFeIyWaWPY/s640/IMG_20160505_184458.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So based on those shaky measurements and some guessing that people probably make things in integer numbers of millimeters I pushed the model file off to and <a href="https://www.shapeways.com/">Shapeways</a> & <a href="https://www.3dhubs.com/">3D Hubs</a>. You can actually do this with a couple of clicks right out of 123Design which is very much appreciated. Two weeks and one week later respectively I had the following parts on my table. The original in the lovely blue on the left and three of the replacements on the right. Obviously the stand out part is the bronze infused stainless steel. It's incredibly tough. You could make just about anything out of this material. One word of warning. It's difficult to post process. The bronze fouls your cutting tools and the steel has a very high temper on it. Maybe this should be the new standard for bike locks? </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCefwARZGsRY_zLbiFmhdrXU01cHagGc5F9juAEs0QJKZ-VDSNHJ4uMaDl85onGuGgcjHgWHqTGw3S8ugXjhFYy9NhOWYNreAEB3DKNWrb75Uvri2iO3X1LMHiUqyXFk2Ws0MryrTwpVQ/s1600/IMG_20160418_174033.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="467" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCefwARZGsRY_zLbiFmhdrXU01cHagGc5F9juAEs0QJKZ-VDSNHJ4uMaDl85onGuGgcjHgWHqTGw3S8ugXjhFYy9NhOWYNreAEB3DKNWrb75Uvri2iO3X1LMHiUqyXFk2Ws0MryrTwpVQ/s640/IMG_20160418_174033.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
This is how the new part looks in situ. Pity about it clashing with their colour scheme.<br />
<br />
<div style="text-align: center;">
<img height="475" src="https://images3.sw-cdn.net/product/picture/625x465_14143132_8666347_1461894843.jpg" width="640" /></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Here it is securing my rather heavy camera. Far more trustworthy than the plastic part!</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZWAMUt1hGLZgmoGdGNJb-vkjMh7xn79DVqrkRYgkP3FP0DIidYHds3oWVFKzWnnVQZuFfNj5CSV7DQTSa5qfZrhF10CuIx4PYasetJ8KzyrVP2PgGNPIvBI2PzvYwOOA6W1R9ddqLWbE/s1600/IMG_20160418_183328.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZWAMUt1hGLZgmoGdGNJb-vkjMh7xn79DVqrkRYgkP3FP0DIidYHds3oWVFKzWnnVQZuFfNj5CSV7DQTSa5qfZrhF10CuIx4PYasetJ8KzyrVP2PgGNPIvBI2PzvYwOOA6W1R9ddqLWbE/s400/IMG_20160418_183328.jpg" width="297" /></a></div>
</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Now the part that I find the coolest. If you happen to want this incredibly obscure part you can just go <a href="https://www.shapeways.com/product/62RZ4LUE3/pin-plus-v2">here</a> and have one run off the printers at Shapeways for you. In fact two people have already done that. Isn't that cool? Yes. yes it is.</div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com1tag:blogger.com,1999:blog-6650204029311506267.post-84451054758018027182016-04-26T22:24:00.000-07:002016-04-26T22:27:10.272-07:00OpenMemories DoF<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/YQvnrjohLt4/0.jpg" frameborder="0" height="338px" src="https://www.youtube.com/embed/YQvnrjohLt4?feature=player_embedded" width="600px"></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
A quick (and ugly) sample app doing something slightly useful using the OpenMemories-Framework <a href="https://github.com/ma1co/OpenMemories-Framework">https://github.com/ma1co/OpenMemories-Framework</a><br />
<br />
APK available here <a href="https://github.com/Bostwickenator/dof-math/releases/tag/1.0">https://github.com/Bostwickenator/dof-math/releases/tag/1.0</a><br />
<br />
Amazing work everyone involved!Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com3tag:blogger.com,1999:blog-6650204029311506267.post-11373936001212275082016-04-02T10:01:00.002-07:002016-04-07T03:06:12.698-07:00IoHeating Part 2Last time we built an internet connected heater with a REST interface. Being able to control anything physical from a web browser is cool. Being able to control it from your phone is much cooler.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3fDWocTtmjmRVp-qfyEWkoLgUKwGC6j9p2gYw6MroqxDhTvpHDLBQpQLNVRvKn47TgY3h-30DgMe26_MopHO0-d2du0Zv76GhWt-wWy7_yS6lt_hDQys5YbyTctroMtX4Qym5cUgmJlI/s1600/screenshot+%25281%2529_framed.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3fDWocTtmjmRVp-qfyEWkoLgUKwGC6j9p2gYw6MroqxDhTvpHDLBQpQLNVRvKn47TgY3h-30DgMe26_MopHO0-d2du0Zv76GhWt-wWy7_yS6lt_hDQys5YbyTctroMtX4Qym5cUgmJlI/s640/screenshot+%25281%2529_framed.png" width="372" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Something like this</td></tr>
</tbody></table>
<br />This post is about doing that. Let us not waste any time. Open up a copy of <a href="https://github.com/Bostwickenator/SmartHeater" target="_blank">the GitHub repo</a>. Even better pull it and open it in <a href="http://developer.android.com/tools/studio/index.html" target="_blank">Android Studio</a><div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlgu-8B9LWUcPuORhYloJtFqDCU6bDB7TksOjUSaWL2TUmveIT1NzarzsR8TwmQ5oR7HsFHCJ6owGRQY4bWHYhvDXq7KMdKkffnimkiZKrh4yuOlQzbCUdiYJiPfj4DxGRP0ruI2rSvMU/s1600/Android+studio.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="475" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlgu-8B9LWUcPuORhYloJtFqDCU6bDB7TksOjUSaWL2TUmveIT1NzarzsR8TwmQ5oR7HsFHCJ6owGRQY4bWHYhvDXq7KMdKkffnimkiZKrh4yuOlQzbCUdiYJiPfj4DxGRP0ruI2rSvMU/s640/Android+studio.png" width="640" /></a></div>
<div>
<br /></div>
<div>
The core of this application is the communication with the Particle.io device via their API. What I have chosen here is a compromise for time. We aren't using the normal method of authentication that you would take if you are releasing a product to a consumer market. Simply we are taking our credentials and building them into the application package. This means anyone who has access to that application package can control your device. You've been warned. On the positive side of this trade off the code is really easy to understand and doesn't require a lot of interactions with authentication APIs. </div>
<div>
<br /></div>
<div>
The system we are using here is <a href="http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html" target="_blank">Bearer Authentication</a> and part of OAuth2.0 spec. Conceptually it is a simple two part process. Firstly you the user authenticate to a server. You then say to the server. Give me a secret so big that no one can guess it. This secret is understood by the server to mean (since no one can guess it) that any other actor (program in our case) that knows the secret is authorized by you to do things on your behalf. The second step is exactly that you give a program the secret and it talks to the server to do work for you. We are simply breaking this up and doing the first step in our development environment so that we don't need to write a UI for it in our application. Particle has a detailed <a href="https://docs.particle.io/guide/how-to-build-a-product/authentication/" target="_blank">write up</a> of how OAuth2,.0 works should you be interested. </div>
<div>
<br /></div>
<div>
If you haven't already you need to setup the <a href="https://docs.particle.io/guide/tools-and-features/cli/photon/" target="_blank">Particle.io command line interface</a>. Then from the CLI you can use the command. </div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">particle token new</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
to generate a token for your application.</div>
<div>
<br /></div>
<div>
There is a second slightly hacky method you can use to obtain a token which is pulling one out of the Particle build system. Open it up and navigate to the settings screen. You should see a token in place of the red square below. This has the advantage (and security issue) that it will not expire. You can also generate longer lived tokens using curl and performing REST calls to the Particle servers. </div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpTIhatdv7ABGQ3hRtzLjCbqM_b3d1VH90PRRRKtJlGP1EzyAzeuKCq76nyGA7ytOSYSlghNdrz27-TRRc7TB35Ty2G_q-NKlt5qM1R398zzkyIMg9poxk5pH1Vlz4oJ3Ab6B2J-W059k/s1600/dev.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpTIhatdv7ABGQ3hRtzLjCbqM_b3d1VH90PRRRKtJlGP1EzyAzeuKCq76nyGA7ytOSYSlghNdrz27-TRRc7TB35Ty2G_q-NKlt5qM1R398zzkyIMg9poxk5pH1Vlz4oJ3Ab6B2J-W059k/s640/dev.png" width="640" /></a></div>
</div>
<div>
<br /></div>
<div>
You can now use the <a href="https://dashboard.particle.io/user/devices" target="_blank">particle dashboard</a> to find your device ID. Or the CLI if you are so inclined.</div>
<div>
<br /></div>
<div>
Substitute these values into the application (removing the square brackets) and you should be able to communicate with your device.</div>
<div>
<br /></div>
<div>
The Android app show a few patterns for working with this API. As it is a simple application with only a few functions we aren't implementing a service or any more complicated Android patterns. We just use the <a href="http://developer.android.com/reference/android/os/AsyncTask.html" target="_blank">AsyncTask</a> API.</div>
<div>
<br /></div>
<div>
So that is it. Really simple communication with your development device suitable for your simple use cases like controlling your own device with a bespoke app.</div>
<div>
<br /></div>
<div>
As an added bonus. There is some nice color animation depending on the heat. OR whatever you what to retrieve from your device.</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<span id="goog_1479213071"></span><span id="goog_1479213072"></span><br /></div>
</div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-76522175468934746322015-11-05T19:41:00.000-08:002015-11-20T12:00:11.736-08:00IoHeating Part 1<br />
Recently I had a few days off from work and decided to solve one of the problems that had been bothering me throughout winter. Namely a cheap heater which had a temperature dial that was:<br />
<ol>
<li>Completely unlabeled</li>
<li>Driven by a large loud low accuracy thermostat.</li>
</ol>
<div>
Instead of solving these problems by getting a new heater or off the shelf controller I decided to make things a little more interesting. That meant it was parts shopping time. </div>
<div>
<br /></div>
<div>
If you are switching mains power you have two options <a href="https://en.wikipedia.org/wiki/Relay">relays</a> and <a href="https://en.wikipedia.org/wiki/TRIAC">triacs</a>. Triacs are a sextuple layer silicon switch similar to the better known transistor but compatible with <a href="https://en.wikipedia.org/wiki/Alternating_current">alternating current</a>. They are great because you can switch them many millions of time with no wear and because they are completely silent in operation. Relays are simply electronically operated physical switches. A triac would clearly be optimal here. A quick Google later and it turns out that the majority of parts for the hobbyist market are based around relays. I wanted to utilize one of these readily available parts because:</div>
<div>
<ol>
<li>When I have time off work I'm trying to be as lazy as possible</li>
<li>Relays and triacs often need a drive transistor which I would have to solder on <a href="https://en.wikipedia.org/wiki/Veroboard">veroboard</a> (eww)</li>
<li>Isolation.</li>
</ol>
In New Zealand we use 240V AC in every country the AC transmission voltage is dangerous, here especially so. Isolating the low voltage electronics especially the controller (more on that soon) is important for safety and longevity. Fortunately electrocuting kids is very bad press so most of the hobbyist relay boards include a drive transistor AND an optoisolator. If you haven't come across these before I'm about to make your day.</div>
<div>
<br /></div>
<div>
Optoisolators are essentially a transistor where the gate is not electrically connected but optically connected. So on on side of the package you have an LED and on the other a transistor with a gate that is excited by photons not those dirty old electrons. This whole thing is packaged up in a nice black box that puts the input side far enough away from the output side that everything is electrically isolated and safe enough to lick (do not lick). We are actually using the same power supply for driving the relay and the controller so this doesn't actually make us all that much safer but it is still good to isolate our delicate IO lines from nasty physical things like relay coils.</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGwlb8hAOQsw-QgM3uffTPv9ZZw5uQpY-qwWuI9vEOQGkV88stH0xn8UWRH74iK06mAQve5wcfWEHWedM_BmMWWOw6JEpW_fHkTuArLjiNw6O04EInKbgc2GPhcolksIQcejpSzu6cJ7k/s1600/F4C11AOGCJ108EL.MEDIUM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGwlb8hAOQsw-QgM3uffTPv9ZZw5uQpY-qwWuI9vEOQGkV88stH0xn8UWRH74iK06mAQve5wcfWEHWedM_BmMWWOw6JEpW_fHkTuArLjiNw6O04EInKbgc2GPhcolksIQcejpSzu6cJ7k/s320/F4C11AOGCJ108EL.MEDIUM.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Something like this.</td></tr>
</tbody></table>
<div class="separator">
So we have a switch that we can control. Now we need to know when to turn the heater on and off. The clunky old thermostat relied on a bimetallic strip to sense the temperature of the room. This sensor if you want to call it that is large and has an inherent hysteresis. We can do better. How precise does our temperature need to be half a degree you say? Perfect we'll use the <a href="https://www.blogger.com/%C2%A0https://www.sparkfun.com/products/245">DS18B20</a>. This is one of the first digital parts I ever utilized. They are a robust, decently accurate, and voltage compensated sensor. Even better you only need a single IO line to talk to them due to the exceedingly well named "1-wire protocol". </div>
<div class="separator">
<br /></div>
<div class="separator">
Finally time for the controller! <a href="http://particle.io/">Particle</a> (previously known as Spark) are a group who have developed a seriously amazing little bit of kit. The Photon dev board. To boil it down. ARM microcontroller, WIFI 802.11n, Cloud API and development platform, ludicrously simple code and integrations, $20. Go and <a href="https://store.particle.io/?product=particle-photon">buy one</a> right now.</div>
<div class="separator">
<br /></div>
<div class="separator">
So with our shopping list complete let's build our thing. Just so you know a couple of additional components will probably come in handy, those are.</div>
<div class="separator">
</div>
<ol>
<li>A heater with some space in it</li>
<li>A power supply for your controller</li>
<li>A high temperature insulation. Don't use heat shrink this is a heater. Instead use <a href="https://sugru.com/">Sugru</a></li>
</ol>
<div>
<br /></div>
<div>
With that the beautiful build is revealed! From top to bottom we have. A USB power supply from a hapless phone and behind it the Photon board. Below that we have the original heater switches and the thermostat. At the bottom you'll see the relay board and the actual heating elements. The relay board has been tapped into the AC power such that it can break the circuit to the heater whilst leaving the Photon board powered (clever huh). It is also wired in such a way that <b>all the heater's original safeties are in place</b>. The original thermostat (turned up to full), a thermal fuse (in between two of the elements you might spot it) and a thermal cut off at the other end of the element which isn't pictured. Also not seen the the DS18B20 as that is carefully located outside the case as to make it less susceptible to heat soak from the heater chassis. There are more pictures of the build <a href="https://goo.gl/photos/1FpXf9gLzqThDKiEA">here</a>.</div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisfo3DH965Dk1svJWu7ZV0bk3AESbYQ6Be4nS9-qcwHBAkNeVhWOKlE8pNBxk_wJVIhwGJziZdSkyqy-SIMudTM5aYFwPNeVfVZhhHzOAEy9JVxNL3Qk48sHXox8PKvs-LpMZ850HZ7nE/s1600/IMG_20150929_110032.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisfo3DH965Dk1svJWu7ZV0bk3AESbYQ6Be4nS9-qcwHBAkNeVhWOKlE8pNBxk_wJVIhwGJziZdSkyqy-SIMudTM5aYFwPNeVfVZhhHzOAEy9JVxNL3Qk48sHXox8PKvs-LpMZ850HZ7nE/s640/IMG_20150929_110032.jpg" width="480" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRpuJVWf-5I2wo9OoKN7kHvsrP1vcw6ObGn0-OAa6rsaA5Rhs0x1VEVjfoN3YOC7N1pG8dhRdiD5b2wIJuxlqBC4eJzrp5wrqx5m11kgtpJfY_aZm6cJbffeO73FwSjPKu0_kujNPSOyk/s1600/IMG_20150928_144854.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRpuJVWf-5I2wo9OoKN7kHvsrP1vcw6ObGn0-OAa6rsaA5Rhs0x1VEVjfoN3YOC7N1pG8dhRdiD5b2wIJuxlqBC4eJzrp5wrqx5m11kgtpJfY_aZm6cJbffeO73FwSjPKu0_kujNPSOyk/s640/IMG_20150928_144854.jpg" width="480" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator">
The genius of the Photon dev board is just how easy it is to step integrations between real world items like our heater and the <a href="https://en.wikipedia.org/wiki/Philosophy_of_Ghost_in_the_Shell">world of data</a>. For this project I used the build.particle.io development platform and whipped up a simple firmware that knows how to turn the heater on and off, how to measure the temperature from our temperature sensor.</div>
<div class="separator">
<br /></div>
<div class="separator">
There were a couple of small complications discovered whilst writing the code.</div>
<div class="separator">
</div>
<ol>
<li>I didn't read the datasheet for the DS18B20 temperature sensor quite well enough you need to use a pull up resistor to get the 1-wire communication working with the Photon. No issue that five minutes with a soldering iron can't fix.</li>
<li>Our relay board likes to turn on but doesn't like to turn off. To deal with this one we can get away with setting the IO line to <span style="font-family: "courier new" , "courier" , monospace;">INPUT_PULLDOWN</span><span style="font-family: inherit;"> this soaks up any stray electrical potential and makes sure the relay optoisolator and thus the relay returns to the off state.</span></li>
</ol>
<div class="separator">
Want to have a look at how simple this was to implement or even spare yourself that effort and copy it for your project? Go right ahead and read this <a href="https://gist.github.com/Bostwickenator/146f41fced58d4fdb5ff">gist of heater code</a>. Just remember that you'll have to use the library include system in Particle Build to add the libraries listed at the top of the source.</div>
<div class="separator">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-N_eXWmCN850EOtSSPayp2WJyJnxKqPc3Ar52zfYDk7VSyZR-VJVShTOeR921c_D7jVi-XyBBlguBDonWmLTP6GuRJg7YgoKhvXqK204CfU5QEM7uf1JSRT9WXhs_e8fTEMhh3W0ub04/s1600/build.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="440" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-N_eXWmCN850EOtSSPayp2WJyJnxKqPc3Ar52zfYDk7VSyZR-VJVShTOeR921c_D7jVi-XyBBlguBDonWmLTP6GuRJg7YgoKhvXqK204CfU5QEM7uf1JSRT9WXhs_e8fTEMhh3W0ub04/s640/build.png" width="640" /></a></div>
<div class="separator">
<br /></div>
<div class="separator">
<br /></div>
<div class="separator">
At this point we have a heater that can turn on and off at the whim of anything that can use a REST protocol. While using a web browser to turn a heater on and off is pretty cool that isn't going to cut the mustard in this <a href="https://medium.com/@gpeuc/internet-of-things-is-a-really-stupid-idea-e4df1493e4d6">connected world</a>. What we need is apps! lots of apps. Well maybe just one. Next post I will tell you about the application below.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKL8ChIcX1FQ7o5fApkQhMb-YVQc6Z7LJJ5xHoSLVNG4wZT4BdSI9fr0ZWDtCKgxp9o4YpOdO9oYi9VdUUFltNrmrED-FSLONKBWL9vYhMoYYzx9OFfZdhFSgQZJfpdlQ6KxgRvSryK-8/s1600/screenshot+%25281%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKL8ChIcX1FQ7o5fApkQhMb-YVQc6Z7LJJ5xHoSLVNG4wZT4BdSI9fr0ZWDtCKgxp9o4YpOdO9oYi9VdUUFltNrmrED-FSLONKBWL9vYhMoYYzx9OFfZdhFSgQZJfpdlQ6KxgRvSryK-8/s400/screenshot+%25281%2529.jpg" width="225" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-90884406282872038862015-07-17T04:04:00.000-07:002016-06-27T12:16:24.498-07:00It lives!<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkPip-FgDPe2IF-UHsQwby65KVK4jSD4Emds5t9dMC_6CKlDFA8x4Cf3dthLm2X-Ea1hqp8ywgw4-wB_VkFFh7EioAR5N8EOFSATtifhME3SZiNBl2f31yEOmNiDyL1Jsnc10BO1AVdHk/s1600/icon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkPip-FgDPe2IF-UHsQwby65KVK4jSD4Emds5t9dMC_6CKlDFA8x4Cf3dthLm2X-Ea1hqp8ywgw4-wB_VkFFh7EioAR5N8EOFSATtifhME3SZiNBl2f31yEOmNiDyL1Jsnc10BO1AVdHk/s320/icon.png" width="320" /></a></div>
<br />
OK after two false starts I present Wear GBC, play games from your favorite mid nineties portable game console on your Android Wear device. Try out QBert (free and legal) <a href="http://www.1000klub.com/Qbert/">http://www.1000klub.com/Qbert/</a><br />
<br />
<a href="https://play.google.com/store/apps/details?id=org.bostwickenator.android.weargbc">https://play.google.com/store/apps/details?id=org.bostwickenator.android.weargbc</a>Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-71371821604485770332015-07-16T18:25:00.000-07:002015-11-06T00:56:19.790-08:00Google Play Rejections<div class="uyb8Gf" jsan="7.uyb8Gf" jsinstance="0" jstcache="2439" style="background-color: white; color: #212121; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13.1999998092651px; line-height: 19.7999992370605px;">
<div class="F3hlO" jsaction="jsl._" jsan="7.F3hlO,0.jsaction" jstcache="2441">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
Google Play now has a team of actual living humans checking through every app submission. Unfortunately this can lead to exchanges like the one I just concluded today. As with all email chains start reading at the bottom.</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<br /></div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<br /></div>
</div>
</div>
<div dir="ltr" style="background-color: white; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13.1999998092651px; line-height: 19.7999992370605px; unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">From: Alexander Gee <<a href="mailto:bostwickenator@gmail.com" style="position: relative; z-index: 0;" target="_blank">bostwickenator@gmail.com</a>><br />Date: Fri, 17 Jul 2015 at 11:50<br />Subject: Re: [5-6184000007874] Your appeal for reinstatement<br />To: <<a href="mailto:googleplay-developer-support@google.com" style="position: relative; z-index: 0;" target="_blank">googleplay-developer-support@<wbr></wbr>google.com</a>></span></div>
<span style="color: #999999;"><br style="background-color: white; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13.1999998092651px; line-height: 19.7999992370605px;" /></span>
<div dir="ltr" style="background-color: white; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13.1999998092651px; line-height: 19.7999992370605px; unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">This is a very frustrating process. I hope that it is reviewed and augmented soon. Communication via this mechanism is clearly very constrained by regulations against you providing advice. This saddens me.</span><br />
<div>
<span style="color: #999999;"><br /></span></div>
<div>
<span style="color: #999999;">I will resubmit the app under a different name without the button. Thanks for trying to help me as much as you can within your constraints.</span></div>
</div>
<span style="color: #999999;"><br style="background-color: white; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13.1999998092651px; line-height: 19.7999992370605px;" /></span>
<div class="gmail_quote" style="background-color: white; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13.1999998092651px; line-height: 19.7999992370605px;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On Fri, 17 Jul 2015 at 11:38 <<a href="mailto:googleplay-developer-support@google.com" style="position: relative; z-index: 0;" target="_blank">googleplay-developer-support@<wbr></wbr>google.com</a>> wrote:</span></div>
<blockquote class="gmail_quote" style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">Hello,</span><br />
<span style="color: #999999;">Unfortunately, the violation on the application was still present after conditionally reinstating the application. Previous email states, "Please remove any violations prior to resubmitting your application." We will not be reinstating your applications because the conditions were not met. </span><br />
<span style="color: #999999;">If you do choose to re-publish a new, policy-compliant version of your app, please make sure to review the<a href="https://play.google.com/about/developer-content-policy.html" style="position: relative; z-index: 0;" target="_blank"> Content Policy</a> and visit the<a href="https://support.google.com/googleplay/android-developer/answer/113474?hl=en" style="position: relative; z-index: 0;" target="_blank"> Policy Help Center</a> for additional guidance to ensure your next app is compliant with the policy.</span><span style="font-family: "arial"; font-size: 13.3333333333333px; line-height: 1.38; white-space: pre-wrap;"><span style="color: #999999;">You will need to upload a new apk as a new app with a different package name, that is an updated version of the app you are trying to publish to the Google Play Store.</span></span><br />
<span style="font-family: "arial"; font-size: 13.3333333333333px; line-height: 1.38; white-space: pre-wrap;"><span style="color: #999999;">If we can assist you further, please let us know.</span></span></div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<br />
<div>
<div>
<span style="color: #999999;">Regards,</span></div>
<div>
<span style="color: #999999;">Arya</span></div>
<div>
<i><span style="color: #999999;">The Google Play Team</span></i></div>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On 07/16/15 15:11:43 <a href="mailto:bostwickenator@gmail.com" style="position: relative; z-index: 0;" target="_blank">bostwickenator@gmail.com</a> wrote:</span></div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;"><span style="font-size: 13.1999998092651px; line-height: 19.7999992370605px;">Ok I'll remove the button. </span>I did previously comment on the mis-identification of those softwares as protected works (they are explicitly offered as free by the owners). Since my appeal was approved directly after this I assumed that meant after further review you were in agreement with my statement. A misinterpretation on my part. If it will make this process simpler I'm happy to remove the button. Sorry for the further complication this has caused.</span></div>
<span style="color: #999999;"><br /></span></blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On Fri, 17 Jul 2015 at 09:13 <<a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">googleplay-developer-support@<wbr></wbr>google.com</a>> wrote:</span></div>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<span style="color: #999999;">Hello,</span><br />
<span style="color: #999999;">Thanks for contacting the Google Play team.<br /><br />After further review, your app will not be reinstated because it violates the <a href="https://play.google.com/about/developer-content-policy.html#IP" style="position: relative; text-decoration: none; z-index: 0;" target="_blank"><span style="background-color: transparent; font-family: "arial"; font-size: 13.3333333333333px; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">intellectual property</span></a><span style="background-color: transparent; font-family: "arial"; font-size: 13.3333333333333px; vertical-align: baseline; white-space: pre-wrap;"> and </span><a href="https://play.google.com/about/developer-content-policy.html#impersonation" style="position: relative; text-decoration: none; z-index: 0;" target="_blank"><span style="background-color: transparent; font-family: "arial"; font-size: 13.3333333333333px; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">impersonation or deceptive behavior</span></a> provision of the Content Policy:<br /><br />- Our policy states: </span><br />
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; font-family: Arial; font-size: 13.3333333333333px; list-style-type: disc; unicode-bidi: -webkit-isolate; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; unicode-bidi: -webkit-isolate;">
<span style="background-color: transparent; font-size: 13.3333333333333px; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #999999;">Your app and/or elements of its listing on Google Play, including title, description, logo(s), or promotional screenshots must not include unauthorized usage of protected works belonging to a third party.</span></span></div>
</li>
<li dir="ltr" style="background-color: transparent; font-family: Arial; font-size: 13.3333333333333px; list-style-type: disc; unicode-bidi: -webkit-isolate; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; unicode-bidi: -webkit-isolate;">
<span style="background-color: transparent; font-size: 13.3333333333333px; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #999999;">Your app icon and promotional screenshots must not contain images that appear confusingly similar to existing products.</span></span></div>
</li>
<li dir="ltr" style="background-color: transparent; font-family: Arial; font-size: 13.3333333333333px; list-style-type: disc; unicode-bidi: -webkit-isolate; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; unicode-bidi: -webkit-isolate;">
<span style="background-color: transparent; font-size: 13.3333333333333px; line-height: 1.38; white-space: pre-wrap;"><span style="color: #999999;">Protected work could typically include product names, brands, images, logos, music, and similar works.</span></span></div>
</li>
</ul>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<div>
<span style="color: #999999;">- As an example, your app contains: <span style="font-family: "arial" , sans-serif; line-height: 16px;">Currently, your application lets users download copyrighted content via the "Get Roms" button within your application. <b> The violation was not removed in the latest submission and the violation STILL exists.</b></span></span></div>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<span style="color: #999999;"><br /><br />If you publish a new version of your app, please make sure it’s in compliance with our policies. You may want to review these resources for additional guidance:<br /><br />Content Policy:<br /><a href="https://play.google.com/about/developer-content-policy.html" style="position: relative; z-index: 0;" target="_blank">https://play.google.com/about/<wbr></wbr>developer-content-policy.html</a><br /><br />Google Play Developer Help Center:<br /><a href="https://support.google.com/googleplay/android-developer/answer/113474" style="position: relative; z-index: 0;" target="_blank">https://support.google.com/<wbr></wbr>googleplay/android-developer/<wbr></wbr>answer/113474</a></span></div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<span style="color: #999999;">Regards,<br />Arya<br /><i>The Google Play Team</i></span></div>
</div>
</blockquote>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On 07/15/15 18:12:09 <a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">bostwickenator@gmail.com</a> wrote:</span></div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">Arya, I resubmitted it and it got kicked again. WHAT DO I DO?</span></div>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On Thu, 16 Jul 2015 at 11:02 <<a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">googleplay-developer-support@<wbr></wbr>google.com</a>> wrote:</span></div>
</div>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<span style="color: #999999;">Hello,</span><br />
<span style="color: #999999;">Thanks for contacting the Google Play Team.<br /><br />We’ve <b>conditionally</b> accepted your appeal and your app has been reinstated. Please remove any violations prior to resubmitting your application. For the app to appear in the Play Store, you’ll need to sign into your Developer Console and submit your app again.<br /><br />Please let us know if you have any other questions or concerns.<br /><br />Thanks for supporting Google Play!</span></div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<div>
<span style="color: #999999;">Regards,</span></div>
<div>
<span style="color: #999999;">Arya</span></div>
<div>
<i><span style="color: #999999;">The Google Play Team</span></i></div>
</div>
<span style="color: #999999;"><br /></span></div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On 07/14/15 19:44:49 <a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">bostwickenator@gmail.com</a> wrote:</span></div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">Hi Arya,</span></div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">That link directs people to a site devoted to homebrew games. Files that are written for demonstration purposes or fun and released freely and publicly. It is there explicitly to discourage users from downloading content protected by copyright.</span></div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">If you wish I can remove it and resubmit. Would it at that point meet your criteria?</span></div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">Your advice here would be appreciated,<br />Alex</span></div>
<span style="color: #999999;"><br /></span></blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On Wed, 15 Jul 2015 2:27 pm <<a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">googleplay-developer-support@<wbr></wbr>google.com</a>> wrote:</span></div>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">Hello,</span><br />
<span style="color: #999999;">Thanks for contacting the Google Play team.<br /><br />After further review, your app will not be reinstated because it violates the <a href="https://play.google.com/about/developer-content-policy.html#IP" style="position: relative; text-decoration: none; z-index: 0;" target="_blank"><span style="background-color: transparent; font-family: "arial"; font-size: 13.3333333333333px; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">intellectual property</span></a><span style="background-color: transparent; font-family: "arial"; font-size: 13.3333333333333px; vertical-align: baseline; white-space: pre-wrap;"> and </span><a href="https://play.google.com/about/developer-content-policy.html#impersonation" style="position: relative; text-decoration: none; z-index: 0;" target="_blank"><span style="background-color: transparent; font-family: "arial"; font-size: 13.3333333333333px; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">impersonation or deceptive behavior</span></a> provision of the Content Policy:<br /><br />- Our policy states: </span><br />
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; font-family: Arial; font-size: 13.3333333333333px; list-style-type: disc; unicode-bidi: -webkit-isolate; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; unicode-bidi: -webkit-isolate;">
<span style="background-color: transparent; font-size: 13.3333333333333px; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #999999;">Your app and/or elements of its listing on Google Play, including title, description, logo(s), or promotional screenshots must not include unauthorized usage of protected works belonging to a third party.</span></span></div>
</li>
<li dir="ltr" style="background-color: transparent; font-family: Arial; font-size: 13.3333333333333px; list-style-type: disc; unicode-bidi: -webkit-isolate; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; unicode-bidi: -webkit-isolate;">
<span style="background-color: transparent; font-size: 13.3333333333333px; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #999999;">Your app icon and promotional screenshots must not contain images that appear confusingly similar to existing products.</span></span></div>
</li>
<li dir="ltr" style="background-color: transparent; font-family: Arial; font-size: 13.3333333333333px; list-style-type: disc; unicode-bidi: -webkit-isolate; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; unicode-bidi: -webkit-isolate;">
<span style="background-color: transparent; font-size: 13.3333333333333px; line-height: 1.38; white-space: pre-wrap;"><span style="color: #999999;">Protected work could typically include product names, brands, images, logos, music, and similar works.</span></span></div>
</li>
</ul>
<span style="color: #999999;">- As an example, your app contains: <span style="font-family: "arial" , sans-serif; line-height: 16px;">Currently, your application lets users download copyrighted content via the "Get Roms" button within your application.</span><br /><br />If you publish a new version of your app, please make sure it’s in compliance with our policies. You may want to review these resources for additional guidance:<br /><br />Content Policy:<br /><a href="https://play.google.com/about/developer-content-policy.html" style="position: relative; z-index: 0;" target="_blank">https://play.google.com/about/<wbr></wbr>developer-content-policy.html</a><br /><br />Google Play Developer Help Center:<br /><a href="https://support.google.com/googleplay/android-developer/answer/113474" style="position: relative; z-index: 0;" target="_blank">https://support.google.com/<wbr></wbr>googleplay/android-developer/<wbr></wbr>answer/113474</a><br /><br />If I can be of further assistance, please let me know.</span></div>
</blockquote>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div>
<div>
<span style="color: #999999;">Regards,</span></div>
<div>
<span style="color: #999999;">Arya</span></div>
<div>
<i><span style="color: #999999;">The Google Play Team</span></i></div>
</div>
<span style="color: #999999;"><br /></span></div>
</div>
</blockquote>
</blockquote>
</div>
</div>
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<div dir="ltr" style="unicode-bidi: -webkit-isolate;">
<span style="color: #999999;">On 07/14/15 01:58:28 <a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">bostwickenator@gmail.com</a> wrote:</span><br />
<blockquote style="border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<span style="color: #999999;">first_name: Alexander<br />last_name: Gee<br />registered_email_address: <a href="https://www.blogger.com/null" style="position: relative; z-index: 0;">bostwickenator@gmail.com</a><br />abuse_type: ip<br />package_name: org.bostwickenator.weargbc<br />appeal_reason: There are no trademarks for Wear or GBC. There are various<br />apps on the Play Store using both of these terms in their name. All works<br />were produced by me or credited correctly: one image under CC:A v3 from<br />(<a href="http://cyrilmottier.com/2014/07/31/android-wear-flat-device-frame/" style="position: relative; z-index: 0;" target="_blank">http://cyrilmottier.com/2014/<wbr></wbr>07/31/android-wear-flat-<wbr></wbr>device-frame/</a>),<br />several packages under GPL (<a href="https://code.google.com/p/kiddgbc/" style="position: relative; z-index: 0;" target="_blank">https://code.google.com/p/<wbr></wbr>kiddgbc/</a>) and LGPL<br />(<a href="https://github.com/spacecowboy/NoNonsense-FilePicker/blob/master/LICENSE" style="position: relative; z-index: 0;" target="_blank">https://github.com/<wbr></wbr>spacecowboy/NoNonsense-<wbr></wbr>FilePicker/blob/master/LICENSE</a><wbr></wbr>).<br />Thank you for your reconsideration.<br />subject_hidden: Your appeal for reinstatement<br /><br /><br />:---- Automatically added fields ----:<br />Language: en-GB<br />IIILanguage: en-GB<br />auto-helpcenter-id: 203<br />auto-helpcenter-name: googleplay/android-developer<br />auto-internal-helpcenter-name: androidmarket<br />auto-full-url:<br /><a href="https://support.google.com/googleplay/android-developer/contact/appappeals" style="position: relative; z-index: 0;" target="_blank">https://support.google.com/<wbr></wbr>googleplay/android-developer/<wbr></wbr>contact/appappeals</a><br />auto-user-logged-in: true<br />auto-user-was-internal: false<br />IssueType: appappeals<br />form-id: appappeals<br />form: appappeals<br />subject-line-field-id: subject_hidden<br />body-text-field-id:<br />AutoDetectedBrowser: Chrome 43.0.2357.132<br />AutoDetectedOS: Windows Windows NT 6.3<br />MendelExperiments: 10800005,10800027 </span></blockquote>
</div>
</div>
</blockquote>
</blockquote>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</blockquote>
</blockquote>
</div>
</div>
</blockquote>
</div>
Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0tag:blogger.com,1999:blog-6650204029311506267.post-2912331266849085592015-07-16T18:19:00.001-07:002015-07-16T18:19:54.737-07:00StartingIt occurs to me that I have never had a blog devoted to software development. Quite strange considering how much of my life I spend working on that. This blog will rectify that.Alexander Geehttp://www.blogger.com/profile/10567739271529600460noreply@blogger.com0