Some christmas leds

By   December 1, 2015

Working on a sort of secret-santa gift for members of my truck club, I decided to do something with the WS2812B RGB LED’s. There’s a metric buttload of blog articles about these so I thought I would try to add something.

From what I can see, people are spending a lot of time dealing with timing. Nodemcu can do it but not if WIFI is enabled; or at least reliably anyway.. Since I’d had some success with the hardware SPI on the ESP8266 talking to a thermocouple amplifier, I thought I would try to get the SPI hardware to do my bitbanging for me. Turns out it’s actually quite trivial and ‘just worked’. Thanks to Joost Damad for the pattern which saved me the effort of figuring it out myself. Isn’t the internet amazing? Whenever you get a bright idea, turns out someone’s already done it.

First initialize the hardware SPI interface per David Ogilvy’s blog:

bool
ICACHE_FLASH_ATTR
ws2812b_init(void)
{
        if (initialized || sysCfg.board_id != BOARD_ID_PHROB_WS2812B)
                return true;
        spi_init_gpio(SPI_DEV, SPI_CLK_USE_DIV);
        spi_clock(SPI_DEV, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
        spi_tx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);
        spi_rx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);
        SET_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_CS_SETUP|SPI_CS_HOLD);
        CLEAR_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_FLASH_MODE);
        initialized = 1;
        pcfg.stringlen = 16;
        pcfg.ms_delay = 500;
        os_timer_setfn(&PatternTimer, PatternTimerHandler, NULL);
        return true;
}

Then simply load the bit in question into the SPI data register:

ws2812b_send_zero(void)
{

        int xtemp;
        xtemp = spi_transaction(1, 8, 0x80, 0, 0, 0, 0, 0, 0);
}

ws2812b_send_one(void)
{
        int xtemp;
        xtemp = spi_transaction(1, 8, 0xe0, 0, 0, 0, 0, 0, 0);
}

and that’s it. To send an RGB sequence for a single LED:

static inline void
ws2812b_send_color(uint8_t c)
{
        uint8_t bit=0x80;
        while(bit) {
                if (c&bit)
                        ws2812b_send_one();
                else
                        ws2812b_send_zero();
                bit>>=1;
        }
}

void
ws2812b_send_rgb(uint8_t r, uint8_t g, uint8_t b)
{
        ws2812b_send_color(g);
        ws2812b_send_color(r);
        ws2812b_send_color(b);
}

I haven’t really put any effort into optimizing this. I suppose it might be possible to pre-generate a pattern and blow the whole thing out the SPI but I wasn’t in the mood. What I’ve got works fairly well.

Here it is in action

Code is available here

How to reboot a DLink router from a script

By   November 7, 2015

I have a Dlink DIR-615 that periodically drops its connection to the outside world. It appears to coincide with my wireless provider going down but the DLink never recovers. I don’t know why; but whatever.

I was going to use a relay Phrob to just power cycle it but figured I’d explore doing a soft reboot since that appears to bring the connection back up. Because the HTTP foo is not strong within me, I searched and found this article which gave me the basic steps required to login to a DLink and reboot it. It didn’t work and I didn’t need to append a “A” to the password; but after some futzing and looking at the POST headers in Google Chrome, I eventually reached this script that I put in cron:

#!/bin/sh
# Check whether we can see google's DNS, if not, login to the router and reboot it.
ADDR=192.168.34.3
ADMIN_PASS="Zm9vCg=="

ping() {
        echo Pinging;
        ping -q -c 1 -n 8.8.8.8 >/dev/null && exit 0
}

login() {
        curl -o - -X POST -d "html_response_page=login.asp&login_name=YWRtaW4A&login_pass=$ADMIN_PASS&graph_id=5190c&&log_pass=$ADMIN_PASS&graph_code=&login=Login" http://$ADDR/login.cgi | grep index.asp
}

reboot() {
        echo "Rebooting ... " ;
        curl -X POST -d  "html_response_page=reboot.asp" http://$ADDR/reboot.cgi
}

ping || (login && reboot)

In order to encode your $ADMIN_PASS, you need to:

$ echo -n MYPASSWORD | base64

The ADMIN_PASS=”Zm9vCg==” above is what you’d get if your admin password was “foo”.

