Achronite / energenie-ener314rt

Node module for RaspberryPi energenie ener314-rt board, used by node-red-contrib-energenie-ener314rt
MIT License
4 stars 2 forks source link

Error When Running on Raspberry Pi 5 #33

Closed JamesTimothyMeech closed 6 months ago

JamesTimothyMeech commented 9 months ago

I came across this repo because I am having issues with the Raspberry Pi software SPI driver built on top of gpio.c: https://github.com/whaleygeek/pyenergenie/issues/133

I attempted to run the app.js example on a Raspberry Pi 5 but I got this error:

app.js: Initialising board
ener314rt: mmap error -1
app.js: ERROR: Cannot initialise ENER314-RT board, status=-2
app.js: Quitting

I had to remove a superfluous bracket to get app.js to run. Does the app.js example use the SPI hardware driver code? I don't have experience with node.js so I haven't been able to figure this out for myself.

Achronite commented 9 months ago

What was the superflous bracket in app.js? I need to fix that!

The code does use the SPI hardware driver if it is enabled in raspi-config. Enable this, reboot and retry.

JamesTimothyMeech commented 9 months ago

Line 17: https://github.com/Achronite/energenie-ener314rt/blob/master/Examples/app.js

Achronite commented 9 months ago

OK it is in examples folder - phew.

You would be better off running the implementation of this module directly, and then interacting using MQTT or node-red. What is your use case?

JamesTimothyMeech commented 9 months ago

I have hardware SPI enabled in raspi-config. I tried rebooting but the error when running app.js is the same. I also get the mmap error -1 when running the @whaleygeek version. I just want a script which can switch a socket on and off using my Raspberry Pi 5. I'll probably just run the script manually when I want to switch the socket.

Achronite commented 9 months ago

Hmm, will have to do a bit more digging on this; maybe it needs a node.js update? What node.js version are you running?

JamesTimothyMeech commented 9 months ago
$ node -v
v20.9.0
JamesTimothyMeech commented 9 months ago

Is there any straightforward way to force your scripts to use the SPI hardware driver?

Achronite commented 9 months ago

It should say in the log which driver it is trying to use, something like:

ener314rt: Initialising gpio
ener314rt: Hardware driver enabled on /dev/spidev0.1

If you run the mqtt version and set logging to 'verbose' it will definitely show it.

Do you have the file /dev/spidev0.1?

JamesTimothyMeech commented 9 months ago

How do I properly run it?

grappa@raspberrypi:~/Desktop/mqtt-energenie-ener314rt $ sudo systemctl start mqtt-energenie-ener314rt.service
Failed to start mqtt-energenie-ener314rt.service: Unit mqtt-energenie-ener314rt.service not found.
grappa@raspberrypi:~/Desktop/mqtt-energenie-ener314rt $ ls
app.js        config_sample.json  energenie.js  mqtt-energenie-ener314rt.service  package-lock.json
CHANGELOG.md  devices             LICENSE       package.json       
Achronite commented 9 months ago

Just go into the directory and run node app.js after setting up your MQTT connection details in config.json.

I think your issue might be that /dev/spidev0.1 is missing; check this, and fix this issue. I can't seem to find anything on rpi5 and spidev.

JamesTimothyMeech commented 9 months ago

/dev/spidev0.1 is not missing:

