Tuesday 28 January 2020

Hacking the HW-655 ESP8266 WiFi IoT Relay Board

HW-655
I got my HW-655 for just RM10, ESP-01S included. However it did not work and I suspected the seller just plain forgot to program the STC15F104W CPU. Luckily, Sergiy Zaschipas has a great writeup on this and I strongly recommend a careful read.

[2020-07-12 update: here's the hack for the 2 relay Nuvoton N76E003 CPU version]

I had always wanted to reprogram these serial relay modules. They are perfect for use with the ESP-01S. When reprogrammed a number of them can be daisy-chained on the same serial port allowing a single ESP-01S to control them all. They can also be daisy-chained without reprogramming, but then all the relays would turn on and off at the same time.

The same serial port is brought out to a header and this also lets a Raspberry Pi control the relay daisy-chain with a minimum of wiring. The usual hat is maybe the Piface Digital or Piface Digital 2, but of late Piface libraries has been buggy and it has begun to feel like abandonware.

So hie you hence to Zaschipas' repository. There stays a program to make you a working HW-655. Since I mostly run Slackware, I would add a few notes. sdcc, the compiler for the 8051 CPU (STC15 is an Intel 8051 derivative) is installed thus:

$tar -xvjf sdcc-src-3.9.0.tar.bz2

But you will first need gputils:
gputils-1.5.0$./configure
gputils-1.5.0$make clean
gputils-1.5.0$su -c "make install"

Then to sdcc proper:
sdcc-3.9.0$./configure

The compile takes a long time so if you have the resources to run it in parallel, I would recommend:

sdcc-3.9.0$make -j 10
sdcc-3.9.0$su -c "make install"

If you do not want to compile Sergiy's relay.c from source, here are my results:
$cat relay.ihx
:0400000002001132B7
:03000B0002012CC3
:03006A0002000E83
:03000E0002006D80
:20006D0075415575425075B10075B204C2B2753B00753D00C20412019BE4F53FF540E53F55
:20008D002441F9E7FF600F8F8212018F053FE4B53FEC054080E810030302011985223CE53E
:2000AD003B24FC5003020119E53B75F003A49000BF730200CB0200D40200E20200F974A0E5
:2000CD00B53C49053B80457401B53C04053B803C753B0080377401B53C028004E53C700783
:2000ED00053B853C3D8025753B00802074A2B53C0B7401B53D06D2B2D204800D74A1B53C54
:20010D0008E53D7004C2B2D204753B001004030200A3A2B2E433F58212018F0200A322C073
:20012D00E0C0D0300120D52628752603D52809852422C201D2038019E524C313F52430B056
:20014D0010432480800B20B008D201752604752809D52529752503300023E527700AC2B114
:20016D008521237527098015E523C313F523D52708D2B1C200D2028004A2D792B1D0D0D0AC
:20018D00E032AF8210020280FB8F21D20022759850C2AFC2B9C2A9C28C758900758E8075E4
:1C01AD008A80758CFED28CD2A9D2B9D2AFC200C201D202C20375250075260022D3
:06004000E4787FF6D8FD14
:20001E007900E94400601B7A009001CD780175A000E493F2A308B8000205A0D9F4DAF275BA
:02003E00A0FF21
:200046007800E84400600A790175A000E4F309D8FC7800E84400600C7900900001E4F0A3B8
:04006600D8FCD9FAEF
:0D0011007581421201C9E582600302000EF4
:0401C9007582002219
:00000001FF

The utility to program the STC15 is stcgal and I installed it thus:

$pip3 install stcgal

Getting stcgal to program was very tricky. I used a CH340 USB to serial ttl dongle set for 3.3V.

CH340

What worked for me was to run the CH340 and the HW-655 from separate 5V power supplies, the latter seemed to work better from  battery-power, like from a power bank. Unusually, I had to connect the CH340 TX to HW-655 TX and RX to RX (you usually connect TX to RX), but your mileage may vary. You then ran the programming command; mine is slightly different from Sergiy's:

Programming setup: CH340 in center and the 1-channel serial relay module on top. Wires are TX-TX, RX-RX and GND-GND


$stcgal -p /dev/ttyUSB0  -b 1200  -D relay.ihx

To test, the python interpreter makes it fun and easy:
$python                     
Python 2.7.16 (default, Apr  3 2019, 21:30:55)
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> port = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=3.0)         
>>> relON = [0xA0,0x01,0x01,0xA2]
>>> port.write(serial.to_bytes(relON))
4

