Showing posts with label hardware. Show all posts
Showing posts with label hardware. Show all posts

Friday, January 29, 2021

Instrument Cluster Board Level Repairs And The Evils of Lead Free Solder

 My wife drives a Ford C-Max “energie” plugin hybrid. It is an awesome little car that Ford no longer bothers to sell in the US because they failed to market it well enough and it became unprofitable for them to keep them around. Or it is possible that Americans really are only interested in double sized trucks and SUV’s and simply don’t want smaller cars at all. I don’t know but I suspect a combination of both problems exist. In any case I was in Chicago 4 months ago caring for my mom and I got a call from home saying that the dashboard on the car was completely blank. Had to manage remotely getting her a rental and getting the car fixed at the dealership. A couple of thousand dollars later we had a new instrument cluster as the old one was dead. It took weeks to get fixed as a new one had to be ordered with the proper odometer reading burned into it. 


This morning it did it again! Not even a full 4 months later! Car starts but the instrument cluster stays dark and eventually the touch screen/ radio comes up with a message that says “Vehicle Network Communication Error” and will not do anything else. Other interesting side effects are that the climate controls defaulted back to Celsius without being able to talk to the instrument cluster. 

Since there is no way to control most of the car and no way to know easily how fast you’re going the car is simply not safe to drive that way beyond just not having to have it towed to the dealership. 

The local Ford dealership said that since this was an electrical problem it required special attention from special people and they wouldn’t be able to even begin to work on it for 5 days! Don’t bother bringing it in before this coming Wednesday! And no willingness to tell me if this would be a warranted repair since they just did it. 

As I sat here fuming about how long we’d have to rent a car for as they ordered another new one for us I decided that since it was dead anyway I’d take it out and have a look at it. I’ve rarely regretted doing that and have often found that I could make a repair to something that would have cost a lot of money to replace unnecessarily. 

It turns out that it’s very easy to remove the instrument cluster from most Ford cars. There are lots of youtube videos about it but basically you pull the cowling that connects the rubbery sheet that covers the top of the adjustable steering column to the plastic under the cluster straight towards you and then that reveals the 2 7mm bolts that hold in the cluster. Make sure to adjust the steering wheel all the way down and forward or you can’t get it out. On this C-Max there are 2 clips that you need to force to let go directly behind it, but I have no idea if just yanking it straight out is the right thing to do for your model or not. It was the right thing for mine. Grab the cluster and pull it straight towards you until they let go. If you do it wrong or yours is held on differently though you might break something expensive so find a take apart video for your specific model before you start applying excessive force to anything.

There is a single connector on the back that you can reach around and find the pinch spot to easily remove it. You may want to put a towel over the cowling part or any other exposed plastics to keep from scratching them as you figure out how to get the cluster out from between the steering wheel and the dashboard. It is possible, but only just.



 

It actually look me longer to clear enough room on the desk to work on it than to get it out of the car ;) After carefully removing all the other plastic coverings you get to the point of having to remove the speedometer meter pointer. There is no D shaped or otherwise locking connection point for this. It is strictly a friction fit piece of plastic pushed down over the pin that comes up from the stepper motor that drives it. At this point it is recommended that you take a piece of tape, I used electrical that didn't seem to damage the plastics or paint or printed parts underneath it but go easy on it, and make that line up with exactly where the pointer is at it's sopping point. You'll notice it is a little below zero but if you get this wrong when you put it back together you'll be driving at a speed other than what you think you are. "I took the dash apart Officer and evidently did not get the pointer back on right" is not going to get you out of a speeding ticket. Put some tape on the underside lined up with it's stop point so that you get it back together right.

I used a "spudger" and very gently pried it up on both sides. The plastic these parts are made of feels like the lowest quality styrofoam and I believe they would break if you so much as looked at them wrong. If you don't have a proper spudger put some cloth or something to protect the black plastic background as you pry upwards or you will damage it and have to look at the light soaking through your scratches forever.

The next thing you have to remove to get to the board are the connections to the 2 screens on either side. I didn't capture a picture of this but I HATE these kind of board connectors. I've ruined many similar ones on Raspberry Pi camera connectors or others. In this specific one the connectors had a black plastic bar across the ribbon connector that you VERY GENTLY pried upwards to release the ribbon cable and then could slide the ribbon cable out. For me they worked very well but if you have any qualms about this sort of thing don't do it. You must remove them to safely work on the board though because once you take off the front plastics nothing else is holding them in place and any force or movement will be transferred to the connector which will either rip the cables or tear the connectors right off the board. It does not take much force to do that at all so really be seriously careful at this point. I would also make sure you don't confuse the left and right screens. I couldn't see any difference in looking at them but it seemed like a good idea not to put it back together backwards. They would certainly fit just fine backwards but who knows if they have different firmware or something.

And finally you'll have the nice board you can have a good look at!



It is, of course, almost entirely surface mount and there just isn't much you can do about that unless you're much more of a professional soldering god than I am. I put it under the inspection microscope and can see a lot of connections that looked a bit iffy to me. The first thing I did was to put some flux over the through hole pins that go to the connector on the opposite side of the board. You can see them as two rows of parallel pins in the picture aboe right in the middle of the board towards the top. I then carefully touched each one up with some nice antique leaded solder making sure not to over do it. I then searched the board for other such connections and found lots that looked like they were not particularly well done. I also touched up the larger connections in the several different power regulators on both sides of the board though I don't know if that or just the connector itself was what finally brought it back to life.

Many of the CPU connections looked quite badly done to me as well but I did not try to reflow any of them in the initial attempt to get this working as I was almost certain that if I touched them I'd make things worse and not better.