grappa@raspberrypi:/dev $ ls
autofs           gpiochip3  loop2         ptmx    rtc         tty16  tty35  tty54      v4l     vcsu2        video30
block            gpiochip4  loop3         ptp0    rtc0        tty17  tty36  tty55      vcio    vcsu3        video31
btrfs-control    gpiomem0   loop4         pts     serial      tty18  tty37  tty56      vc-mem  vcsu4        video32
bus              gpiomem1   loop5         ram0    serial0     tty19  tty38  tty57      vcs     vcsu5        video33
cachefiles       gpiomem2   loop6         ram1    shm         tty2   tty39  tty58      vcs1    vcsu6        video34
cec0             gpiomem3   loop7         ram10   snd         tty20  tty4   tty59      vcs2    vcsu7        video35
cec1             gpiomem4   loop-control  ram11   spidev0.0   tty21  tty40  tty6       vcs3    vga_arbiter  video36
char             hidraw0    mapper        ram12   spidev0.1   tty22  tty41  tty60      vcs4    vhci         video37
console          hidraw1    media0        ram13   spidev10.0  tty23  tty42  tty61      vcs5    vhost-net    watchdog
cpu_dma_latency  hidraw2    media1        ram14   stderr      tty24  tty43  tty62      vcs6    vhost-vsock  watchdog0
cuse             hwrng      media2        ram15   stdin       tty25  tty44  tty63      vcs7    video19      zero
disk             i2c-1      mem           ram2    stdout      tty26  tty45  tty7       vcsa    video20
dma_heap         i2c-11     mmcblk0       ram3    tty         tty27  tty46  tty8       vcsa1   video21
dri              i2c-12     mmcblk0p1     ram4    tty0        tty28  tty47  tty9       vcsa2   video22
fb0              initctl    mmcblk0p2     ram5    tty1        tty29  tty48  ttyACM0    vcsa3   video23
fd               input      mqueue        ram6    tty10       tty3   tty49  ttyAMA0    vcsa4   video24
full             kmsg       net           ram7    tty11       tty30  tty5   ttyAMA10   vcsa5   video25
fuse             kvm        null          ram8    tty12       tty31  tty50  ttyprintk  vcsa6   video26
gpiochip0        log        port          ram9    tty13       tty32  tty51  uhid       vcsa7   video27
gpiochip1        loop0      ppp           random  tty14       tty33  tty52  uinput     vcsu    video28
gpiochip2        loop1      pps0          rfkill  tty15       tty34  tty53  urandom    vcsu1   video29

I don't have any MQTT connection details or any desire to have them

Achronite commented 9 months ago

Good that spidev0.1 is there. I get you on MQTT, let's try and fix this using the example app.js.

It's a shame I have yet to update my 'debug' repo to use spidev. So I'll need you to manually enable debug and recompile instead.

Un-comment the following lines in C/energenie/trace.h:

#define TRACE_POSIX
#define FULLTRACE

You can recompile the node module using node-gyp rebuild in the base directory. Please paste the log file when done.

JamesTimothyMeech commented 9 months ago

Should there be some additional log file appearing somewhere?

grappa@raspberrypi:~/Desktop/energenie-ener314rt-master/Examples $ sudo node app.js -verbose
app.js: Initialising board
ener314rt: mmap error -1
app.js: ERROR: Cannot initialise ENER314-RT board, status=-2
app.js: Quitting
JamesTimothyMeech commented 9 months ago

Or is this the log file you wanted?

gyp info it worked if it ends with ok
gyp info using node-gyp@10.0.1
gyp info using node@20.9.0 | linux | arm64
gyp info find Python using Python version 3.11.2 found at "/usr/bin/python3"

gyp info spawn /usr/bin/python3
gyp info spawn args [
gyp info spawn args '/usr/local/lib/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/home/grappa/Desktop/energenie-ener314rt-master/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/local/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/home/grappa/.cache/node-gyp/20.9.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/home/grappa/.cache/node-gyp/20.9.0',
gyp info spawn args '-Dnode_gyp_dir=/usr/local/lib/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=/home/grappa/.cache/node-gyp/20.9.0/<(target_arch)/node.lib',
gyp info spawn args '-Dmodule_root_dir=/home/grappa/Desktop/energenie-ener314rt-master',
gyp info spawn args '-Dnode_engine=v8',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.'
gyp info spawn args ]
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/home/grappa/Desktop/energenie-ener314rt-master/build'
  CC(target) Release/obj.target/ener314rt/C/achronite/napi_energenie.o