This works on my DIR-615, Hardware Version E3 and Firmware Version 5.10. Hope it helps someone.

MQTT Config

By   October 13, 2015

MQTT Config

So as I work to integrate MQTT into my automation environment, I find myself wishing for some sort of device discovery mechanism. Possibly also a device configuration mechanism.

Here’s the problem as I see it.

If I know the topic of a device, I can subscribe to it and I can even get its last data. I can also subscribe to all topics or a subset of topics. But then I have to wait for a device to publish something in order to discover it.

Unfortunately, I can’t ask Mosquitto what devices it knows about.

There are many use-cases where this just isn’t sufficient:

  • A device that isn’t publishing when you reboot.
  • A device that is turned off and only publishes when it gets turned on (like a device that uses a tilt sensor to power itself on).
  • A device that doesn’t publish at all (a subscribe only device like a Relay).

It would also be nice to be able to re-configure some attributes of a device though I can see how this could be abused in an InternetOfThings scenario.

So I believe I’m going to define a ‘discovery’ record and experiment with that. I’m thinking something like this:

/Device_ID/config/[Name]/[Attribute]/[Value]

Examples:

/Kitchen/config/Temperature/type/int
/Kitchen/config/Temperature/direction/input
/Kitchen/config/Temperature/unit/celsius
/Kitchen/config/Humidity/type/float
/Kitchen/config/Humidity/direction/input
/Kitchen/config/Humidity/unit/percent
/Garage/config/Relay/type/bool
/Garage/config/Relay/direction/output
/Garage/config/RelayToggle/type/int
/Garage/config/RelayToggle/direction/output
/Garage/config/RelayToggle/unit/seconds
/Garage/config/Relay/type/bool
/Garage/config/Relay/direction/input

This tells me that is a sensor named “Kitchen” that publishes a temperature as an int in degrees celsius… There’s also a control named “Garage” that publishes a “Relay” state but it also has an output that it subscribes to called “Relay”… They both provide/take a boolean. There’s also a control named “Garage” that subscribes to “RelayToggle” that will conceivably cycle a relay on/off or off/on for some number of seconds.

I’ll experiment with that and see if I can make it useful… It will allow me to maintain an inventory of devices that are available… I will have to come up with some sort of expiry mechanism of course and if an attribute changes, I’ll need to override the old config with the new one presumably.

ESP8266 ESP-12 Deep Sleep

By   October 2, 2015

To address the issue of my temperature reading too high on boards with temperature/humidity sensors, I opted to deploy the ESP system_deep_sleep(us) call to put the board to sleep after publishing the temperature via MQTT.

Current draw when the board boots is 145mA until it connects to the AP, then it seems to go down to about 77mA and then when it goes to sleep, it draws about 55-60uA…

Presently I have it configured to wake up, bind to my AP, after it gets an IP, publishes the temperature/humidity and go to sleep for 30 seconds.

Here is the board:

Here’s a thermal video demonstrating this. At 00:04 and 00:35, you can see the LDO heat up when it wakes up from it’s nap:

Video was taken using a Therm-App android thermal imaging camera borrowed from Angus.

ESP8266 ESP-12 Thermal

By   September 29, 2015

I’ve been working with the ESP8266 chip, specifically the ESP-07 and ESP-12 modules available for cheap… One of my Phrobs has an SI7020 I2C – temperature/humidity sensor on board. As I’m a beginner at hardware, I’ve had to crank out a couple revs of this board due to thermal coupling issues. The temperature reads about 9C higher than ambient which obviously affects the humidity reading. My second rev of this board had the SI7020 isolated with its own grounding vs the LDO ground plane and the ESP8266 ground plane… I was hoping to be able to dissipate the heat other than through the substrate. As you can see below, I was wrong.

Here is the board:

wifi_temphum_phrob_v2

 

Here we are plugging in the USB power:

esp8266_thermal_8s

Here it is immediately after plugging in the USB power:

esp8266_thermal_9s

And here it is 90 seconds later…

esp8266_thermal_90s

Images were taken using a Therm-App android thermal imaging camera borrowed from Angus.

My Phrob Army

By   September 3, 2015