I re-attached the screens and the plastic case parts necessary to hold them and provide for the cable attachment point to the car and took it back to the garage and low and behold it lit up!


Took it back upstairs and re-affixed the speedometer indicator and the rest of the plastics and it kept working! 

This is almost certainly a failure to make proper connections while using lead free solder. The connections seem to become brittle and just break. I have assembled only 1 device with lead free solder, a wonderful clock kit and every 2 years I have to take it apart and resolder one of the LED displays with good old fashioned lead free solder as the original connections fail one after another. 

It should be possible to do such things properly with lead free solder, but it is my opinion that it requires slightly different design and probably different or better flux and other such things. The solder joints themselves look so horrible with lead free solder that I think it would be impossible to validate them with visual inspection the way you can with leaded solder. A cold leaded solder joint is obvious. The ones that failed with lead free solder look identically awful to me to the ones that are still working. 

In any case, if you have the skills you should take things apart and look at them before you pay someone many thousands of dollars to replace it. We may be putting less lead into the land fills but we're putting a lot more entire assemblies into them because of it. It seems there should be a solution that properly recycles leaded boards while still letting you use what is so obviously a superior way of making things that should last for more than a few years.

I'm off to cancel the appointment at the Ford dealership for next week and to complain to someone who has no idea what the parts are made of and who won't know who to contact to complain at corporate that their instrument cluster boards are patently defective because they have not carried lead free solder construction techniques over into their new lead free board designs. I know it's pointless but I'm still going to complain to them...

Monday, August 3, 2020

Power Supplies for ESP32 Arduino Based Projects

You’ll be surprised to learn that not all power supplies are created equal ;) Or if you’ve bought more than 1 or 2 online you’ll not be surprised by that at all. There are some that are so wonderfully cheap and seductive that you purchase them only to have them fail on day 3 or do something even worse. I have fallen prey to that in the past, but not anymore. This post is nothing about any of that, but just the well documented differences between name brand (not rip off!) imported power supplies. There are still issues you need to be aware of when selecting a power supply for your Arduino or IOT based project and evidently, specifically for your ESP32 based projects. 

Here you’ll see 2 name brand, Mean Well Din rail mounted power supplies of similar ratings.


The one on the left is a MeanWell model: HDR-15-12 with a slightly blurry sticker on the top which I apologize for. It accepts line voltage input and outputs 12v at 1.25 amps. It is also very nicely tiny and uses only a very small amount of your din rail space. It’s also cheaper than any other Mean Well supply I’ve seen of similar output. It also did not work reliably with an ESP32 based IOT device. The one on the right is also a Mean Well supply model DR-15-12. It also outputs 12v at 1.25 amps but it has the “DC OK” indicator on it.

The cheaper one on the left caused my ESP32 based device to reliably startup in firmware upload mode if you waited long enough between re-powering for the internal capacitors to be discharged. If the power was disconnected for more than a minute or so the device would not properly restart when power was applied again! This is obviously not acceptable as you need to be able to plug in a device and have it actually start up. The DR-15 model on the right starts up the device every single time without any care for how long it’s been disconnected and is only slightly more expensive and only slightly wider than the cheaper one.

So whats the difference? The only thing I can find is that the “Rise Time” on the spec sheet for the 2 is significantly different. It is listed in the “output” section of the sheet and along with the “setup” time. The setup time is the amount of time between when power is applied before the output actually turns on. If you’ve used many switching power supplies you’ll have noticed that there is a delay between applying power and any voltage coming out of them. This is not generally an issue, just the housekeeping and charging up of everything that the power supply must do before it is ready to supply regulated output. It’s the “Rise Time” that seems to be important. 

In the case of the cheaper HDR-15 model the rise time is 80ms. Which doesn’t sound like a lot. The slightly more expensive one is only 30ms. I have measured these on the scope and it does indeed seem like they are the problem. In my case they are running a secondary 3.3v switching supply on the board, so your exact requirements and the point at which is causes you trouble will be different based on that.  

It does seem that a longer Rise Time can cause the ESP32 (and possibly ESP8266) based designs to startup in firmware upload mode, as if you were holding gpio0 to ground even when you are most definitely not, rather than starting up normally.  There is some allusion to this in the ESP32 documentation about making sure that if you’re running from batteries that you have a power controller that will not apply power to the ESP32 until it is above a certain level. Or as I’ve learned if it is going to within 30 or 40ms but not as long as 80ms. Keep in mind while testing that if I unplugged and replugged the supply within say 10 or 20 seconds it would come up fine. It was only with power outages that lasted long enough for it to discharge all it’s internal caps that it would fail.

While the exact timing that causes your design problems will be different based on the 3.3v regulator design if you have this specific issue then I would first recommend testing with a power supply with a faster rise time. In my case the chip just did nothing when powering up. Re-applying the programming cable revealed the “waiting for download” message from the ESP32 making it clear that it thought I was grounding the gpio0 pin even though I wasn’t. With a faster rise time it starts up reliably every single time. 

Thursday, October 17, 2019

RGB Fairy Lights with only 2 wires (part the first)

I am a huge fan of all things blinky and light up. I’m less interested in things I cannot control remotely by writing a plugin for XTension or by building a new controller for it. While looking for RGB “fairy” lights on Amazon (“fairy” lights here being defined as some strands of what looks like magnet wire with surface mount LED’s soldered between then and then sealed into a little blob of epoxy) I came across these RGB ones and was intrigued since they appeared to have only 2 wires. There was no control wire or separate PWM lines for the RGB channels. (Amazon Link) These are by “Yihong” but there may be others that are the same.