../C/achronite/napi_energenie.c: In function 'nf_send_radio_msg':
../C/achronite/napi_energenie.c:188:78: warning: passing argument 4 of 'napi_get_buffer_info' from incompatible pointer type [-Wincompatible-pointer-types]
  188 |                 status = napi_get_buffer_info(env, argv[2], (void **)(&msg), &len);
      |                                                                              ^~~~
      |                                                                              |
      |                                                                              unsigned int *
In file included from ../C/achronite/napi_energenie.c:3:
/home/grappa/.cache/node-gyp/20.9.0/include/node/node_api.h:144:65: note: expected 'size_t *' {aka 'long unsigned int *'} but argument is of type 'unsigned int *'
  144 |                                                         size_t* length);
      |                                                         ~~~~~~~~^~~~~~
  CC(target) Release/obj.target/ener314rt/C/achronite/lock_radio.o
  CC(target) Release/obj.target/ener314rt/C/achronite/ook_send.o
  CC(target) Release/obj.target/ener314rt/C/achronite/openThings.o
  CC(target) Release/obj.target/ener314rt/C/energenie/radio.o
  CC(target) Release/obj.target/ener314rt/C/energenie/hrfm69.o
  CC(target) Release/obj.target/ener314rt/C/energenie/spis.o
  CC(target) Release/obj.target/ener314rt/C/energenie/gpio_rpi.o
../C/energenie/gpio_rpi.c: In function 'gpio_init':
../C/energenie/gpio_rpi.c:101:44: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
  101 |       printf("ener314rt: mmap error %d\n", (int)gpio_map); //errno also set!
      |                                            ^
  CC(target) Release/obj.target/ener314rt/C/energenie/delay_posix.o
  SOLINK_MODULE(target) Release/obj.target/ener314rt.node
  COPY Release/ener314rt.node
make: Leaving directory '/home/grappa/Desktop/energenie-ener314rt-master/build'
gyp info ok 
Achronite commented 9 months ago

Should there be some additional log file appearing somewhere?

grappa@raspberrypi:~/Desktop/energenie-ener314rt-master/Examples $ sudo node app.js -verbose
app.js: Initialising board
ener314rt: mmap error -1
app.js: ERROR: Cannot initialise ENER314-RT board, status=-2
app.js: Quitting

That is the logfile. I think the issue is that I am still using 'old' libraries (gpio.h) to access and set the status LEDs on the board via GPIO. The rpi5 is completely different in how it handles gpio, and uses different chips to all the other models of pi. It looks like I may need to update this to use something that is more linux kernel based (libgpio) and is not dependent upon BCM chipset; that should hopefully fix the issue.

Give me a little while to work on this and I'll update the thread when an update is available.

JamesTimothyMeech commented 9 months ago

Ah I see, thanks for taking the time to debug this for me. I need a short term solution so I'll get hold of a Raspberry Pi 4 because I know those work

Achronite commented 9 months ago

@JamesTimothyMeech OK I have released some VERY early code here to see if it fixes your GPIO issues, I've switched to gpiod for the LEDs and RESET pin. Can you please try the develop branch of this repo and post your results?

JamesTimothyMeech commented 9 months ago

Thanks, it did quite a lot of stuff. Here is a log file. I don't see the LEDs flashing on the radio board when the script is running. log.txt

JamesTimothyMeech commented 9 months ago

I'm unsure how to convert this success into a scrip that allows me to switch the socket on and off. The socket does not appear to do anything when I run app.js or parent.js

JamesTimothyMeech commented 9 months ago

I tried changing zone = 0 and switchNum = 0 to switch all devices in the default zone as specified in the README.md but it did not seem to change anything.

Achronite commented 9 months ago

Try putting the switch into learning mode (hold down until flashes) and teaching a new zone/switchnum combination by sending a switch on command. Subsequent calls should then work using the same combination.

The red led should light when it sends; although i might have that wrong with my quick edit last night :)

