Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

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.


Tuesday, May 7, 2019

WiFi Signal Strength as presence indicator, part 2

As a followup to yesterdays post about trying to filter the wifi RSSI of an ESP8266 board in order to sense movement I added a standard variance calculation on the last 2 minutes or samples or so. I added a threshold of 1 just for testing and have let it sit here for a while. The graph of that output looks like this:


When the variance goes above 1, or whatever preset threshold, I turn on the presence register which shows in green. You can see that it definitely does work to know when I’m coming and going, but at this sample rate, buffer size and threshold it also comes on randomly with non-people moving through the room wifi interference.

In order to register anything reasonable at all you have to have the device very close to the person you want to know if they are there. This may be of use for this particular application as I plan to have the device sitting on my desk to provide some display of info for me while sitting here. It might even be able to blank and wake up it’s own display based on that. That would be useful and fun. Unfortunately if I sit very still it eventually thinks I’ve gone away. It’s decided that while I’ve been typing this paragraph actually. Lost of tweaking of settings would be necessary to make it at all useful.

I’m not sure that it will ever be useful as a generic motion sensor. You just have to be too close to the device to get it to see enough variance in the signal. Still an interesting experiment and I will keep fiddling with it to see if something useful can be done with it. It’s also possible that with the newer ESP32’s or other devices you could get better resolution or even access to things like the path being used to send the info or other similar data that would let you do a much better job. But for something that wakes up when you walk up to it and then goes to sleep shortly after nobody is standing next to it this could potentially be used.

Calculating a variance is a standard statistical technique so that you can gauge if you’ve got enough data points to realistically represent what you’re looking for among other thing. The formula is:

S2 = ∑(xi - x̄)2 / (n-1)

Which translates to the Variance squared being equal to the sum of each value in the dataset minus the average of the dataset squared and then divided by the number of points in the dataset minus one. So the first thing you need is an average of the dataset.  It’s slightly complicated by the fact that my buffer array of read RSSI values may contain 0’s or values that are not a valid RSSI. As I place the values into the buffer I am making them all positive as I am not worrying about the actual db value, only the variance of the data. So the first thing you need to do is to call the scanRSSI function every second. To do this you need to compare millis() with the calculated next time you want to do something inside the loop. You can’t just compare simple unsigned longs as are returned from millis() as they will overflow back to 0 at some point which will break everything. So you can do the clever trick of casting it to a long and then subtracting it later which will yield the proper result of timing even during an overflow condition.

#define MAX_RSSI_ARRAY 128
#define RSSI_PRESENCE_THRESHOLD 1
bool currentPresence = false;
byte rssiArray[MAX_RSSI_ARRAY];
byte rssiIndex = 0; // the index into the array where we are now
unsigned long nextPresenceScan = ((long)(millis() + 5000)); // 5 second start

the code above sets up the buffer array as bytes, since the numbers will never be more than 255 there is no reason to waste memory by using 2 byte ints or anything else. We also need an index into the array so we know where to save the next value and the nextPresenceScan value which is where the trick comes in. Casting the value of millis() + 5000 as a long integer and then putting it into an unsigned long variable we get around the overflow problem as far as the comparisons later are concerned. Very clever and described in great detail on the Arduino website if you’re interested.

Next we need some code to run inside the loop() to check the time and call us when it’s time to run. Something like:

void loop( void){
 if (((long)(millis() - nextPresenceScan)) >= 0){
  nextPresenceScan = ((long)(millis() + 1000));
  scanRSSI();
 }
}

Same trick as before, sets up the nextPresenceScan and then calls the function to do the work.



void scanRSSI(){


 float currentRSSI = WiFi.RSSI();
 
 if (currentRSSI > 0){
  // sometimes the WiFi.RSSI() call can return a number greater than 0 to indicate
  // an error or that it simply couldn't get the info at this time. If that happens
  // just ignore it.
  return;
 }

 // add the new value into our buffer at the current rssi buffer index
 // multiply by -1 to turn it into a positive number
 rssiArray[ rssiIndex++] = currentRSSI * -1;
 
 // if the index is now beyond the size of our buffer reset it back to
 // the beginning of the buffer for the next read
 if (rssiIndex >= MAX_RSSI_ARRAY){ rssiIndex = 0; }
 
 // first value we need for the variance calculation is the average
 float accumulator = 0;
 
 // since the buffer may not be filled with valid data yet 
 // we need to count how many non-zero values there are for the
 // average calculation rather than just divide it by the 
 // MAX_RSSI_ARRAY
 int averageCounter = 0;
 
 float average = 0;
 
 for (int i=0; i<MAX_RSSI_ARRAY; i++){
  
  // ignore values of 0
  if (rssiArray[ i] > 0){
   if (rssiArray[ i] < mn){ mn = rssiArray[i];}
   averageCounter++;
   accumulator += rssiArray[ i];
  }
  
 }
 
 // if we don't have at least 10 valid values in the array then just drop out
 // there is no point in calculating the rest unless we have enough values to 
 // look at
 
 if (averageCounter < 10){ return; }
 
 
 average = accumulator / averageCounter;
 

 
 // now loop again to calculate the SUM portion of the variance
 // reuse the accumulator 
 accumulator = 0;
 
 // loop through the buffer array again, this time subtracting the average and then
 // squaring the result adding it to the accumulator
 
 for (int i=0; i<MAX_RSSI_ARRAY; i++){
  if (rssiArray[ i] > 0){
   // dont want to waste the memory to include the floating point or C math
   // libraries, so just put the calculated value into a local variable and
   // multiply that by itself
   float work = (rssiArray[i] - average);
   accumulator += work * work;
  }
 }



 // here we divide by n-1 
 float variance = (accumulator / (averageCounter - 1));
 
 // the variance may be less than 0? if so take absolute value
 if (variance < 0.0){ variance *= -1; }
 
 // now do something clever with the variance data.

}