Things are starting to come together. I’ve made some single-relay versions as I’ve determined they’re more practical. I’ve reduced BOM cost a bit, and my thermocouple Phrobs are coming together. Waiting for some connectors. Also my experimental Hall Effect Phrob is there as well.

Phrob_Army

Cottage Automation Revisited

By   July 20, 2015

So I’ve been expanding my cottage automation a bit and I think I’m starting to expose some cracks in my plan to use Snap! as an automation language. The biggest is at tasks that are schedule based. Here is the current logic. The whole thing doesn’t do a great deal because I’m not yet ready to trust major functionality to this code. Specifically irrigation. Shari would be displeased if the flower beds dried out.

dr-logic

The block on the right is my experimental irrigation block. First it checks that I’ve enabled irrigation. Then it checks to see if the rain-sensor is wet. Once the unit is ready, it checks for the various days of the week and then checks times and when they match, sets “would_irrigate” to the appropriate sprinkler valve number.

Looking at the whole block, it’s very ‘bit’ relative to the others and something I can do with Cron in about 3 small lines of text.

I need to find a better way to handle scheduled tasks.

Phrobs are in!

By   June 25, 2015

I’ve been working the last few months on learning KiCad which is open source eCad software with an abyssmal user interface. But I’ve managed to layout my first two boards. Both are based on the ESP-8266.

My first board has an SI7020 temperature/humidity chip. My second board has a couple of 16A relays on it (though the traces only support about 5A for now). Both boards are a ‘rev 1’ so a couple things need to be cleaned up for Rev 2.

Here they are:

P1080407

I’ve also been hacking on esp8266-frankenstein which is a cool u-boot-like environment for the ESP8266’s. Another user had started porting someone else’s MQTT code to Frankenstein and then got busy. I took the code, finished bashing on it, cleaned it up, added some commands, integrated it into the GPIO driver and the SI7020 driver, and now I can MQTT Publish/Subscribe to my Phrobs:

mosquitto_pub -t "RelayPhrob1/gpio/5" -m "1"

Office/si7020/temperature/0 30
Office/si7020/humidity/0 24
RelayPhrob1/gpio/5 0
RelayPhrob1/gpio/5 1
RelayPhrob1/gpio/5 1
Office/si7020/temperature/0 30
Office/si7020/humidity/0 24
RelayPhrob1/gpio/5 1

$ mosquitto_pub -t "RelayPhrob1/gpio/5" -m "0"

RelayPhrob1/gpio/5 0
RelayPhrob1/gpio/5 0
Office/si7020/temperature/0 30
Office/si7020/humidity/0 24
RelayPhrob1/gpio/5 0

Next I will simply add an MQTT plugin to my Phrob ecosphere and I will be relatively self sufficient.

tftpd and xinetd on Ubuntu

By   May 10, 2015

I’ve been doing embedded for a long time but I’ve been doing unix admin stuff for way longer. I’ve probably been using inetd and tftp for 25 years. I’m always shocked at the ability for tftp to take up a couple hours of time the first time you want to get it running on a host.

When doing embedded, I typically like to point tftpboot at my compiler output directory which saves a copy step. Sometimes you forget to copy and you can’t figure out why your printf()s aren’t showing up (because you’re still running an old version).

Anyway, on Ubuntu, you typically install xinetd and tftpd…

sudo apt-get install xinetd tftpd

Then you want to create /etc/xinetd.d/tftpd :

service tftp
{
        disable         = no
        socket_type     = dgram
        protocol        = udp
        wait            = yes
        user            = hpeyerl
        server          = /usr/sbin/in.tftpd
        server_args     = -s /home/hpeyerl/trunk/firmware/esp8266
}

Then poke xinetd:

$ sudo pkill -1 xinetd

I always like to debug by using tcpdump:

06:11:42.796755 IP (tos 0x0, ttl 255, id 4, offset 0, flags [none], proto UDP (17), length 56)
    192.168.37.249.69 > 192.168.37.30.69:  28 RRQ "/images/antares.rom" octet
    0x0000:  4500 0038 0004 0000 ff11 ef48 c0a8 25f9  E..8.......H..%.
    0x0010:  c0a8 251e 0045 0045 0024 c8b6 0001 2f69  ..%..E.E.$..../i
    0x0020:  6d61 6765 732f 616e 7461 7265 732e 726f  mages/antares.ro
    0x0030:  6d00 6f63 7465 7400                      m.octet.