Achronite commented 9 months ago

Just to check, what type of device are you trying to switch? Is it the dumb OOK socket - ENER002?

JamesTimothyMeech commented 9 months ago

It is a MIHO005. I will try your previous suggestion now

JamesTimothyMeech commented 9 months ago

I tried that by putting the switch into learning mode and then running app.js but it just seems to stay in learning mode. Presumably this code from app.js is enough to do the teaching and I can just run app.js as is?

var intervalId = setInterval(() => {
    let zone = 0;
    let switchNum = 0;
    switchState = !switchState;
    let xmits = 20;
    console.log(`app.js: switching ${zone}:${switchNum}:${switchState}`)
    var ret = ener314rt.ookSwitch(zone, switchNum, switchState, xmits);
}, 14000);
Achronite commented 9 months ago

MIHO005 uses a different FSK based call. It's a smart device; so you'll have to wait for it to JOIN the network; and then use you can use this to switch it once you know the deviceId:

var res = ener314rt.openThingsSwitch(productId, deviceId, switchState, xmits);
Achronite commented 9 months ago

Try commenting out this section from the example: and wait until a message gets decoded; they usually send updates every minute or so... ''' // every 14 seconds toggle an OOK switch/teach message var intervalId = setInterval(() => { let zone = 1; let switchNum = 1; switchState = !switchState; let xmits = 20; console.log(app.js: switching ${zone}:${switchNum}:${switchState}) var ret = ener314rt.ookSwitch(zone, switchNum, switchState, xmits); }, 14000); '''

You can then take the productId and deviceId for your script.

JamesTimothyMeech commented 9 months ago

I can see them sending updates fairly regularly and also when I push the button on the socket but I'm not sure how to decode these messages:

*openthings_deviceList(): Returning: {"numDevices":0, "devices":[
]}
app.js: deviceList={"numDevices":0, "devices":[
]}
*************HRF_readfifo_burst_cbp() len=29, data:28:4:2:8:220:0:124:187:231:162:170:136:193:53:213:227:110:80:11:9:211:209:158:4:202:194:252:200:201:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
******HRF_readfifo_burst_cbp() len=29, data:28:4:2:80:84:79:165:224:225:29:23:20:85:114:121:159:129:54:26:136:46:71:164:63:61:122:135:73:170:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
**************HRF_readfifo_burst_cbp() len=29, data:28:4:2:85:207:201:32:29:253:137:80:184:41:157:31:143:0:203:141:142:21:176:9:68:240:36:40:189:233:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
******HRF_readfifo_burst_cbp() len=29, data:28:4:2:26:234:47:26:29:71:203:247:219:254:68:146:55:115:1:136:80:130:199:69:183:142:54:116:188:201:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
*openthings_deviceList(): called
openThings_scan(): called
*************HRF_readfifo_burst_cbp() len=29, data:28:4:2:29:160:35:109:151:95:185:216:143:187:77:188:90:208:104:213:35:188:223:58:242:59:181:200:22:110:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
******HRF_readfifo_burst_cbp() len=29, data:28:4:2:120:102:198:47:206:0:227:117:22:128:194:109:144:172:91:129:186:143:119:165:32:101:214:63:225:210:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
*openthings_deviceList(): Returning: {"numDevices":0, "devices":[
]}
app.js: deviceList={"numDevices":0, "devices":[
]}
Achronite commented 9 months ago

It has not found a device yet, that will show in the 'deviceList =' bit as it having problems decoding the radio messages; Do the messages stop when you switch off the power at the socket, they could be from something else?

JamesTimothyMeech commented 9 months ago

The messages do seem to stop when I turn off the socket

Achronite commented 9 months ago

That's strange. Can you please try the following, it could be an encryption issue: 1) Start the script 2) Hold the button on the device for > 5 secs until it flashes to force it to join the network

If that doesn't work I'll have to try and do a manual decode to see what is going wrong.

