Travel, Code, and Engineering
on October 23, 2016 by Kurt Tomlinson
I recently bought a pack of LED Night Lights from China on Amazon. They were very cheaply made, so of course I wondered what they were like on the inside. Today I tried to unplug one from the wall to move it to another outlet, and the front cover came off. Since it practically disassembled itself for me, I decided to take a closer look at its circuit and figure out how it worked.
The first step was to figure out what everything was. That was pretty easy. The LEDs are the four yellow boxes at the outside corners of the circuit board. The resistors are all labeled with three numbers "XYZ" where the value of the resistor is XY10^Z (e.g. 754 --> 7510^4 = 750k). The squiggly thing in the middle is clearly a photoresistor. The big blue thing is clearly a capacitor that is marked with "400V 224J" where "400V" is the voltage rating of the capacitor, and "224" indicates the value is 22*10^-4 and "J" indicates it has 5% tolerance on the value.
The two big blobs of solder are where the AC power comes in from the wall. And the two ICs were a little more difficult. The small 3-pin device is marked "J3Y". A quick Google search for J3Y turns up the S8050 NPN transistor from Shenzhen City Koo Chin Electronics Limited. I guessed the four-pin device was a bridge rectifier based on the "+" and "-" markings near two of its pins. I was not able to identify its part number though.
Next I traced out the circuit with the continuity checker function on my multi-meter and transferred it into LTSpice for simulation purposes.
I've labeled each section of the schematic to show what each section does.
Resistor R1 and capacitor C1 work together to limit the maximum current and voltage delivered to the load. If the current is too high, the LEDs will overheat and break. If the voltage is too high, then the bridge rectifier will fail and cease to continue rectifying the AC current into DC current.
R1 and C1 must be sized together in order to properly limit the voltage and current supplied to the bridge rectifier. If C1 is too large, then it will never charge, and it will act like a short circuit. In that case, the voltage dropped across the bridge rectifier will be somewhere around V_S*R4/(R1+R4) where V_S is the peak voltage of the mains power. In the USA, V_S is about 120 * sqrt(2) = 169.7 V. All bridge rectifiers have a maximum rating called the "Maximum DC blocking voltage". In cheaper bridge rectifiers, this number is lower, and can be in the range of 50 V. Given V_S = 169.7 V, R4 = 330, and R1 = 510, the voltage across the bridge rectifier would be about 67 V if C1 is too large.
On the other hand, if C1 is too small then it will act like an open circuit and no current will flow through the load. If no current flows through the LEDs, they will never turn on.
Given the maximum voltage desired across the bridge rectifier and the maximum current through the load, resistor R1 can be sized using Ohm's law. Once the value of R1 is known, C1 must be sized so that the current through the load will charge/discharge it at the appropriate rate in order to keep the voltage across the bridge rectifier within an acceptable range.
Finally, the resistor R5 is simply used to discharge the capacitor C1 when the device is disconnected from the wall so that the maximum voltage difference between the capacitor and mains voltage is never more than V_S.
The bridge rectifier is standard. It forces current to flow in only one direction in the rest of the circuit. It's just four diodes in a single package.
The power burner makes use of a photoresistor to turn off the LEDs when there is ambient light. The photoresistor, marked PSR (for photosensitive resistor) has a resistance of about 2k in a brightly lit room and a resistance of about 25k in a dark room. When exposed to light, the photoresistor decreases its resistance and supplies the NPN transistor with a base current. The base current turns the transistor on, and it conducts current from its collector to its emitter. This starves the LEDs for current (because only a fixed amount of current is available due to the current limiting resistor R1), and they turn off.
When there is no ambient light, the photocell's resistance increases, the base current is removed from the NPN transistor, the transistor turns off, and current flows through the LEDs. This turns the LEDs on at night time.
Since the same amount of current is passing through the cicruit whether the LEDs are on or off, the night light uses the same amount of power all the time. That's why I called this portion of the circuit the power burner.
Finally, the load is just four LEDs and an additional current limiting resistor. I haven't dug into this circuit enough to figure out exactly why a second current limiting resistor is necessary. I think it could be removed without impacting the circuit's functionality. If you know why it's there, feel free to let me know in the comments.
I also simulated how the circuit works in nighttime and daytime. The first simulation below is the daytime simulation. It shows a maximum of about 14 mA flowing through the collector of Q1 and almost no current flowing through the LEDs.
The second simulation is the nighttime simulation. You can see that it's just the opposite of the daytime simulation: current flows through the LEDs and not the transistor.
on September 25, 2016 by Kurt Tomlinson
My aging laptop was having trouble keeping up. It slowed to a crawl. Even opening up more than one tab in Chrome seemed to be too much for it. That's when I decided to take things into my own hands and fix it in a surprising way.
I drilled holes in my laptop.
When I was using my laptop, it used to get so hot. The fan always sounded like it was running at top speed. Considering the age of the laptop and the low price I had originally paid for it, I decided it was time to open it up and see what I could do. The warranty had long since expired, and I wouldn't be too upset if I broke it and had to buy a new one.
So I unscrewed every screw I could find on the bottom of the case and gently pried the bottom panel off. (It really was that easy. Thanks, Sony, for making my particular model laptop so easy to open up!)
Once I had it open, I actually found the root of the problem very quickly. There is a single heat pipe going from the CPU to an array of aluminum fins that are cooled by a blower fan. The fan blows air through the fins and the hot air would get exhausted out the side of the laptop case.
The problem was that there wasn't anywhere for the fan to take in cool air from outside the case! The fan was pressed tight between the motherboard and the plastic bottom panel. Maybe some air could leak in somewhere, but I couldn't really see any obvious air intake locations.
Initially I thought about cutting a big hole in the case and covering that hole with metal mesh to filter out dust, but I settled on drilling a lot of small holes in a circular pattern after doing a bit of searching on the internet about how other people how modified their own laptop cases for improved cooling.
I took a couple of random circular objects I had lying in my room (a Carmex container and a button) and traced out two circles on the bottom panel centered on where the fan was centered. I then used a Sharpie to place 16 dots in a circle half-way between the two circles. I kept the dots evenly spaced by placing dots every 90 degrees, and then halfway between those dots, and then halfway between again. I filled in the two circles with another two rows of sixteen dots: one inside the first row and one outside the first row. I offset the inner and outer rows from the middle row so the drill holes wouldn't be too close together.
I then drilled holes where all the dots were with a drill press and what I can only guess was about a 1/8" drill bit. The result looks so much better than I had hoped especially after seeing the ridiculously lop-sided and uneven patterns other people had drilled into their own laptops on the the internet.
I noticed a distinct performance improvement after drilling those holes into my laptop case. (Sorry, I don't have any benchmarks to prove this.) The CPU used to overheat and scale down its frequency all the time. Now, it runs much cooler and is able to sustain a higher higher workload for much longer without having to slow down due to thermal issues. Now my laptop actually feels faster than the day I bought it (but that's probably mostly because I upgraded the hard drive to an SSD.)
Have you done something similar on your computer? Let me know in the comments.
on September 18, 2016 by Kurt Tomlinson
It's been my dream for a long time to be able to control the lights in my house from anywhere in the world. Now I can do that without breaking the bank. Using a Raspberry Pi, some Etekcity Remote Control Outlets, and a 433 MHz transmitter, I can control the outlets in my home with Siri and any other HomeKit-enabled app on iOS. In this tutorial, I'll show you how to do it too.
Unlike the other tutorials in this series, you'll need a few things for this one:
Additionally, you'll need some tools and consumables:
The price of this project is quite cheap if you already have a Raspberry Pi and some basic electronic tools and components: just $32 for the RF outlets and the RF modules! That's downright miserly compared to the cost of buying a commercial, ready-made solution.
This project takes some time to complete, so I recommend you plan to complete this project over the course of several days. I've broken it up into steps with completion milestones to give you good stopping points.
The RF Transmitter and Receiver need antennae to function really well. Without antennae, their range will be limited to just a few meters. You have a couple choices for your antenna design. The simplest choice is to build a quarter-wave monopole. A quarter wave monopole antenna is just a straight piece of wire that is 25% as long as the wavelength RF signals you're working with.
In this case, the Etekcity outlets operate at 433 MHz. We can find the wavelength of 433 MHz waves with the wave equation
c = f * λ
c = f * λ
where c is the speed of light (299,792,458 m/s), f is the frequency of the wave (433,000,000 Hz), and λ is the wavelength of the wave (in meters). Using this equation, we find that our antenna should be 173 mm (or 6-13/16 inches):
299,792,458 = 433,000,000 * λ
λ = 299,792,458 / 433,000,000
λ = 0.69236 m = 692 mm
λ/4 = 173.09 mm
299,792,458 = 433,000,000 * λ
λ = 299,792,458 / 433,000,000
λ = 0.69236 m = 692 mm
λ/4 = 173.09 mm
Calculating that was the hard part. To make the antenna, just cut a portion of your 18 AWG wire to the correct length and then strip off about 3 mm (or 1/8 inch) of the insulation. You'll need to do this two times: once for the transmitter and once for the receiver. (I chose 18 AWG wire because it was what I had on hand, it didn't bend easily, and it fit nicely into the ANT holes of the RF modules. The diameter of the wire doesn't really matter, but stiffer is better because the antenna should be straight.)
Once you've made your antennae, solder them into the holes marked ANT on your RF transmitter and receivers.
Once you've soldered the antennae to your RF modules, you're done with this step. In the image, I used a different design for my transmitter's antenna called a "coil loaded" antenna. I can't comment on which antenna has better performance, but the coil loaded antenna is slightly more compact.
This step is relatively straightforward. Peel off six jumper wires from your Female to Female Jumper Wires and make the connections in the diagram below.
Here's the same information in a couple tables (the pin locations are described when viewed from the top with the pins on the side closest to you):
You'll need to find out what codes are sent to turn on and off each of your outlets.
First, update and upgrade your packages and package repositories:
sudo apt-get update
sudo apt-get upgrade
Then install Git:
sudo apt-get install git
Clone and build the WiringPi utility. It's a library that is used by some other programs we'll be using shortly.
git clone git://git.drogon.net/wiringPi
Now you can compile a couple utilities, codesend and RFSniffer, that let you send and receive data with your 433 MHz RF modules.
git clone --recursive git://github.com/ninjablocks/433Utils.git
Next, you can run RFSniffer to find out what codes are assigned to each of your outlets. RFSniffer won't show any output in your console right away. If you press and hold a button on your Etekcity remote, you should see lines like Recieved 5518604 printed in your console.
Make a table showing which codes correspond to which buttons on your remote. The codes for my remote are below. Your codes will be different.
Once you've created your own table, take a break! You're almost done, and you've completed a good portion of this tutorial.
Now we can use codesend to confirm our RF codes are correct and our transmitter is functioning correctly.
Plug a lamp into your first outlet, and make sure you can turn it on and off with your remote. Then open up two terminal windows. In the first terminal window, open RFSniffer so you can see the codes that are sent by your remote and the codes that are sent by your transmitter module:
In the second terminal window, you can send some codes to try to turn your outlets on and off. For example, the last line below turns off my first outlet:
sudo ./codesend 5510460 -l 200
5510460 is the code that I got from RFSniffer. the -l argument tells the codesend utility to send the code with a pulse length of 200 us. I was able to control my outlets with pulse lengths between 105 and 1445 us.
You will want to try using different pulse lengths to see what works for your setup. Longer pulse lengths will make it take longer to send a code, but shorter pulse lengths will make it more likely that your code will not be properly received.
I found 200 us to be a good compromise between speed and reliability for me. I'd recommend you use pulse lengths around 200 as well since long pulse lengths can also be unreliable if you get too close to the upper limit for your devices.
After you can successfully turn your outlets on and off with your Raspberry Pi, celebrate! You've completed another milestone in getting your home more automated.
Homebridge is a Node.js package that lets you use HomeKit to control devices that weren't designed for HomeKit. We'll use it as he missing link between Siri on iOS and our RF outlets. First, we need to install Node.js:
sudo dpkg -i node_latest_armhf.deb
Confirm that Node and npm are installed correctly by running node -v and npm -v. The output I got is shown below:
pi@raspberrypi:~ $ node -v
pi@raspberrypi:~ $ npm -v
Install make and Avahi. Make is used to build binaries for your system, and Avahi gives Homebridge access to Apple's Bonjour protocol.
sudo apt-get install make
sudo apt-get install libavahi-compat-libdnssd-dev
Finally, Install Homebridge:
sudo npm install -g homebridge
Now we'll add some plugins to Homebridge, configure them, and check to make sure that we can talk to Homebridge from iOS.
First, install the dummy-switch plugin and the rcswitch platform:
npm install -g homebridge-dummy
npm install -g homebridge-platform-rcswitch
Dummy switches are switches that turn off immediately after you turn them on. They're useful just for checking if your iPhone can talk to your Homebridge.
When you install plugins and platforms, you tell Homebridge what type of devices you want it to be able to talk to. The next step is to tell Homebridge how many of those devices you have, what their names are, and how to talk to them. In other words, we need to configure Homebridge. We do that by modifying Homebridge's config.json file.
Overwrite your Homebridge config.json with Nate Henrie's config.json file:
sudo wget https://gist.github.com/n8henrie/639c7f5d72b4202cce7e/raw -O /etc/homebridge/config.json
Here's the content of his config.json file, if you're curious:
"description": "Example config file to test with a homebridge-dummy switch.",
"name": "A dummy switch"
Update the config file and run Homebridge with the command below:
sudo DEBUG=* /usr/local/bin/homebridge -D -U /etc/homebridge
I believe DEBUG=* and -D put Homebridge into debug mode so it prints more helpful information into the console. I think -U /etc/homebridge tells home bridge to look in that directory for its config.json file and to store any persistence data it might have.
After you run Homebridge you should get an output that looks something like the image above. Once that happens, open a HomeKit-enabled app on your phone such as Elgato Eve, Insteon+, or on iOS 10 you can use the pre-installed Home app. In whichever app you choose, tap the button for "adding an accessory" or something similar. You will be prompted for a 8-digit PIN. Enter the PIN printed into your console by Homebridge. Scanning the pin is usually unreliable, so I suggest typing it in.
At this point you should be able to see a single dummy switch that switches itself off immediately after you switch it on. Congratulations! You've reached another milestone in this project. You've linked your Raspberry Pi to your iPhone through HomeKit and Homebridge.
We're almost done. Now we just have to update our config.json file to tell Homebridge that we have RC switches we want it to control, what their names are, and what codes to send to turn them on or off. To get Homebridge to read the updates you're going to make to the config.json file, we're have to restart Homebridge. I ran into issues with Homebridge not releasing the port it was running on properly, so I found that a reboot was the surest way to cleanly shut down Homebridge.
First, update your config.json file:
sudo nano /etc/homebridge/config.json
I've included my config.json file for your reference. You're want to change the "pin" value to a new PIN so no one else can control your devices. Also, update the "code" lines with the on and off codes you wrote down earlier. If your Etekcity outlets worked well with a pulse length significantly different than 198, update the "pulse" lines as well with your pulse length
"description":"A Homebridge with four RC switches.",
Finally, reboot and start Homebridge again. Rebooting might take longer than usual because Homebridge likes to take a long time to shut down:
sudo DEBUG=* /usr/local/bin/homebridge -D -U /etc/homebridge
At this point you should be able to control your outlets remotely in your HomeKit-enabled app. If not, go back and make sure you can still turn your outlets on and off with codesend and that the codes in your Homebridge config file are correct. Also, make sure that you use the -U /etc/homebridge parameter when running codebridge, otherwise it won't use the config.json file you made.
There are many options for how to get Homebridge to run at boot. You can use systemd, rc.init, cron, and probably 10 other things. My preferred method is with cron. First, open sudo's crontab (and press 2 to use the nano editor if you're given the option):
sudo crontab -e
Then add these lines to the end of your crontab file:
@reboot DEBUG=* /usr/local/bin/homebridge -D -U /etc/homebridge > /home/pi/homebridge.log 2>&1
The SHELL=/bin/bash line tells cron to execute your cron jobs with bash, the default login shell on Raspbian. (Normaly cron uses /bin/sh which can make cron behave differently than your normal shell.) The PATH=... line tells cron what folders to look in for executables like Node. Cron uses a minimal PATH variable by default, so it won't find your Node executable without this little bit of help. Finally, the @reboot ... line tells cron to run Homebridge every time your Raspberry Pi boots up. (It doesn't matter if you reboot or halt and then power on; your command will run at every boot. The @reboot syntax is a bit of a misnomer.)
And that's it! You should now be able to control your Etekcity outlets from an iOS device. Congratulations on completing this tutorial.
If you found that I skipped a step or need some help, leave a message in the comments below. If this tutorial worked for you, let me know that as well!
on May 29, 2016 by Kurt Tomlinson
I wrote the BarStack Windows App way back in 2014 when Windows 8 was brand new. Windows 8.1 hadn't been released yet, and "Metro" style apps had just been rebranded as "Windows Store" apps. Developing Windows Store apps was major pain. The development tools didn't work very well, and the GUI building blocks were far from refined.
Since then, a lot of time has passed. I moved on from BarStack and created my blogging platform, Bloopist. The last update I made to the BarStack Windows app was probably in late 2014, and the majority of updates I made to the BarStack website were security-related. Any new features planned for BarStack were put on hold.
Recently, I was notified that the BarStack Windows app wasn't working. I fired it up to check it out, and it definitely wasn't. It crashed right away when it tried to log in. The first couple bugs were pretty easy to find. The server was responding with text instead of JSON data, so that caused the JSON parser in the Windows app to throw an unhandled exception. I corrected this on the server side, so the Windows app now longer crashed on startup.
The next bug was much harder to root-cause. When the app tried to log in to the server, the server would respond with a JSON structure with an empty "email" field and a null "password" field. According the BarStack API documentation I had written a few years ago, the response was supposed to include a "success" boolean, a "auth_token" string, and an "email" string.
After several hours of poking around, I finally noticed that my Ruby on Rails server process was processing GET requests from the Windows app when in production mode and POST requests when it was in development mode. There was something wrong in production that wasn't wrong in development. The Rails code was properly interpreting a GET to the sign-in path as an "index" action, but the Windows app should have been making POST requests that would be interpreted as "create" actions for the Rails server's sessions controller.
For some reason, POST requests were being turned into GET requests in my production environment before they were handed off to my Rails app's controllers. I checked my webserver's NGINX access logs to see what was going on. I saw that whenever the BarStack Windows app was making a POST requested, NGINX was responding with a 301 Moved Permanently redirect followed by the BarStack Windows app making a GET request for the same resource. I did some digging and found that NGINX could be redirecting the BarStack Windows app because of a rewrite rule. After a redirect, only GET requests can be made. NGINX wasn't the culprit, but this information did help me find the real problem.
After a couple hours of trying to get NGINX to log its redirects and confess to a crime that it didn't really commit, I moved down the stack a little bit. In the BarStack web app, NGINX hands off requests to the Rails app, and then the Rails app processes those requests with Rack before handing it off to the Rails app's controllers. In my Rails app's logs, the first POST request was never recorded, and NGINX wasn't responsible for sending the redirect response. That meant that somewhere in the Rack Middleware portion of the BarStack web app, a redirect response was being generated.
I opened up the gemfile for the BarStack web app and took a quick look around. In the middle of the file, I saw
gem 'rack-ssl', :require => 'rack/ssl' #enable https connections
Oh yeah! I had forgotten that I had started forcing people onto secure https connections. (The purpose of the rack-ssl gem is obvious when you consider its description on rubygems.org is "Rack middleware to force SSL/TLS.") Any connection that was made over http would get redirected to the same resource but with https, and my Rails app's controllers would never know about the original request! That expains why I saw a POST and a GET in my NGINX access logs but only a single GET in my Rails production logs.
I checked the BarStack Windows app's API endpoint, and sure enough, it started with http://.... I slapped an "s" into the endpoint constant, recompiled the app, and it ran smooth as silk.
And that's the story of how I fixed a bug with a single keystroke after 8 hours of debugging.
Photo by Forsaken Fotos
on May 8, 2016 by Kurt Tomlinson
If you have any reason to want to connect to your Raspbery Pi when you're away from home, you're going to want a dynamic DNS address. A dynamic DNS address lets you use a constant address like raspberry.johnsmith.com instead of an ever-changing IP address. This is useful if you've set up a VPN server on your Raspberry Pi or just like to tinker over SSH while you're away.
This tutorial hinges on the assumption that you have a domain name registered with Google Domains. If you have a domain with another registrar, then you should either move your domains to Google, or find another tutorial for dynamic DNS on a Raspberry Pi.
This tutorial lets you use a subdomain of one of your domains to point to your raspberry pi. After forwarding the correct ports from your router you your Raspberry Pi, you'd then be able to access your Raspberry Pi from anywhere in the world.
The first step is to go to the DNS records for the domain you want to use for your dynamic DNS address. There, scroll down to the Synthetic records section and add a Dynamic DNS entry. For me, my dynamic DNS entry is "raspi.kurttomlinson.com".
Next, expand the Dynamic DNS section of that web page and click "View credentials". This will show you a randomly generated username and password that you'll need later.
Next, ssh into your raspberry pi and install ddclient: sudo apt-get install ddclient. Once it's installed, a few prompts will pop up. It doesn't really matter what you enter into the prompts. The prompts are used to created a configuration file for you, but we're going to replace that configuration file anyway.
sudo apt-get install ddclient
To edit ddclient's configuration file, enter sudo nano /etc/ddclient.conf. Make the configuration file look like the image, but replace the username and password with the username and password you got from Google Domains earlier. Replace the last line with the dynamic domain you created earlier on Google Domains. Here's the content of the config file for your convenience:
sudo nano /etc/ddclient.conf
# Configuration file for ddclient generated by debconf
Finally, make sure that ddclient gets run at boot. You can add ddclient to your rc.local file to do this.
Photo by The Preiser Project