To use it with the ESP-01S, I need an Arduino IDE sketch. And it worked first time, just like that. The baudrate is 9600. The code repository is in github. To turn on the relay you use a browser with the URL:
http://ww.xx.yy.zz:8080/1/on

You can pick up the device IP address from your router but I used the 'Tools->Port' sub-menu in Arduino IDE which lists the device IP address.

In my installation, the ESP-01S often had to be reset when it has WiFi disconnects and when you use it to control relays this annoyingly resets the relay as well. I can probably flash the relay state into ESP8266 filesystem, but this tends to wear out the flash memory. But the great thing with having a separate CPU like the STC15 is that the relay state is still preserved in there. Except now you need a command to read the relay state back.

First we need to decode the relay commands used. They are:

0xA0, 0x01, 0x01, 0xA2 to turn on a relay
0xA0, 0x01, 0x00, 0xA1 to turn off a relay

Notice the STC15 replies with a 1-byte reply with the actual state of the relay control line.
For modules with two relays the commands for the second relay are:

0xA0, 0x02, 0x01, 0xA3
0xA0, 0x02, 0x00, 0xA2

My guess would be the first byte A0 is the header to indicate the start of a command packet. Next byte would be the relay number, and the third byte would be relay operation code, ie 0 for off and 1 for on. The last byte would be a checksum, which is just a straight sum of the preceding 3 bytes.

So for my relay daisy chain, I would extend the commands as follows for relay 3:

0xA0, 0x03, 0x01, 0xA4 to turn on relay 3
0xA0, 0x03, 0x00, 0xA3 to turn off relay 3

And so on. Now for the relay state read I would propose a new opcode 2, so to read relay 1:

0xA0, 0x01, 0x02, 0xA3

And the answer would be in the same 1-byte reply. I implemented this in the relay_read.c program. To read the state from the ESP-01S I would use a browser and the URL:
http://ww.xx.yy.zz:8080/1/read

For installations were hazardous voltages in the relay module need to be completely enclosed, an external ESP8266 with TTL Serial Adapter PCB may improve WiFi reception


There you have it, an HW-655 in the palm of your hand. Happy trails.

Tuesday 21 January 2020

3G Failover using the Huawei B310

Huawei B310 3G router
I first implemented a 3G failover using the TP-Link MR3420, but that had a few problems. It got a little erratic with less than 20 IoT devices connected. When in backup 3G mode the uplink often failed when run for too long and the 3G USB modem then needed to be power cycled. In a thunderstorm 3G reception often got a lot worse. But worst of all I could not alter the failover criteria.

This is because my benighted ADSL service provider Talikom Malaysia plumbed news depths in quality of service. The ADSL connection would get erratic, going on and off within a few minutes. Sometimes there would be an actual ADSL connection but it would not be able to reach the TM gateway and from there the Internet. Sometimes the link simply got slow.

This would sometimes cause the MR3420 to remain in ADSL mode and not fail over to 3G. Worse this sometimes caused it to randomly drop connections to some client WiFi devices. Power-cycling it usually helps, but the random dropouts are nevertheless annoying.

Huawei B310 with external antennae


The Huawei B310 has a simple failover criteria: it needed its WAN input cable disconnected before it goes into 3G mode. I could do that with an electromechanical relay; this allowed me to make a custom failover program to handle TM's myriad failure modes. Also the B310 has two connectors for 3G external antennae which are separately bought. And it does not disconnect clients in either 3G or ADSL mode.

The setup is much the same as before:


The Huawei B310's WAN uplink is taken from the Archer D50 via the DES-100S LAN switch. This allows me to disconnect the WAN link by turning off the DC power to the LAN switch. I do this using a Raspberry Pi Model B and a Piface hat.

Because of frequent electrical storms, the ADSL line can also be disconnected by an AS3935 lightning detector relay module.

The Raspberry Pi runs Raspbian. The Piface is controlled by the pifacedigitalio library and the failover program for now is a simple bash script. Here is a first-pass version of the failover program, it did not take more than an afternoon to code and test.

Because of the AS3935 lightning detector, the failover program subscribes to and publishes to a local MQTT server. The piface digitalio library is not one of you best supported ones, but there are a few hints if you run into trouble.

As always the choice of components is not necessarily optimal, if not downright obsolescent. Most of the time they are used simply because they are available on hand. Indeed you can probably get an all-singing all-dancing 3G failover modem router for a very reasonable price somewhere. But it goes against grain not to use working parts simply because they are a little too old.

Much better to go out with your boots on. Happy Trails.