They came with an RF remote which is nicer than the IR ones that some similar things come with. Since you don’t have to point it at the controller box. Interestingly enough the remote also has an IR led and so could be used by either type of system. I have not tested to see if it is running on the standard 433mhz band or does something special. Given that it appears the same as the thousand other such remotes I’ve gotten over the years for other LED displays or just for remote arduino projects I would guess that it does.
In spite of the picture on the box showing different colors on the strand at the same time, you cannot control the LED’s individually, only as a whole strand.

This is the very tiny control box. The strand is powered from a USB plug and this box does the work of receiving the remote signals and adding whatever data is necessary to the power lines going down the strand. I have not broken the case open yet to see whats in there.

While there is tons of information out there about the “neopixel” type LED’s and the newer “dot star” that Adafruit sells and are amazingly wonderful there is very little information about anything similar to this. If anybody knows the type of chip or LED that they are made from I’d be interested to hear about it.

This you tube episode from Julian Ilett shows him reverse engineering a similar protocol. The system used by my lights looks to be very different however. So the first step to seeing what it’s doing is to get it on the scope. Since the wires are just enameled I scraped some of the insulation off them at the end of the strip. It occurs to me that I might have gotten a cleaner signal by tapping it at the front of the string instead. I’ll try that in step 2 and see if it makes it easier for the scope to trigger on it.

These LED’s are different than Julians as they don’t pulse all the way to off. The data pulses drop the voltage to the lights down to 1.5 volts, but not all the way to off. This potentially makes sense as it would let the little processor in the LED chip continue to operate as it’s being updated.


Here you can see the amazingly noisy USB power supply, either from the hub I was using to power this or from the controller device itself I don’t know, but it didn’t seem to bother them. You can also see the tiny blips of the control pulses coming in every 100ms or so. 

 
Zoomed in on those a bit you can start to see the data.



There are 2 lengths of pulses. Since the on portion of the pulse is always the same length the entire duration of the data packet changes based on how many 1’s there are in it.

The short pulses, which I will call a binary 0, are approximately 5us with the bus at 1.5v and then 10us back at 5v. The actual measurements I got from the scope was 6us and 12us but they varied enough that I assume they meant to use 5 and 10us. That may have to be adjusted later if the device is very picky about the timing. The 1 binary pulse is 10us at 1.5v and 10us at 5v.

Every data packet starts with 8 “0” or short timing bits. These do not appear to change no matter what the string is displaying so I will assume they are a preamble that helps the receiver lock into the data rate. In the screen shot above you can also see the end pulse which is twice the length of the “long” or binary 1 pulse, 20us at 1.5v. 

There are 32 bits in total, one byte for the preamble and 3 more bytes which obviously encode the RGB values that the LED should display. I did several captures from the various solid colors the three different intensity levels, leaving out the preamble byte: I’ve added the decimal value of the binary next to them:

RED:   FULL:  0010 0110(38)  0000 0000     0000 0000
       MED:   0100 1100(76)  0000 0000     0000 0000
       LOW:   1001 1000(152) 0000 0000     0000 0000

GREEN: FULL:  0000 0000      0010 0110(38)  0000 0000
       MED:   0000 0000      0100 1100(76)  0000 0000
       LOW:   0000 0000      1001 1000(152) 0000 0000

BLUE:  FULL:  0000 0000      0000 0000      0010 0110(38)
       MED:   0000 0000      0000 0000      0100 1100(76)
       LOW:   0000 0000      0000 0000      1001 1000(152)

Its quite obvious already that the 3 bytes are RGB values. You can also see that even when on at full they dont send just an FF. Perhaps the LEDs would overheat at full on. There is some visible PWM even when a solid color is set to full on. Or there is a limit in the controller device itself that is not capable of 255 individual levels. They are rotating that bit pattern across for dimming the LED. At this point Im thinking that the value is actually how long to wait into the PWM cycle before turning on that LED. That would make sense, it would let a larger number actually be a dimmer display. Just for fun sampled some of the other colors as well:

ORANGE: FULL:  0011 0001(49)  0101 0000(80)  0000 0000
        MED:   0110 0010(98)  1010 0000(160) 0000 0000
        LOW:   1100 0100(196) 0100 0100(68)  0000 0000

YELLOW: FULL:  0010 0110(38)  0100 1100(76)  0000 0000
        MED:   0100 1100(76)  1001 1000(152) 0000 0000
        LOW:   1001 1000(152) 0011 0000(48)  0000 0000

CYAN:   FULL:  0000 0000      1101 0010(210) 1101 0010(210)
        MED:   0000 0000      1010 0100(164) 1010 0100(164)
        LOW:   0000 0000      0100 1000(72)  0100 1000(72)

and now Im wishing I hadnt sampled those extra colors as they dont seem to follow the same start point of PWM. Or perhaps they are just compensating for irregularities in how much the LEDs output at any given level. They wont be the same certainly, generally red needs a much higher value than green and blue to look the same. 

In any case there is enough information here to get started trying to build an Arduino controller for the thing. I’m not entirely sure how to provide the 1.5v pulse level in hardware. Will it be enough to just run the stream power supply through a resistor? Will have to calculate the power draw of the LED’s and do the math to drop the voltage to that level. Or are the LED’s in sync with this pulse and so will be off when the data starts and therefore I’ll need a different value since the load would be less. Or will it be necessary to provide a 1.5v regulator and use a transistor or mosfet to bypass it when the strip should be given the full voltage. Some experimentation will be necessary. When I’ve had a chance to play with that I’ll post again.


Friday, May 8, 2015

XTension Smart Meter Reader Kit

I am pleased and proud to announce the XTension Smart Meter Reader Kit



