Introduction
Previously, I had developed a simple wireless temperature display system using a network of battery-powered transmitters which transmit the temperature from their current location using low-cost 433MHz AM transmitters spread around the house to some custom-made display units, one of which was documented here: Wireless temperature display with bare glass LCDs
The transmitters were all built inside 4xAA battery boxes which had been modified to accept 2xAA batteries to power the stripboard circuit which occupied the other half. These units didn't have any display capability, but I thought it would be better if they did.
A small number of PIC microcontrollers have built-in LCD drivers, and after connecting an LCD to one on breadboard, I found that it was possible to achieve power consumption of only 20uA so it should be possible to have a display on it and still have a battery life measured in years. The PIC16LF1936 was used in this project.
All code and the PCB design for the transmitter can be found on GitHub here: wireless-thermometer-transmitter-dgl-lcd
All code and the PCB design for the receiver can be found on GitHub here: wireless-thermometer-display-esp32
The display
The DGL-0401YG-4EH LCD from the Wireless temperature display with bare glass LCDs would also be used here as it's a fairly large size and it also fits well in the space of 3xAA batteries.
Wireless communications
From the previous project: The 433MHz transmission system is a very simple system which does not define a protocol and is unidirectional, which means an unlimited amount of receivers can be added without any changes needing to be made to the firmware in the transmitters. The task of decoding and receiving the data was passed off to an NKM2401 to save time and due to reasons relating to the design of the temperature transmitters which was done previously, but it wouldn't be difficult to implement this directly in the PSoC...
The previous transmitters used a PICAXE microcontroller which included built-in support for the same protocol used by the NKM2401. No PICAXE microcontrollers have built-in LCD drivers, so that immediately ruled out the use of one of those. It would also be impractical to use an NKM2401 as that chip had no power saving optimisations and space was at a premium anyway. The only solution would be to reverse-engineer the protocol.
I captured a number of packets from the output of an NKM2401 with a logic analyser
From inspection of the waveform, we can see that each half bit is indeed exactly 200us and the packet format is as follows:
- One-byte preamble of 0x00
- Constant byte of 0x09
- 8 data bytes in the same order as the input bytes, with no processing, scrambling or further encoding
- CRC – and this is indeed a CRC not a simple checksum
I used the CRC RevEng program to determine that the CRC polynomial is 0xB3.
A more detailed explanation of my reverse engineering efforts can be found here.
I initially implemented the transmit sequence using C for loops, but this didn't work and the waveform showed that there was a longer delay between bytes than between bits, and the overhead of the C for loop was enough to make a difference at 4MHz. The solution was to use the rlf
instruction in inline assembly as explained in the link above. The rlf
instruction also makes implementing the CRC calculation much simpler than the typical C algorithm which uses a big lookup table.
Once implemented correctly, my PIC16LF1936-based transmitter project worked perfectly with the various receivers in the system.
The transmitter PCB
I designed the PCB to fit in the same space as 3xAA batteries, so that it would be possible to use a modified battery box as the enclosure. I also tried to track out a PCB antenna but it didn't work very well and ultimately a wire was needed for this function.
It is difficult to find battery boxes which take 5xAA batteries, and a 6xAA battery box would just be too big, so I considered solutions which would allow the use of a 4xAA battery box. The first idea was to find a half AA sized battery and use two of them in series, but they were all 3.6V primary lithium types and very expensive anyway. How about a 3.6V primary lithium AA battery? Also very expensive. Eventually, I settled on using 3.2V rechargeable LiFePO4 14500 cells, which are still more expensive than alkalines, but less expensive than primary lithium and can also be recharged once the 600mAh capacity is depleted. They also have a much flatter discharge voltage curve than alkalines so the contrast of the LCD will be consistent over time.
600mAh doesn't sound like much but the voltage is much higher than a regular alkaline AA, so the volumetric energy density is similar. The specific energy (energy per unit mass) of the LiFePO4 cell is incidentally much higher than NiMH or alkaline, and the LiFePO4 cell weighs much less than an alkaline or NiMH cell. I did test the cell and it delivered the claimed capacity. The power consumption of the transmitter is so low that the 600mAh capacity should power it for over 5 years if the backlight is not used frequently.
The receiver
This used the same PCB as the improved version of my ESP32-based Octopus Tracker Unit Rate Display project. Ultra-low power consumption wasn't a requirement and reducing the effort was more of a priority, so an NKM2401 was used for reception duties with the output connected to the ESP32's UART instead of implementing the decoding in the ESP32.
The display code was also reused from the ESP32-based Octopus Tracker Unit Rate Display project, but slightly modified so that the number was only displayed to one decimal place when the temperature was a single-digit positive value. This display code was combined with the Espressif's ESP-IDF webserver example, suitably modified so that requests to a specific page on the webserver would have the live temperatures injected into it, or unknown
in the case of temperature IDs which hadn't been received since the last power cycle for correct handling in Home Assistant.
After some testing, it was found that the temperatures would stop updating in Home Assistant after a few days unless the receiver was power cycled. Examination of the code revealed that the cause was obvious and that was the wifi connection code in the webserver example was only a very basic implementation which wouldn't reconnect if the connection ever dropped. I added the much more elaborate wifi connection code used previously in the ESP32-based Octopus Tracker Unit Rate Display project and this seems to have resolved the problem and the connection is very reliable now.
The receiver is working well in Home Assistant and each temperature sensor works like any other sensor would.