JamesTimothyMeech commented 9 months ago

I borrowed a Raspberry Pi 4 from someone and used the whaleygeek pyenergenie code to find the product and device ID. The Raspberry Pi 5 is working with your code now but app.js only turns the socket on and never manages to turn it off. It could be that !switchState does something to the variable which is required to make the socket switch. If I change the hard coded value of switchState the app.js code is able to turn the socket off but never turns it back on again. I have the functionality I need now as I have scripts to turn the socket on and off! Thanks for taking the time to help me get this working. Apologies for not understanding how node js works.

Achronite commented 9 months ago

I probably still need to get to the bottom of why it wasn't decoding your messages correctly...

Maybe the pyenergenie code doesn't bother checking the CRC or something?

JamesTimothyMeech commented 9 months ago

I tried what you asked for here: https://github.com/Achronite/energenie-ener314rt/issues/33#issuecomment-1824369323 and I get this:

grappa@raspberrypi:~/Desktop/energenie-ener314rt $ sudo node app.js
napi_energenie.Init() called
app.js: Initialising board
init_ener314(0): Initialising
init_ener314(): mutex created & locked
radio_init()
ener314rt: Hardware driver enabled on /dev/spidev0.1
Hardware SPI ret=0,spiMode=0
radio_ver=36
radio_standby
HRF_writereg(1,4)
_wait_ready(): init_ener314(): mutex unlocked
app.js: Starting monitoring...
tf_ napi_create_threadsafe_function done
tf_ monitor thread started, timeout=10000
tx_openThings_receive_thread starting
HRF_writereg(2,0)
HRF_writereg(5,1)
HRF_writereg(6,236)
HRF_writereg(7,108)
HRF_writereg(8,147)
HRF_writereg(9,51)
HRF_writereg(11,0)
HRF_writereg(24,8)
HRF_writereg(25,67)
HRF_writereg(3,26)
HRF_writereg(4,11)
HRF_writereg(46,136)
HRF_writereg(47,45)
HRF_writereg(48,212)
HRF_writereg(55,162)
HRF_writereg(56,66)
HRF_writereg(57,4)
radio_setmode() modulation changed to FSK mode changed to 16
HRF_writereg(1,16)
_wait_ready(): P******************HRF_readfifo_burst_cbp() len=13, data:12:4:2:38:14:186:242:75:163:167:56:41:39:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:
@Non-OT message, openThings_decode() returned -2
**********app.js: switching 1:1:false
openThings_switch: productId=2, deviceId=16222, state=0
switch tx payload (unencrypted):
13,4,2,103,198,0,63,94,243,1,0,0,3,180,
radio_mod_transmit()
 mode changed to 12
HRF_writereg(1,12)
_wait_ready(): _wait_txready
radio_send_payload(): HRF_writereg(60,13)
20 tx payloads
PXPPXPPPXPPXPPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPX<PPirqflags1,2=176,0
 mode changed to 16
HRF_writereg(1,16)
_wait_ready(): P***************************app.js: switching 1:1:true
openThings_switch: productId=2, deviceId=16222, state=1
switch tx payload (unencrypted):
13,4,2,105,115,0,63,94,243,1,1,0,48,133,
radio_mod_transmit()
 mode changed to 12
HRF_writereg(1,12)
_wait_ready(): _wait_txready
radio_send_payload(): HRF_writereg(60,13)
20 tx payloads
PXPPXPPPXPPXPPXPPPXPPXPPPXPPXPPPXPPXPPXPPPXPPXPPPXPPXPPPXPPXPPPXPPX<PPirqflags1,2=176,0
 mode changed to 16
HRF_writereg(1,16)
_wait_ready(): P**openthings_deviceList(): called
openThings_scan(): called
********************openthings_deviceList(): Returning: {"numDevices":0, "devices":[
]}
app.js: deviceList={"numDevices":0, "devices":[
]}
****app.js: switching 1:1:false
openThings_switch: productId=2, deviceId=16222, state=0
switch tx payload (unencrypted):
13,4,2,81,255,0,63,94,243,1,0,0,3,180,
radio_mod_transmit()
 mode changed to 12