The arduino IDE compatible board reads the calibration pulses available on many smart meter models and outputs to XTension the instantaneous usage, the peak usage, the wh used since the last packet and the wh elapsed since the last nightly reset of the counters.

Communications back to XTension is done via an xBee radio, any other “bee” device with the same pinout and power requirements or any other means you wish via the serial data pads on the board.

Kits are available for shipping now starting at $45USD without xBee radios. The included electric meter attachments are 3D printed to order.

Though this kit is designed to interface with the XTension for Macintosh home automation software and does not come with any kind of display system, you could certainly make that a second arduino receiver project if you wished to do it yourself. The firmware describing the data output is open and available on the MacHomeAutomation wiki linked to above.

Sunday, April 26, 2015

XTdb update and Lightning Sensor for XTension

Lots of work done recently on the day job over at XTension.

An updated version of the graphing and database add on to the program that provides motion reports and lovely graphs. I replaced the simple graphing engine with a commercial one that has already added several features like transparency and on/off graph zones. Very useful and a great update. Many more possibilities are coming in future builds. You can get the new version from the XTdb home page

Today I finished a tutotial for connecting a very nice Lightning sensor to XTension by way of an Arduino and an xBee radio. I’ve been enjoying the storm alerts from this on my phone for a long time now and am finally getting around to posting the tutorial for everyone. XTension Lightning Tutorial

UPDATE: 4/28/15 and digi liked the lightning tutorial so much they added it to their gallery site! http://gallery.digi.com/2015/04/28/lighting-sensor/

Sunday, September 14, 2014

xBee network hosted remotely off a Wiznet TCP/Serial board.

Wow, haven’t posted any projects since may 8th?! Most of my effort was spent in playing with the kids over the summer and in porting XTension to Cocoa. We’ve been a carbon app so long because we like to support older operating system versions, indeed we still supported PPC machines up until the most recent build. Thats just got to change, we’re never going to be in the app store or run properly in the sandbox if we don’t get around to leaving some of that behind. The PPC and pre-10.7 builds of XTension will continue to receive bug fixes but are basically done. I’ve been running my house on the cocoa version for almost a month now without difficulty and the ease of doing some important things is just wonderful. Even though the conversion was not at all painless it’s coming along nicely and the UI things I can do now alone make it worth while.

The last few days I’ve been fighting with an xBee breakout board and a Wiznet card trying to build a remotely hosted xBee network. Under most circumstances you can just add more xBee’s in between the area you need to cover and the host machine and connect it directly to the XTension machine, but that isn’t always feasible. So if you have any desire to host an xBee network with the xBee coordinator sitting on an ethernet network somewhere other than where you can reach with a USB cable from your XTension computer here’s the connections you’ll need to make.

Mac Home Automation - Hosting an xBee on a Wiznet card

Tuesday, August 6, 2013

Tankless Water Heater Musings

One way of saving money and energy that is touted greatly is a tankless water heater. As I understand it there is still some controversy over just how much money this will save you, and they tend to be rather expensive so the payback can be long. A year ago or so I strapped a temp sensor to the inlet and outlet pipes of my traditional tank water heater so I could measure it's usage and see just how much it's running when nobody is using water to give myself some idea of the use of a tankless water heater here.  Specifically they are dallas 1-wire sensors connected to a Barix, Barionet 50 and finally reading their data in to XTension.




Here is a few recent days worth of data. Yes, I know I have the temperature turned up too high, but this is the kitchen, laundry and master bedroom heater and not the one in the kids rooms. My kids are big enough now that it's not that much of a danger to them. The second water heater that serves their rooms  is still turned down to 120 though so don't worry about us.

The blue line is the cold inlet temp and the red line is the hot output line. The first thing I see is that the cold inlet temp rapidly reaches the same temp as the outlet as soon as you stop using water. That makes me suspect there isn't a heat trap or whatever that fixture is that is supposed to reduce heat loss through the pipe on that line. I'll have to investigate that. But the other thing you see is that in these 3 days there isn't a single point where the cold water inlet temp spikes without a corresponding spike in the outlet temp. Meaning that the water heater hasn't run once not in response to demand in the last 3 days. As it turns out I have to go back to July 24th to find a graph that shows a "maintenance" cycle just to keep the tank warm.


There, at 2:30 in the morning the cold temp spikes with no hot water use measured. I have to go back several weeks again from this to find another one. If I switched to a tankless heater those would go away, and any energy wasted by them. But how much would that be? 2 or 3 waste cycles a month isn't very much to pay back the high cost of a tankless water heater.

The other factor to consider is efficiency or how well does it put the energy that it uses into the water. It was my understanding years ago that electric tank water heaters are nearly 100% efficient, meaning that almost none of the energy is lost, it all goes into the water. Gas water heaters like mine do lose quite a bit of energy up the smokestack, but so do gas tankless. This is an area for further research, but I do not believe that it's a huge difference at this point. At least not enough to make me replace a currently functional hot water heater. When it's time to replace it though I will look seriously again at these figures and it may make sense in the future.

There is an additional consideration as well in cost. Gas tankless water heaters require a lot of gas, they have a minimum pipe size in order to get enough gas. At the placement in my attic where it would replace the existing water heater I would have to have new gas piping run to support a tankless of enough capacity for my home. At considerable expense. The same holds true for electric, you have to have a high amp service run to where it is, they can't just be plugged in to a handy outlet. They use a huge amount of power. If you're on a peak metering system that changes you more if you use large amounts of power your electric tankless is very likely to put you close to or over the limit so the power you use for it may be much more expensive. Do the math on this or you may be very unpleasantly surprised.