06:11:42.799663 IP (tos 0x0, ttl 64, id 8086, offset 0, flags [DF], proto UDP (17), length 49)
    192.168.37.30.42622 > 192.168.37.249.69:  21 ERROR EACCESS "Access violation"
    0x0000:  4500 0031 1f96 4000 4011 4ebe c0a8 251e  E..1..@.@.N...%.
    0x0010:  c0a8 25f9 a67e 0045 001d cc96 0005 0002  ..%..~.E........
    0x0020:  4163 6365 7373 2076 696f 6c61 7469 6f6e  Access.violation
    0x0030:  00                                       .

Sometimes syslog is helpful:

May 10 06:03:57 pm001 in.tftpd[4564]: connect from 192.168.37.30 (192.168.37.30)
May 10 06:03:57 pm001 tftpd[4565]: tftpd: trying to get file: antares.rom
May 10 06:03:57 pm001 tftpd[4565]: tftpd: serving file from /srv/tftp

The key there is “/srv/tftp”… Since there’s no mention of /srv/tftp in your xinetd.d config file, something else must be happening…

So, here are some gotchas that will consume some debug time:

  • If you’re testing this by using tftp on the same host as tftpd, you won’t see anything in tcpdump because the packets are short-cutting through your localhost interface.
  • On Ubuntu, there is also an /etc/inetd.conf which is your culprit:
#:BOOT: TFTP service is provided primarily for booting.  Most sites
#       run this only on machines acting as "boot servers."
tftp           dgram   udp     wait    nobody  /usr/sbin/tcpd  /usr/sbin/in.tftpd /srv/tftp
  • tftpd is very picky about permissions. You might be tempted to make every element in your path 777, I don’t need to tell you this is a bad idea.

The Snap! environment

By   February 14, 2015

I thought it might be useful to explain how Snap! works in my device control scenario. I’ve ever so slightly modified Snap! to be able to query my server and get an inventory of inputs and outputs available. These are known as “Phrob Ins” and “Phrob Outs” for lack of a better name.

snapshot1

On the left is a list of all inputs that were discovered during the inventory process.

In the center are the logic blocks I’m currently working with. There are 4 logic blocks there. Two of them are outlined in Green. These two are presently executing. The other two are not. The smallest logic block on the bottom has a speech bubble next to it. I simply clicked on the “Office:temperature” input and the speech bubble popped up and said “2214” which is DegreesC multiplied by 100. I’m currently experimenting on whether to transmit data as integers or floating point decimals. The jury is out. There is a logic block on the middle right that is not executing. I can simply click on a logic block to start or stop the block.

On the right top is a white canvas which presently displays some temporary variables that my logic blocks use. It’s handy to see those variables displayed because it makes debugging easier.

The top running logic block is responsible for collecting some statistics and transmitting a single text message out to the APRS IS network. On this network, I can remotely see what’s happening at the cottage:

2015-02-14 13:40:28 UTC: VF9ABC-9>VF9ABC: T=70.0,OA=32.0,SP=70.0,H1A=0,C1A=0,LRT=21.86,LRH=33.83
2015-02-14 13:45:28 UTC: VF9ABC-9>VF9ABC: T=70.0,OA=32.0,SP=70.0,H1A=0,C1A=0,LRT=22.01,LRH=33.4
2015-02-14 13:56:02 UTC: VF9ABC-9>VF9ABC: T=70.0,OA=32.0,SP=70.0,H1A=0,C1A=0,LRT=22.14,LRH=32.88
2015-02-14 14:06:42 UTC: VF9ABC-9>VF9ABC: T=69.0,OA=32.4,SP=70.0,H1A=1,C1A=0,LRT=22.49,LRH=32.76
2015-02-14 14:12:00 UTC: VF9ABC-9>VF9ABC: T=70.0,OA=32.0,SP=70.0,H1A=0,C1A=0,LRT=22.57,LRH=32.45

While it is somewhat soothing to see the raw data, sometimes it’s nice to see a graph:

graph