HRF_writereg(1,12)
_wait_ready(): _wait_txready
radio_send_payload(): HRF_writereg(60,13)
20 tx payloads
PXPPXPPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPXPPXPPPXPPXPPXPPPXPPXPPPX<PPirqflags1,2=176,0
 mode changed to 16
HRF_writereg(1,16)
_wait_ready(): P***************************app.js: switching 1:1:true
openThings_switch: productId=2, deviceId=16222, state=1
switch tx payload (unencrypted):
13,4,2,74,236,0,63,94,243,1,1,0,48,133,
radio_mod_transmit()
 mode changed to 12
HRF_writereg(1,12)
_wait_ready(): _wait_txready
radio_send_payload(): HRF_writereg(60,13)
20 tx payloads
PXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPXPPPXPPXPPX<PPirqflags1,2=176,0
 mode changed to 16
HRF_writereg(1,16)
_wait_ready(): P******

The socket continues to flash and the script continues to run until I kill the script. The socket never switches off or on.

JamesTimothyMeech commented 9 months ago

I probably still need to get to the bottom of why it wasn't decoding your messages correctly...

Maybe the pyenergenie code doesn't bother checking the CRC or something?

I am now unable to successfully use the scripts that previously worked on the Raspberry Pi 5. Is it possible that the Raspberry Pi 4 script put the socket into a mode where it would accept messages from the Raspberry Pi 5?

Achronite commented 9 months ago

I doubt it, but you could always try and reset the plug by holding down the reset button.

The message it did receive (in your recent log) looks like it could be valid, but I don't know why the CRC is failing. Are you happy to try again if i add some debug code that shows the decrypted payloads and a bit more about the CRC?

whaleygeek commented 9 months ago

Beware that the detailed driver debug significantly affects the timing of the system, to the point it might not work at all. It was only ever there to debug the logic of the physical layer, it was never intended to be used while the system was running. Specifically, you will find significant interruption to the receive processing if you have full trace turned on.

The FSK switches will always process messages that are received with a correct header format/contents and CRC. If you know their address and if the encryptPIP is correct and the CRC correct, they will always respond.

Don't be fooled by adding more debug and then the system stops working - that is usually quite normal when you are close to the physical layer.

The HRF69 radio module that is the same on both of these boards, has a maximum SPI speed that it can accept - check the data sheet, it might be 10MHz max, or even lower. If the new Raspberry Pi 5 defaults to sending SPI at a much higher rate due to how the southbridge chip is configured, you may indeed get some very strange behaviour.

According to 'RFM69 ISM TRANSCEIVER MODULE V1.3', Table 8 Digital Specification, the maximum tolerated FSCK rate is 10MHz.

So, if by moving to spidev you have inadvertently chosen a higher clock rate, that's going to cause a lot of problems.

It is also noted that these devices don't use any form of rolling-code encryption. So if you send the same known working payload to a switch with the correct EncryptPIP and CRC and correctly encoded payload, the switch will respond. I used this in the early days of testing the physical layer by capturing a pre-encoded switch_on and switch_off with the correct header for that switch, and just replaying it.

A debugging strategy could be to use the code on the Pi4 with debug 'on' to capture the raw payload that is sent to the low level HRF transmit_buffer routine. Then write a test program on your Pi5 that just passes that raw pre-encoded buffer to the same routine on the Pi5. If it works, or if it doesn't work, that will highlight if you have a payload codec problem, or a more fundamental problem such as correct configuration of the radio config registers into FSK mode, or timing issues due to a faster than expected SPI setup.

Achronite commented 9 months ago

Hi David, the code has worked OK to date on all other Pi devices tested, and is used by quite a few people now.