Just thinking out loud here, everyones situation is different and it may make perfect sense for you to get yourself one of these. If you use a LOT of hot water you'll never run out, and if you use very little hot water you dont waste energy keeping the tank warm. Though if the tank is like mine the number of those phantom cycles might be very few.

Monday, July 15, 2013

Building and interfacing an Arduino barometer sensor with XTension

With the initial release just the other day of the Arduino interface for XTension I find that I want to do just heaps of examples and demos. This is the perfect startup project as it's very simple build and fairly simple software. Though I've added features to the software that adds functionality and tries to get around the limitations of the sensor the basics should be easy to see in there.

The Arduino interface is just a simple ASCII protocol that sends and receives name=value pairs to XTension which end up in the standard units in that home automation program.

This project is going to build a barometer and put the data into XTension as well as take a crack at measuring a rising/falling trend and report that as well.


You're looking at all the necessary hardware. The code is specific to this kind of barometer sensor, but any arduino uno or compatible should work. The only other needed accessory are 4 female to male jumper wires. They aren't strictly necessary, but without them you have to do more soldering.
The barometer breakout board is the MPL115A2 from Adafruit for just shy of $12 as of this writing. There are other models but they were more expensive (and also more accurate) but if you use a different one you'll need to alter to code to include their libraries and different access methods. 

UPDATE: I've redone this with the $20 BMP085 also from adafruit. It gives much more resolution and usable data. Everything else is the same, I've uploaded the arduino project at the end to support the different board but wiring it up is virtually identical since it's also an IC2 device. So the same 4 pins need to be connected but they are in different locations on the board so read the labels and not just go by the positions in my pictures here. This is the new board:



Adafruit has an excellent library making the reading of the pressure (and it has a built in temp sensor too) just a single line in code, you don't have to worry about any of the low level stuff at all. You just include the library and say read pressure. 

Since we're going to plug this directly into the XTension server via USB you'll want an Arduino with a built in USB/Serial adaptor. Apart from that any of the Uno types will do.

The only soldering you have to do for this project is to connect those headers to the barometer board. If you're doing without the molded cables you can skip that and solder directly to the pads. 


 Standard soldering precautions apply. Don't overheat the board or the surface mount components might come off, don't overdo the solder or you may bridge pins, wash the lead off your hands if you're using leaded solder before dinner... But this is easy.




Lets make the power connections first, connect the "vdd" labeled pin to the +5v pin on the arduino and the gnd pin to a ground pin on the arduino. 




(REMEMBER that the BMP085 board is different than the one pictured. The pins have the same labels but are physically in a different order than in the pictures I posted above)

Next up the data connections. Follow the info on the Adafruit site for connecting them but on mine the barometer pin labeled "SCL" goes to analog pin 5 and the barometer pin "SDA" goes to analog pin 4. This is actually an "I2C" data bus which is an interconnect protocol for small computers like this. Theoretically you can hang many devices off those same 2 pins and talk to them by address. In reality most devices, like this one, have a fixed address and you have to desolder or add surface mount resisters to change it so that more devices can be connected. But that doesn't matter here.

After you get the wires plugged in it's a good idea to drop on a small amount of hot glue to hold these connections in place. They are really just meant for temporary breadbording and prototyping but with a little glue you can keep them from getting unstuck while still making it easy to take them apart on purpose should you ever wish to recycle them.




 don't over do the hot glue, if you get it in other holes you'll be stuck if you want to use them later. Just a little will hold them together.


now we need to load in the firmware.  If you're already old hat with the arduino IDE you can skip this bit but I'm going to document a few of the things that were confusing to me. Download and install the latest version of the Arduino IDE from their download page. Next you'll need to download the Adafruit library that simplifies the communication with the barometer. They use a github repository as of this writing and it's confusing if you've never used it. The github page is here and you're looking for the "download ZIP" button to get the whole thing.

