My messages from sensors and to actuators have always been in the form of an ID code followed by three values (of which only the first is often valid--e.g. for a temperature sensor). The ID has been a capital letter, A-Z. I will be expanding that to include "a-z".
The central part of this is the Pi 4B, which needs to talk to ESP32 nodes. My solution looks like this: My first pass was to plug an ESP32-S2Mini into the 5V, 0V, Tx and Rx pins on the Pi. These align perfectly with VBus (5V), GND, 16, and 18 on the S2Mini. This worked after serial was enabled on the pi, creating the serial port address, /dev/serial0. I could talk back and forth.
But I wanted a way to toggle the power if communication was lost. It turns out that by installing a program called uhubctl, you can turn off and on the 4 USB ports (they can't be switched individually): "sudo apt install uhubctl". Now you can turn off power to the USB ports with "sudo uhubctl -l 2 -a 0", and turn it back on with "sudo uhubctl -l 2 -a 1".
I wired up a little perf-board adaptor to connect 5V, Tx, Rx, GND on a USB/serial adaptor to 5V, G, 4, 3 on an ESP32-C3Supermini. This is on the port /dev/ttyUSB0. Now I can talk to the ESP32, and power cycle it if communication is lost.
My first project for this is to control the zones in my 3-zone hot water system by being able to bypass (short out) the relays in the zone thermostats. I'm using ESP32-S2Minis which have the D1Mini relay modules plugged in (all the D1 modules plug into the outer rows of the S2Mini). The S2Mini+Relay combination presents a web page which allows you to toggle the relay, turning on heat to the zone. In addition to toggling the relay, a message, "DR Thermostat Relay ON" or "OFF" is sent with ESP-Now to the C3Supermini, which passes it via serial to the Pi (in the form, "p 1 0 0" or "p 0 0 0"), which logs it to a file with a timestamp. Control can also go the other way. From the pi, the command echo -n "p 1" >/dev/ttyUSB0 will turn the relay on, and "p 0" will turn it off.
This bash code running on the Pi handles the incoming serial:
Code: [Local Link Removed for Guests]
#!/bin/bash
stty -F /dev/serial0 115200 clocal cread cs8 -cstopb -parenb -crtscts -echo
cat /dev/serial0 2>/dev/null | while read v1 v2 v3 v4; do
if [ "$v1" \> "@" -a "$v1" \< "[" ] ; then # A-Z
echo "$v1 $v2 $v3 $v4 $(date +%y%m%d%H%M%S)" >> /home/lb/signals.txt
fi
if [ "$v1" \> "\`" -a "$v1" \< "{" ] ; then # a-z
echo "$v1 $v2 $v3 $v4 $(date +%y%m%d%H%M%S)" >> /home/lb/signals.txt
fi
# echo "$v1 $v2 $v3 $v4 $(date +%y%m%d%H%M%S)" >> /signals.txt
done
Here is the Annex code on the relay node:
Code: [Local Link Removed for Guests]
' DR_zone.bas
' CC:8D:A2:8C:A1:A8
dim wifi_APs$(2)="omnibus6_EXT","Omnibus_N"
dim RECEIVER_MAC$(2) = "F0:F5:BD:FD:02:50","CC:8D:A2:8C:A1:A8" ' MAC address of the receiver
currentWIFI=0
' WIFI.CONNECT wifi_APs$(currentWIFI),"amber1977"
pin.mode 35,output ' D2
led1=0
ID$="p"
cls
autorefresh 1000
wlog "ESP-Now init " ; espnow.begin ' should print 0 if all OK
espnow.add_peer RECEIVER_MAC$(currentWIFI) ' set the address of the receiver
'espnow.add_peer RECEIVER_MAC$(1) ' set the address of the receiver
bcast$ = "FF:FF:FF:FF:FF:FF" 'broadcast address
espnow.add_peer bcast$
onEspNowError status ' set the place where jump in case of TX error
onEspNowMsg espnowRX 'branch here with incoming msg
gosub make
wait
make:
if led1=1 then
state$="ON"
else
state$="OFF"
endif
cls
a$=""
a$=a$ + "<table>"
a$=a$ + "<tr style='vertical-align:baseline'><td>" + "DR Thermostat Relay " + "</td><td>" + Led$(led1) + "</td><td>" + button$("Toggle",toggle1) + "</td></tr>"
a$=a$ + "</table>"
html a$
pin(35)=led1
espnow.write "DR Thermostat Relay " + state$ ' send the message
return
toggle1:
led1=1-led1
gosub make
return
status:
print "ESP-Now TX error on ";wifi_APs$(currentWIFI);", ch ";WIFI.CHANNEL;": "; espnow.error$ ' print the error
wlog "ESP-Now TX error on ";wifi_APs$(currentWIFI);", ch ";WIFI.CHANNEL;": "; espnow.error$ ' print the error
return
espnowRX: ' set/reset relay if message is for this node
RXmsg$ = espnow.read$
sender$ = espnow.remote$
if sender$<>MAC$(0) and sender$<>MAC$(1) then ' don't respond to self
if instr(RXmsg$,chr$(13)) then
RXmsg$=mid$(RXmsg$,1,instr(RXmsg$,chr$(13))-1) ' should strip CR & LF
endif
wlog "ESP_Now message :"+RXmsg$+": from "+sender$+" "+time$
ledVal=-1
if mid$(Rxmsg$,1,1)= ID$ then ' message is for us
if mid$(Rxmsg$,3,1)= "1" then ' turn relay on
ledVal=1
elseif mid$(Rxmsg$,3,1)= "0" then ' turn relay off
ledVal=0
endif
endif
if ledVal <> -1 then
led1=ledVal
gosub make
endif
endif
return
Code: [Local Link Removed for Guests]
' log_now.bas ' ESP-Now receiver
SERIAL2.MODE 115200,3,4
' print2 "a 23 1 0"
MAC_adr$="CC:8D:A2:8C:A1:A8"
wlog "ESP-Now init " ; espnow.begin 'should print 0 if all OK
bcast$ = "FF:FF:FF:FF:FF:FF" 'broadcast address
espnow.add_peer bcast$
onserial2 serialRX2
onEspNowMsg espnowRX 'branch here with incoming msg
RXmsg$ = "b 1 0 0 " ' starting now
sender$="00:00:00:00:00" ' for startup message only
gosub RXnow
wait
espnowRX:
RXmsg$ = espnow.read$
sender$ = espnow.remote$
if sender$ <> bcast$ then
if sender$ <> MAC$(0) and sender$ <> MAC$(1) then ' ignore messages from ourselves
if RXmsg$<>"" then ' ignore empty
gosub RXnow
endif
endif
endif
return
RXnow:
wlog "!"+RXmsg$+"!",sender$
if mid$(Rxmsg$,1,2)= "DR" then
if instr(RXmsg$,"ON") then
RXmsg$="p 1 0 0" ' DR Zone on
else
RXmsg$="p 0 0 0" ' DR Zone off
endif
elseif mid$(Rxmsg$,1,2)= "BR" then
if instr(RXmsg$,"ON") then
RXmsg$="q 1 0 0" ' BR Zone on
else
RXmsg$="q 0 0 0" ' BR Zone off
endif
endif
print2 RXmsg$ ' send to RPi4 MHome
return
serialRX2:
pause 20 ' allow characters to arrive
serRXmsg$ = serial2.input$
if len(serRXmsg$)>2 then
wlog "*"+serRXmsg$+"*"
espnow.write serRXmsg$+chr$(13), "ff:ff:ff:ff:ff:ff" ' broadcast the text
endif
return
There's lots more to be done to build this out to redo my entire setup.