The spidev version grabs (and sends) a full payload in one ioctl call, so adding debug of the decrypted payload shouldn't affect the SPI interaction. I checked and I already set the SPI clockspeed to 10000000 (10MHz), so I don't think it is that either.

The pi5 does use a new chipset for GPIO; I'm wondering if it somehow related to that, or maybe the socket is dodgy or something?

Achronite commented 9 months ago

@JamesTimothyMeech Did you get any compile errors or warnings when you ran node-gyp rebuild (just exploring if any libraries have changed at all)?

JamesTimothyMeech commented 9 months ago

Or is this the log file you wanted?

gyp info it worked if it ends with ok
gyp info using node-gyp@10.0.1
gyp info using node@20.9.0 | linux | arm64
gyp info find Python using Python version 3.11.2 found at "/usr/bin/python3"

gyp info spawn /usr/bin/python3
gyp info spawn args [
gyp info spawn args '/usr/local/lib/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/home/grappa/Desktop/energenie-ener314rt-master/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/local/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/home/grappa/.cache/node-gyp/20.9.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/home/grappa/.cache/node-gyp/20.9.0',
gyp info spawn args '-Dnode_gyp_dir=/usr/local/lib/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=/home/grappa/.cache/node-gyp/20.9.0/<(target_arch)/node.lib',
gyp info spawn args '-Dmodule_root_dir=/home/grappa/Desktop/energenie-ener314rt-master',
gyp info spawn args '-Dnode_engine=v8',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.'
gyp info spawn args ]
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/home/grappa/Desktop/energenie-ener314rt-master/build'
  CC(target) Release/obj.target/ener314rt/C/achronite/napi_energenie.o
../C/achronite/napi_energenie.c: In function 'nf_send_radio_msg':
../C/achronite/napi_energenie.c:188:78: warning: passing argument 4 of 'napi_get_buffer_info' from incompatible pointer type [-Wincompatible-pointer-types]
  188 |                 status = napi_get_buffer_info(env, argv[2], (void **)(&msg), &len);
      |                                                                              ^~~~
      |                                                                              |
      |                                                                              unsigned int *
In file included from ../C/achronite/napi_energenie.c:3:
/home/grappa/.cache/node-gyp/20.9.0/include/node/node_api.h:144:65: note: expected 'size_t *' {aka 'long unsigned int *'} but argument is of type 'unsigned int *'
  144 |                                                         size_t* length);
      |                                                         ~~~~~~~~^~~~~~
  CC(target) Release/obj.target/ener314rt/C/achronite/lock_radio.o
  CC(target) Release/obj.target/ener314rt/C/achronite/ook_send.o
  CC(target) Release/obj.target/ener314rt/C/achronite/openThings.o
  CC(target) Release/obj.target/ener314rt/C/energenie/radio.o
  CC(target) Release/obj.target/ener314rt/C/energenie/hrfm69.o
  CC(target) Release/obj.target/ener314rt/C/energenie/spis.o
  CC(target) Release/obj.target/ener314rt/C/energenie/gpio_rpi.o
../C/energenie/gpio_rpi.c: In function 'gpio_init':
../C/energenie/gpio_rpi.c:101:44: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
  101 |       printf("ener314rt: mmap error %d\n", (int)gpio_map); //errno also set!
      |                                            ^
  CC(target) Release/obj.target/ener314rt/C/energenie/delay_posix.o
  SOLINK_MODULE(target) Release/obj.target/ener314rt.node
  COPY Release/ener314rt.node
make: Leaving directory '/home/grappa/Desktop/energenie-ener314rt-master/build'
gyp info ok 

This is the output from when I ran node-gyp

JamesTimothyMeech commented 9 months ago

I doubt it, but you could always try and reset the plug by holding down the reset button.

The message it did receive (in your recent log) looks like it could be valid, but I don't know why the CRC is failing. Are you happy to try again if i add some debug code that shows the decrypted payloads and a bit more about the CRC?