Decompress the resultant file and you'll have to remove the "-master" from the end of the folder name. Arduino doesn't like the "-" character at the end of it. Now you need to find or create the hierarchy of folders on your Mac (assuming you're using a Mac which most of you will be since XTension is a Mac app...) When you run the IDE it will create an "Arduino" folder in your documents directory. Inside of that you'll need to find or create if it's not there a folder called "Libraries" and place the "Adafruit_MPL115A2" folder into that. If the IDE is already running you'll need to quit and restart to make it pick up on the new folder. If it worked you should see a folder for it under examples in the file menu something like:


If you see that then all is well and you can download and open the arduino source code. Place that folder inside the same Arduino folder in your documents folder. Projects must live there. If you click the checkmark and it says compiled and gives you a size for the compiled project then everything worked and you're ready to program the Arduino. 

Connect the arduino to the Mac in question and you should now be able to set the board type and the port name under the "tools" menu. then click the upload button and program your reader. after the upload is complete if you click the magnifying glass icon in the upper right hand corner of the program window you will get the serial console. Make sure it's set to 9600 baud and you should get the arduino barometer startup message and in 20 seconds or so start to see updates being sent. If thats working then you can move on to the next step and connect it to your XTension machine and create the necessary units there.


My install just looks like this at the moment, I want to be able to remove it and easily reprogram it as I refine the firmware. Pegboard is also dead useful for hanging all your home automation doodads off of. 

First step is to create the interface. Open the preferences window and create a new interface, set the device type to "Arduino" and select the silly and non-descriptive serial port name that is created for it in the port popup. Add a port command to it so you can more easily find it again later once you know what it is. Depending on the kind of arduino it may have the same name as on the machine you used to program it, or like the Uno i used it has a different name on that machine, I have no idea why. 

Don't enable the interface yet though, just save it. First we need to create a couple of units to hold the data. One for the pressure and one for the temperature. You may not need to use the temperature for anything and I dont know how accurate it is but you get it for free so you may as well record it.


The pressure unit should look something like this, you can call it anything you like but the interface needs to be the same as the one you just created and the address must be "pressure" Add the "hPa" unit of measure for better display. The unit needs to display numbers and not just on and off so check the dimmable checkbox and both the receive only and ignore clicks in list to keep you from accidentally changing it's value while using the UI.


The temperature unit is very similar but the address must be "temp" in the arduino code I am converting the temp to F since this is America, but if you wish to keep it as C see the arduino code comments for info on changing that. Use "option-k" to create that degree sign. Go ahead and enable the interface in the preferences and you'll start to collect data.





The description will initially say "calculating" for about half an hour as it collects data and starts watching for a trend. I'm not sure how good thats going to actually work. the logic I"m using is that I look back 15 and 30 minutes from now and compare them with the current reading. If they are all going up I say rising, if they are all going down I say falling otherwise I say stable. If anyone knows the convention for calculating the trend let me know and I'll adjust the code.

I'm also not entirely sure about the proper resolution and hysteresis for the pressure value. It reports directly from the device with 4 decimal points, but they bounce all over the place. I'm taking a reading every second and averaging the last 20 of them together and then rounding to just one decimal point to get any thing that doesn't just bounce uselessly around. It may be my unit, or it may be that the math just works out to far more decimals than it's accurate to. When I look up the pressure on my local weather site this seems to keep it in good sync and the resolution seems similar to what they display but if anybody knows more about this and what it should be let me know. 

If you have XTdb installed you can generate interesting graphs. The output of the new board is in hPa, not kPa but I might have missed some of that when updating the article above. In this graph I have the temperature output and the pressure for the last 24 hours here at the house.



Sunday, June 16, 2013

Arduino, xBee and PWM lighting with XTension

Back on Halloween Ben and I built him a gigantic lightup inflatable pumpkin costume that was a great deal of fun. In addition to the el wire face on it we also built him an electric t-shirt with LED strips attached to an arduino, some buttons for lighting effects and a little 12v battery pack to power them.

You can see them there under his costume, at night they put on a great show, flickering and fading in and out and flashing brightly when he pushed the button that let them accentuate his awesomeness while trick-or-treating.  We used these cool white LED strips from adafruit.com. After halloween I removed them from the t-shirt and saved them for future projects. A future project revealed itself shortly thereafter in the form of aquarium lighting for his new fish tank. We didn't do any fancy remote control or PWM on them for version 1. We just taped 2 of the 4 little strips to some shelf support material I had and powered them from a generic 12v wall wort.

They worked great for a while, but the constant splashing of water on them and the metal bars soon took it's toll. I think that the power supply may have been a bit high too for they rather quickly started to degrade and individual LED's started to go dim. Even so they lasted several months, but finally died and it was time to rebuild. We had 2 more strips left over from the costume and this time we decided to do it right. PWM to control the levels so it could be dimmed, an xBee radio so that it could be wired into the Home Automation System and some buttons so he could set the level there. I had just finished an arduino interface for XTension and so decided that this should be a demo project on how to bring some of these things together. 

Here you can see how far the old LED strips degraded. The metal shelf support is rusty, the LED strips have gone opaque and you can see where some coper was exposed and turned bright green.


Yuck... This time I would build something with proper heat sinking and proper protection from the elements. I used a  piece of aluminum extrusion U channel as the base for them. It's available at HD and others as a shelf support. It's meant to go over the long edge of a plywood or particle board shelf to keep it from bowing in the middle. It wasn't quite the perfect size for 2 LED strips, they were a tight fit, but I added some extra adhesive behind them as well. 


Also you can see one of the bezel pieces. I printed those on the MakerBot out of translucent PLA. They are actually less translucent that I had though and I might replace them with just cut pieces of plastic soon, but they work for now to protect the lights from the water.

For the Arduino I went with a Fio. I'm not using the lipoly battery charging ability of it, just the fact that it's an arduino with an xBee socket built in. Both running at 3.3v so no other circuitry is required. Or so it seemed... The LED strips need to run at 12v, the Fio is rated at 12v input and initially booted and started up OK, when I had it wired in circuit and applied 12v the regulator on the board burst into bright flame or arcing or something. I removed the power with some alacrity thinking I had cooked the arduino and probably the xBee as well. Testing from USB power though showed them both to be just fine. Now thats impressive, a piece of gear that can actually catch fire and not break down! So instead of relying on the on board regulator I added a beefier external 3.3v regulator. That also released it's magic smoke upon startup. So at this point I took a step back and reviewed the rest of my wiring. Had I wired the mosfet backwards and was putting 12v into one of the input pins or something? Nope, everything looked good. So I broke out an anyvolt micro adjustable regulator and hooked that up instead. Adjusted it's output down to 3.3v and all was well. I guess 3.3v linear regulators just dont like an input as high as 12v. There are many dc/dc converters on the market now, and anyvolt also make a 3.3v version, but the adjustable was what I had on hand. Connecting that to the 3.3v input and bypassing the internal regulator completely brought it all happily back to life.



The mosfet in the picture makes PWM'ing high loads so very easy, no external parts required, not even a resister. This particular model is an N-channel power mosfet and I wired it according to adafruits excellent examples that are linked to from that store entry. Thats actually the same one that powered ben's halloween costume so it's still got some lumps of hot glue attached.  A $1.25 saved is a $1.25 earned ;) You can also see the LED strips powered up and running behind their makerbotted water protection. The plastic strips are just hot glued gently on top of the aluminum channel. I want to be able to replace them when they get a scuzzy from being in the water.


I mounted all three devices into a tiny plastic parts case with a hole drilled through the top/bottom for the xBee antenna. If you were using a lower output one with a chip antenna then even that wouldn't be necessary. 


The buttons in their final install position on the fish tank. Not very pretty, this end of the project will likely get a reworking.

The arduino interface for XTEnsion just provides a simple text based interface for sending values back and forth. basically just address=value with a return at the end. It can be extended of course ;) but for this that wasn't necessary. I opted to make the buttons and the light totally separate in the device itself, requiring the intervention of the computer in order to send back the light level in response to a button push. This means that you can't control the light if the computer if offline, but if the computer is offline I've got bigger problems than the fish tank lights. So in this code the buttons just send an ON when they are pushed (and no off, though I could do that easily enough if it's useful) and then the computer responds by sending a level for the lamp. There is a heartbeat delay between pushing a button and the response coming back, but this way I can set the levels in the computer without having to recompile the arduino code, or without having to write a lot of code to save the levels into the eeprom. So there are other solutions if you like that. You could also build this without any remote computer in the mix at all by just setting the lamp PWM value in the processButtons() handler. But this is an example of how to write arduino code that talks to XTension.