That is actually pretty horrible code. I also do realize that I’m never taking the square root of the variance as calculated. That doesn’t seem necessary at this point and the poor arduino is already working hard with all those floats. If I make the value even smaller it will be harder to watch whats happening. It’s also not memory compact as it needs a full buffer. I’m sure some other kind of rolling average could be used. To get anything useful you’ll have to adjust the threshold and the scanning frequency and probably a lot of other stuff too. An interesting starting point to something potentially useful.

The device in question here is sending it’s values back to XTension for graphing and potential use. The graph above was generated by that program. XTension: Home Automation for the Mac, is my day job.

Sunday, May 5, 2019

Using wifi signal strength as a motion or presence indication

It seems like it should be possible to use wifi RSSI as a presence or motion detector. I have seen some very fancy devices that made low level use of the reflection information to target motion or people in a room, but the graph below is from an ESP8266 just reporting it’s RSSI every 5 seconds.


The device is sitting on my desk just a couple of feet away, so the range might not be very good, but still there might be instances where this is useful. You can quite plainly see in the above graph that I was in the office on and off until just after 7, and then it is fairly smooth while I was attending the local Philharmonic concert to hear my wife sing Mahler’s 2nd, and then picks up in variability as soon as I started going in and out of here this morning.

A lot of hysteresis would be necessary since there are many things that can affect the signal strength. Since it would take some time to know that you were there for sure it might not be useful to turn on lights or make adjustments when you arrive, but it could definitely be used to figure out when you’ve gone. Adding a Wifi calculated presence detection to such IOT devices would be very helpful. It would not work very well for battery operated devices however since you would need to wake up the wifi radios far more often than for the regular functions of the device.

Part two of this thought has code examples and is here.

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/

Monday, August 19, 2013

xBee battery powered motion sensor, part the second.

This is a followup to an earlier post as came out in the comments you can't wake up an xBee directly with the output from the motion sensor, it's the wrong polarity. It connects to Vcc when motion is detected and floats when there is no motion. Just adding a pulldown and a transistor didn't work at all to connect it to ground and wake up the xBee. Too many timing issues.

So I decided to go with an ATTiny85 chip that can sleep most of the time and be woken up itself when the sensor goes high, and it can then handle the timing of waking up the xBee and having it sample it's pins and send the data. This actually worked lovely until I tried to add back in the motion sensor.

It turns out these motion sensors just dont work below 3v or so. They have an onboard voltage regulator for the 3.3v that they need to work so you really must power them with 5v to get them going. There is some talk on teh intertubes that you can just short across the regulator on the board. I think those instructions were written before they switched to all surface mount parts on these boards which makes it much more difficult. I did try doing that though and it did work then at 3.3v quite well.


you can see my tiny little wire loop across the voltage regulator. Unfortunately at about 3v and lower it stops behaving at all which means that 2AA batteries are not going to power it for very long. And it also stops behaving above 4.5v which means that 4 batteries are a no go. The ATTiny has a good range of voltages in this area which makes it excellent for a long term battery operated product but the xBee is very sensitive to voltages above 3.3 volts. I wouldn't want to run it on 3 batteries without a regulator. Which means that would require a regulator which would waste a lot power and significantly reduce battery life.

I've looked around quite a bit, and there are some excellent canned solutions to motion sensing out there, including some fantastic chip/sensor combinations from Zilog (who also offer an SMT version of the Z80 CPU chip which somehow I find funny :) but they use too much current and still dont operate at a low enough voltage for a good battery operated project.

So we're left with separate power supplies for the sensor and the xBee or regulators or rolling it from scratch. I might experiment with a 3AA battery system where the sensor runs with it's regulator off 3 batteries and see what the current usage is and tap just 2 of the batteries to power the xBee. They will run down out of sync but that might still work and 3 batteries in the device isn't out of the question. Or it really might be time to start studying how these sensors work and roll one from scratch. The otherwise quite good except in radio range and reliability X10 motion sensors work for years on 2AAA batteries. I've glanced at their insides and I think they do a op amp comparitor thing between the 2 outputs of the motion sensor and then have a tiny PIC to make decisions on the output.

At least I understand why the newer ZWave motion sensors are so expensive and why the battery life in them sucks so badly overall.

But all this does mean that without the motion sensor the combination of an ATTiny and an xBee radio work great. So other sensors should be a piece of cake, something like a door/window contact closure device that might also sample temperature and light levels on a regular basis should be quite possible. I might concentrate on that for the moment and stew over the motion sensor problems a little longer.

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; }