Happy to try anything that could work!

Achronite commented 9 months ago

@JamesTimothyMeech OK I've fixed the type issues reported in the complie and added a dump of payload if CRC check fails.

Please download the develop branch, recompile, run the test again and paste the logs.

whaleygeek commented 9 months ago

Is the chip select managed by the spi module, or as a raw gpio write via the southbridge? If the latter, can you guarantee the chip select is asserting correctly to surround the spi transfer,or as they will be independently controlled in the latter use case, the gpio cs assert may be delayed and not correctly timed. A way to test that if you dont have a logic analyser would be to add a delay between asserting cs and triggering the spi transaction, wait a fixet time then deassert cs and delay before starting the next transaction. A delay in the order of 10 of 100ms would paper over any latency in the gpio driver, and you would prove the issue.

If this is a new issue introduced by the addition of the southbridge chip, getting a logic analyser trace would allow you to confirm that all the required timing constraints are met. For example rise and fall times on the spi bus are so critical and might not be the same on the different hardware architecture

Achronite commented 9 months ago

If this is a new issue introduced by the addition of the southbridge chip, getting a logic analyser trace would allow you to confirm that all the required timing constraints are met. For example rise and fall times on the spi bus are so critical and might not be the same on the different hardware architecture

I don't have a logic analyser, so am unable to test this. But I could try adding a wait, maybe the pi5 is just too quick :)

Achronite commented 9 months ago

I've added a 10usec delay and uploaded the code to develop. @whaleygeek there is a param delay_usecs which I previously had set to 0. It looks like the ioctl call handles the rest:

        xfer.tx_buf        = (uintptr_t)txbuf;
        xfer.rx_buf        = (uintptr_t)rxbuf;
        xfer.delay_usecs   = 10;         // allow for card to wake up (try and fix rpi5 issue)
        xfer.speed_hz      = 10000000;
        xfer.bits_per_word = 8;
        xfer.len           = len;
        xfer.cs_change     = 0;

        // transmit the register to read - this returns length of transmit
        status = ioctl(_spi_hw_fd, SPI_IOC_MESSAGE(1), &xfer);
Achronite commented 9 months ago

@JamesTimothyMeech Have you had chance to test this yet?

JamesTimothyMeech commented 9 months ago

I have been overwhelmed working on other things but I will try to test it soon. I could also try to get a logic analyser trace. Would I just need to measure the SPI clock, MOSI, and MISO?

JamesTimothyMeech commented 9 months ago

@JamesTimothyMeech OK I've fixed the type issues reported in the complie and added a dump of payload if CRC check fails.

Please download the develop branch, recompile, run the test again and paste the logs.

Here are the logs from running this code in the logs.txt file. apologies for the delay. Each time I download the develop branch I edit app.js to use the local module and then move app.js to the top directory so I can run it:

// If you would rather uses the local module build, replace the next line
//var ener314rt = require('energenie-ener314rt');
var path = require('path');
var ener314rt = require(path.join(__dirname, 'build/Release/ener314rt'));

logs.txt

whaleygeek commented 9 months ago

@JamesTimothyMeech you need the CS (chip select) as well, as the timing of that with respect to the rest of the SPI transaction is critical.

Achronite commented 9 months ago

@JamesTimothyMeech You are still calling ookSwitch repeatedly, instead of openThingsSwitch, this call is for the older 'dumb' sockets and doesnt work with the MIHO005 smart plug.

I've created some better example code for you, please use miho005.js instead; It attempts to switch a MIHO005 device '16222' on and off similar to the OOK version in app.js. Execute it using node miho005.js

JamesTimothyMeech commented 9 months ago

Ah sorry about that, I forgot I had edited the code to use openThingsSwitch for the MIHO005 and started with the clean repository. Here is a log of me running the miho005.js program, putting the socket into pairing more, and then pushing the switch button on the socket a few times. log.txt