This is how the units are setup in XTension. The buttons receive the commands send from the arduino like:
  Serial.println( "button1=on");

and if you change the aquarium light units level it ends up sending a command like "LAMP=160"

XTension will also convert the address to be all caps, so keep that in mind in your arduino when comparing strings. In the code you'll see some commented out map commands as I was going to map the standard dim level in XTension, 0%=100% onto the range of PWM outputs available on the arduino, 0-255, but decided not to, just let us control it from here. In experimenting with it we discovered that 160 was plenty bright for the fish and the plants and struck a nice comprimise between light and heat output. Any more than that and the light bar started to border on hot rather than just warm. I want to keep these LED's for a long time so we are not going to let them overheat. And a value of just 4 is bright enough on the dim setting for Ben to use as a nightlight. It really does look like moonlight at that level and is quite pretty.

The computer control is important separate from the button control so that the lights can be turned on remotely when we are on vacation, or if he fails to turn them on in the morning. Since feeding the fish and turning on the light is part of his morning ritual he rarely forgets. But now I know when he last turned the lights on, and if it doesn't happen I can turn the lights on automatically and send me an alert so that I can feed the fish if he forgets. He's 8 and is really very good at taking care of them, but it does happen. 

Since the arduino has plenty of inputs and outputs available we have plenty of room available for future expansion. I think a water temperature sensor is in the near future, that will be easy. Perhaps some UV or deep blue LED's to make his fluorescent fish light up at night too. We're also starting to think about an automatic feeder that we would design and print on the makerbot and control from this same arduino.

Setting up xBee radios to work with XTension needs an entry of it's own as well. That will come shortly. Here is the source code free and open use it as you wish. download the arduino project

/*

  Ben's aquarium light 
  
  using an xBee to talk to XTension

  June 10 2013  james@sentman.com
  
  In this example, the 3 buttons send their ON to XTension when they are pushed, and XTension replies
  with the proper change to the light level. They do not directly control the level of the lamp.
  the lamp is only controlled from XTension by way of scripting from the button units.

*/


//input and output pin definitions
const int lampPin = 3;
const int upButton = 8;
const int midButton = 7;
const int downButton = 12;
const int ledPin = 13;

//these globals are used by the serial interface for talking to and getting commands
//from XTension via the Arduino interface. All commands are sent as NAME=value pairs with a 
//carriage return at the end. Set your buffer sizes to be at least as big as the longest command
//you expect to receive. These are oversized as only a single value is sent.

const int commandBufferSize = 19;
const int valueBufferSize = 22;
char commandBuffer[ commandBufferSize + 1];
int commandBufferIndex = 0;
char valueBuffer[ valueBufferSize + 1];
int valueBufferIndex = 0;
boolean gotCommand = false;


//debounce necessities
unsigned long lastButtonMillis = 0;
unsigned long currentMillis = 0;
int currentButtonPushed = -1;




void setup(){
  
 //make sure xBee is set to same serial speed. Could use faster of course 
 Serial.begin( 9600);

 //set the pinmodes for in or out as appropriate
 pinMode( lampPin, OUTPUT);
 pinMode( upButton, INPUT);
 pinMode( midButton, INPUT);
 pinMode( downButton, INPUT);
 pinMode( ledPin, OUTPUT); 
 //turnon the pullup resisters
 //to simplify the wiring I'm using internal pullup resisters for the buttons
 //that way I only have to connect them to ground.
 digitalWrite( upButton, HIGH);
 digitalWrite( midButton, HIGH);
 digitalWrite( downButton, HIGH);
 //make sure we startup off 
 analogWrite( lampPin, 0);
 //could always save the current value of the light to the eeprom 
 //and retrieve it at startup so that a power outage for a few seconds 
 //wouldn't result in the light being off.
 //give the led a flash
 digitalWrite( ledPin, HIGH);
 delay( 500);
 digitalWrite( ledPin, LOW);
 //write to XTension that the system is ready.
 Serial.println( "log=Aquarium Ready");

 //and update it's unit so that it knows that it's not on
 Serial.println( "LAMP=0");
  
  
  
}


void loop(){
  
   //currentMillis is used in the button processing in several places
   //so instead of constantly calling to millis() just do it once and put it
   //in this variable.
   currentMillis = millis();
   //check the serial buffer for any waiting command data and process it
   //if there is any
   processSerialCommands();
  
   //check for any button state changes
   processButtons(); 

  
  
}

/*
  this is part of the Arduino interface to XTension
  it can easily be reused in future projects.
  this just manages the command and value buffers and reading of data
  from the port. Any actual received commands will be passed to the next
  processCommand() method. Add any other incoming value handlers or special
  commands there. This handler shoulnd't need to be changed for most things
*/

void processSerialCommands(){
   int workByte;
  
    //if no data available then just return, nothing to do this cycle through loop
    if (Serial.available() == 0){
     return;
    }
   //read a byte
   workByte = Serial.read();

   //since all data is sent and received as name=value pairs
   //initial data is added to the command buffer. When a 61 or "=" is recieved
   //we finalize the end of the commandBuffer with a nul and start adding future characters
   //to the value buffer.
   if (workByte == 61){
      commandBuffer[ commandBufferIndex] = 0;
      commandBufferIndex = 0;
      gotCommand = true;
      return;
   }
   
   
   //this is looking for the carriage return at the end of the command line
   //if it finds the return then it finalizes the value buffer with a nul and 
   //resets the buffer indexes to get them all ready for the next command
   // and finally passes the most recently received command=value pair to the process command
   if (workByte == 13){
     valueBuffer[ valueBufferIndex]=0;
     valueBufferIndex = 0;
     commandBufferIndex = 0;
     gotCommand = false;
     processCommand();
     return;
   }
   
   
   //if we haven't finalized the command yet (or address as it's now called in XTension)
   //then we add the byte to the commandBuffer and increment the index to wait for the next one
  if (!gotCommand){
    commandBuffer[ commandBufferIndex] = workByte;
    commandBufferIndex++;
    
    //make sure that we dont overrun the buffer though and reset it if we're receiving garbage
    if (commandBufferIndex > commandBufferSize + 1){
      commandBufferIndex = 0;
      return;
    }
    
  } else {
    
    //we've already got the command because gotCommand has been set to true by the
    //check above for a 61 value or "="
    //so now add instead to the value buffer, increment it's counter and continue
    valueBuffer[ valueBufferIndex] = workByte;
    valueBufferIndex++;
    
    //make sure that the value buffer doesn't overflow and if so then
    //reset both the command and value buffer due to garbage on the line.
    if (valueBufferIndex > valueBufferSize + 1){
      commandBufferIndex = 0;
      valueBufferIndex = 0;
      return;
    }
  }
  
}

//XTENSION here is where you will receive incoming commands use the string objects to manage your response
//  add as many addresses as you need.

void processCommand(){
  String theCommand = String( commandBuffer);
  String theValue = String( valueBuffer);
  
  if (theCommand == "LAMP"){
    
    if (theValue == "on"){
      setLampLevel( 100);
    } else if (theValue == "off"){
      setLampLevel( 0);
    } else {
      setLampLevel( theValue.toInt());
    }
    
    return;
  }
  
  //add as many more comparisons for theCommmand as you need to for your application
  //XTension will always send address=value pairs if it's a change to a unit, though
  //any data may be sent with the "send data" verb including commands that have no value
  //though in that case you should still send the = and then immediately the return. like
  //reboot=/13 do not omit the equal sign.
}


void setLampLevel( int newLevel){
 //int adjustedLevel;
 //level from XTension is 0 to 100, map it so that we never go to all on 
 //adjustedLevel = map(newLevel, 0, 100, 0, 210); //keep it from going all on as that burns out the LED's
 //Serial.print( "log=level is ");
 //Serial.println( adjustedLevel);
 analogWrite( lampPin, newLevel);
  
  
}


void processButtons(){
  boolean debounceTimeout;
  
  if ((currentMillis - lastButtonMillis) > 100){
    debounceTimeout = true;
  } else {
    debounceTimeout = false;
  }
  
  
  if (digitalRead( upButton) == LOW){
    //upbutton is pushed
    if ((debounceTimeout) && (currentButtonPushed != upButton)){
      currentButtonPushed = upButton;
      lastButtonMillis = currentMillis;
      Serial.println( "button1=on");
      return;
    }
  } else if (currentButtonPushed == upButton){
      //the button is up but the last button pushed was ours so we can reset it
      if (debounceTimeout){
        lastButtonMillis = currentMillis;
        currentButtonPushed = -1;
      }
  }

    
 if (digitalRead( midButton) == LOW){
    //midButton is pushed
    if ((debounceTimeout) && (currentButtonPushed != midButton)){
      currentButtonPushed = midButton;
      lastButtonMillis = currentMillis;
      Serial.println( "button2=on");
      return;
    }
  } else if (currentButtonPushed == midButton){
      //the button is up but the last button pushed was ours so we can reset it
      if (debounceTimeout){
        lastButtonMillis = currentMillis;
        currentButtonPushed = -1;
      }
    }
    
  if (digitalRead( downButton) == LOW){
    //upbutton is pushed
    if ((debounceTimeout) && (currentButtonPushed != downButton)){
      currentButtonPushed = downButton;
      lastButtonMillis = currentMillis;
      Serial.println( "button3=on");
      return;
    }
  } else if (currentButtonPushed == downButton){
      //the button is up but the last button pushed was ours so we can reset it
      if (debounceTimeout){
        lastButtonMillis = currentMillis;
        currentButtonPushed = -1;
      }
  }
}
.code { background:#f5f8fa; background-repeat:no-repeat; border: solid #5C7B90; border-width: 1px 1px 1px 20px; color: #000000; font: 13px 'Courier New', Courier, monospace; line-height: 16px; margin: 10px 0 10px 10px; max-height: 200px; min-height: 16px; overflow: auto; padding: 28px 10px 10px; width: 90%; } .code:hover { background-repeat:no-repeat; }