Cheap dirty way to send a raw-mysensors message?
-
After many hours trial and error I present you .. the raw-mysensors-client!!
MyGateway: ESP8266 + mysensorsMQTT
MyNode: https://github.com/Miceuz/PlantWateringAlarm
MyNode-MCU: Attiny44 (MemoryFootprint: 87% of 4KB)
ArduinoCore: https://github.com/SpenceKonde/ATTinyCore
ArduinoCore-PinLayout: Counterclockwise (like AttinyCore)
Note: The default "counterclockwise"pinout is the alternate pinout shown here: https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x4.mdThe important hint is here (http://tmrh20.github.io/RF24/ATTiny.html)
Connect MOSI of the RF24 to PA5 of the attiny and MISO of the RF24 to PA6 of the attiny.
CE = 8
CSN = 7To get the connection done right DONT .. i mean DO NOT BECAUSE IT DOESNT FUCKING WORK connect MOSI of the RF24 to MOSI of the attiny. RF24 uses a embedded implementation of the USI-engine found on some AtTiny's.
radio-initilisation
radio.begin(); // Start up the radio radio.setDataRate(RF24_250KBPS); radio.setAutoAck(1); // Ensure autoACK is enabled radio.setRetries(15,15); // Max delay between retries & number of retries //radio.setPayloadSize(8); radio.enableDynamicPayloads(); radio.setPALevel(RF24_PA_MAX); byte tx_address[] = { 0x00, 0xFC, 0xE1, 0xA8, 0xA8 }; //byte tx_address[] = { 0xA8, 0xA8, 0xE1, 0xFC, 0x00 }; radio.openWritingPipe(tx_address); radio.stopListening();Send-Function:
void sendHumidity(uint16_t humidity) { // snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); // X8X22<\0><\n>!<7>7AY0;255;3;0;9;TSF:MSG:READ,50-50-0,s=55,c=1,t=7,pt=1,l=1,sg=0:65<\n> // 0;255;3;0;9;Sending message on topic: domoticz/in/MyMQTT/50/55/1/0/7<\n> #define LAST_NODE_ID 50 // last #define NODE_ID 50 // sender #define GATEWAY_ID 0 // destination // version_length // 5 bit - Length of payload // 1 bit - Signed flag // 2 bit - Protocol version // command_ack_payload // 3 bit - Payload data type // 1 bit - Is ack messsage - Indicator that this is the actual ack message. // 1 bit - Request an ack - Indicator that receiver should send an ack back. // 3 bit - Command type #define SENSOR_TYPE 7 // type S_HUM = 7 #define SENSOR_ID 55 // sensor-id byte test[] = { LAST_NODE_ID, NODE_ID, GATEWAY_ID, 0b00010010, 0b01100001, SENSOR_TYPE, SENSOR_ID, (uint8_t)(humidity & 0x00FF), (uint8_t)((humidity >> 8) & 0x00FF), 0x00 }; radio.write(test,9); }I am not quite sure yet if the message-types etc. are right but I am trying to find this out. 'A' (dec 65) is the "value" of my humidity .. next step is to make this a real value ofc.
Proof at domoticz:

@gohan: In the file MyConfig.h I commented this out:
/** * @def MY_REGISTRATION_FEATURE * @brief If enabled, node has to register to gateway/controller before allowed to send sensor data. */ // #define MY_REGISTRATION_FEATUREThis will skip the whole hasse of registering the client properly (which I can't .. remember 87% of flash is full)
-
After many hours trial and error I present you .. the raw-mysensors-client!!
MyGateway: ESP8266 + mysensorsMQTT
MyNode: https://github.com/Miceuz/PlantWateringAlarm
MyNode-MCU: Attiny44 (MemoryFootprint: 87% of 4KB)
ArduinoCore: https://github.com/SpenceKonde/ATTinyCore
ArduinoCore-PinLayout: Counterclockwise (like AttinyCore)
Note: The default "counterclockwise"pinout is the alternate pinout shown here: https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x4.mdThe important hint is here (http://tmrh20.github.io/RF24/ATTiny.html)
Connect MOSI of the RF24 to PA5 of the attiny and MISO of the RF24 to PA6 of the attiny.
CE = 8
CSN = 7To get the connection done right DONT .. i mean DO NOT BECAUSE IT DOESNT FUCKING WORK connect MOSI of the RF24 to MOSI of the attiny. RF24 uses a embedded implementation of the USI-engine found on some AtTiny's.
radio-initilisation
radio.begin(); // Start up the radio radio.setDataRate(RF24_250KBPS); radio.setAutoAck(1); // Ensure autoACK is enabled radio.setRetries(15,15); // Max delay between retries & number of retries //radio.setPayloadSize(8); radio.enableDynamicPayloads(); radio.setPALevel(RF24_PA_MAX); byte tx_address[] = { 0x00, 0xFC, 0xE1, 0xA8, 0xA8 }; //byte tx_address[] = { 0xA8, 0xA8, 0xE1, 0xFC, 0x00 }; radio.openWritingPipe(tx_address); radio.stopListening();Send-Function:
void sendHumidity(uint16_t humidity) { // snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); // X8X22<\0><\n>!<7>7AY0;255;3;0;9;TSF:MSG:READ,50-50-0,s=55,c=1,t=7,pt=1,l=1,sg=0:65<\n> // 0;255;3;0;9;Sending message on topic: domoticz/in/MyMQTT/50/55/1/0/7<\n> #define LAST_NODE_ID 50 // last #define NODE_ID 50 // sender #define GATEWAY_ID 0 // destination // version_length // 5 bit - Length of payload // 1 bit - Signed flag // 2 bit - Protocol version // command_ack_payload // 3 bit - Payload data type // 1 bit - Is ack messsage - Indicator that this is the actual ack message. // 1 bit - Request an ack - Indicator that receiver should send an ack back. // 3 bit - Command type #define SENSOR_TYPE 7 // type S_HUM = 7 #define SENSOR_ID 55 // sensor-id byte test[] = { LAST_NODE_ID, NODE_ID, GATEWAY_ID, 0b00010010, 0b01100001, SENSOR_TYPE, SENSOR_ID, (uint8_t)(humidity & 0x00FF), (uint8_t)((humidity >> 8) & 0x00FF), 0x00 }; radio.write(test,9); }I am not quite sure yet if the message-types etc. are right but I am trying to find this out. 'A' (dec 65) is the "value" of my humidity .. next step is to make this a real value ofc.
Proof at domoticz:

@gohan: In the file MyConfig.h I commented this out:
/** * @def MY_REGISTRATION_FEATURE * @brief If enabled, node has to register to gateway/controller before allowed to send sensor data. */ // #define MY_REGISTRATION_FEATUREThis will skip the whole hasse of registering the client properly (which I can't .. remember 87% of flash is full)
-
I might have run into a bug in the calculation of message length.In my handcrafted packet I use this as the 4thy byte send:0b10000001So to craft this I looked at MyMessage.h which showed me this:uint8_t version_length; // 2 bit - Protocol version // 1 bit - Signed flag // 5 bit - Length of payloadSo from my understanding:Protocol Version = 2 => 0b10
Signed Flag = 0 => 0b0
Length of Payload = 1 = 0b00001Which results in 0b10 0 00001 = 0b10000001But I get this error:LEN,8!=23So .. where might this come from?radio.write(test,8);Mycontroller received a packet with the length of 8 but expected a packet with the length of .. 23 ?!#define mGetLength(_message) ((uint8_t)BF_GET(_message.version_length, 3, 5)) //!< Get length fieldWhich in essential is BF_GET ..#define BF_GET(y, start, len) ( ((y)>>(start)) & BIT_MASK(len) ) //!< Extract a bitfield of length 'len' starting at bit 'start' from 'y'So what is happening?BF_GET(0b10000001, 3, 5) ( ((0b10000001)>>(3)) & BIT_MASK(5) ) //!< Extract a bitfield of length 'len' starting at bit 'start'Whoops? This will throw away all the length-information!!!
(0b10000001)>>(3)
This should result in:
0b11110000 & BIT_MASK5 = 0b1111000 & 0b00011111 = 0b00010000 = 16 decimalconst uint8_t expectedMessageLength = HEADER_SIZE + (mGetSigned(_msg) ? MAX_PAYLOAD : msgLength);const uint8_t expectedMessageLength = 7+ 16); // = 23Yeah .. the lib is right .. 8 != 23 .. but the handcrafted length = 1 + header_length (7) = 8Am I wrong or is this a bug?Edit: I might have read the comments in the source code the wrong way
-
From time to time I run into this bug .. not sure if this is related:
0;255;3;0;9;TSM:READY:NWD REQ<\n> 0;255;3;0;9;TSF:MSG:SEND,0-0-255-255,s=255,c=3,t=20,pt=0,l=0,sg=0,ft=0,st=OK:<\n> Fatal exception 28(LoadProhibitedCause):<\n> epc1=0x40202704, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00000003, depc=0x00000000<\n> <\r><\n> -
I wish the chirp had been designed with an atmega328p. Cost and footprint for the smd is similar I believe
-
Its not "that" bad .. the Attiny44A is compatible with Arduino thanks to https://github.com/SpenceKonde/ATTinyCore
For now I got Humidity and Voltage(VCC) running up fine.
-
@cimba007 Could you please share your latest working code for generating the packet?
I've created an ATTiny841 node with the RFM69CW radio (with a modified RFM69 library to match the radio config registers of MySensors) but the Raspberry Pi gateway is seeing the packets different.
Here is the sending part:
byte test[] = { 1, // last 1, // sender 255, // destination 0b00001010, // version_length: 2 bit - Protocol version (2), 1 bit - Signed flag (no), 5 bit - Length of payload (1 byte) 0b00100001, // command_ack_payload: 3 bit - Command type (C_SET), 1 bit - Request an ack (no), 1 bit - Is ack message (no), 3 bit - Payload data type (P_BYTE) 16, // type: V_TRIPPED 3, // sensor ID 1 // Value: 1 }; radio.send(255, packet, strlen(packet));which is received as:
DEBUG TSF:MSG:READ,10-255-33,s=0,c=3,t=1,pt=0,l=2,sg=0: DEBUG !TSF:MSG:LEN,6!=9where none of the fields match the packet :(
Here is the packet definition in core/MyMessage.h:
uint8_t last; ///< 8 bit - Id of last node this message passed uint8_t sender; ///< 8 bit - Id of sender node (origin) uint8_t destination; ///< 8 bit - Id of destination node /** * 2 bit - Protocol version<br> * 1 bit - Signed flag<br> * 5 bit - Length of payload */ uint8_t version_length; /** * 3 bit - Command type<br> * 1 bit - Request an ack - Indicator that receiver should send an ack back<br> * 1 bit - Is ack message - Indicator that this is the actual ack message<br> * 3 bit - Payload data type */ uint8_t command_ack_payload; uint8_t type; ///< 8 bit - Type varies depending on command uint8_t sensor; ///< 8 bit - Id of sensor that this message concerns. /* * Each message can transfer a payload. We add one extra byte for string * terminator \0 to be "printable" this is not transferred OTA * This union is used to simplify the construction of the binary data types transferred. */ union { uint8_t bValue; ///< unsigned byte value (8-bit) uint16_t uiValue; ///< unsigned integer value (16-bit) int16_t iValue; ///< signed integer value (16-bit) uint32_t ulValue; ///< unsigned long value (32-bit) int32_t lValue; ///< signed long value (32-bit) struct { //< Float messages float fValue; uint8_t fPrecision; ///< Number of decimals when serializing }; struct { //< Presentation messages uint8_t version; ///< Library version uint8_t sensorType; ///< Sensor type hint for controller, see table above }; char data[MAX_PAYLOAD + 1]; ///< Buffer for raw payload data } __attribute__((packed)); ///< Doxygen will complain without this commentI'll try and log the raw incoming packet on the Pi side just to confirm that the radio config is actually matching.
-
@cimba007 Could you please share your latest working code for generating the packet?
I've created an ATTiny841 node with the RFM69CW radio (with a modified RFM69 library to match the radio config registers of MySensors) but the Raspberry Pi gateway is seeing the packets different.
Here is the sending part:
byte test[] = { 1, // last 1, // sender 255, // destination 0b00001010, // version_length: 2 bit - Protocol version (2), 1 bit - Signed flag (no), 5 bit - Length of payload (1 byte) 0b00100001, // command_ack_payload: 3 bit - Command type (C_SET), 1 bit - Request an ack (no), 1 bit - Is ack message (no), 3 bit - Payload data type (P_BYTE) 16, // type: V_TRIPPED 3, // sensor ID 1 // Value: 1 }; radio.send(255, packet, strlen(packet));which is received as:
DEBUG TSF:MSG:READ,10-255-33,s=0,c=3,t=1,pt=0,l=2,sg=0: DEBUG !TSF:MSG:LEN,6!=9where none of the fields match the packet :(
Here is the packet definition in core/MyMessage.h:
uint8_t last; ///< 8 bit - Id of last node this message passed uint8_t sender; ///< 8 bit - Id of sender node (origin) uint8_t destination; ///< 8 bit - Id of destination node /** * 2 bit - Protocol version<br> * 1 bit - Signed flag<br> * 5 bit - Length of payload */ uint8_t version_length; /** * 3 bit - Command type<br> * 1 bit - Request an ack - Indicator that receiver should send an ack back<br> * 1 bit - Is ack message - Indicator that this is the actual ack message<br> * 3 bit - Payload data type */ uint8_t command_ack_payload; uint8_t type; ///< 8 bit - Type varies depending on command uint8_t sensor; ///< 8 bit - Id of sensor that this message concerns. /* * Each message can transfer a payload. We add one extra byte for string * terminator \0 to be "printable" this is not transferred OTA * This union is used to simplify the construction of the binary data types transferred. */ union { uint8_t bValue; ///< unsigned byte value (8-bit) uint16_t uiValue; ///< unsigned integer value (16-bit) int16_t iValue; ///< signed integer value (16-bit) uint32_t ulValue; ///< unsigned long value (32-bit) int32_t lValue; ///< signed long value (32-bit) struct { //< Float messages float fValue; uint8_t fPrecision; ///< Number of decimals when serializing }; struct { //< Presentation messages uint8_t version; ///< Library version uint8_t sensorType; ///< Sensor type hint for controller, see table above }; char data[MAX_PAYLOAD + 1]; ///< Buffer for raw payload data } __attribute__((packed)); ///< Doxygen will complain without this commentI'll try and log the raw incoming packet on the Pi side just to confirm that the radio config is actually matching.
Turns out that the RFM69 arduino library was missing two additional bytes from the packet header --
rfm69_header_t.versionandrfm69_header_t.sequenceNumberinRFM69::sendFrame()(see the diff).select(); SPI.transfer(REG_FIFO | 0x80); // Select the FIFO write register. SPI.transfer(bufferSize + 5); // rfm69_header_t.packetLen SPI.transfer(toAddress); // rfm69_header_t.recipient SPI.transfer(1); // RFM69_PACKET_HEADER_VERSION = (1u) rfm69_header_t.version header version (20180128tk: >=3.0.0 fused with controlFlags) SPI.transfer(_address); // rfm69_header_t.sender SPI.transfer(CTLbyte); // rfm69_header_t.controlFlags SPI.transfer(0); // rfm69_header_t.sequenceNumber for (uint8_t i = 0; i < bufferSize; i++) SPI.transfer(((uint8_t*) buffer)[i]); unselect();So after adding
SPI.transfer(1);asrfm69_header_t.versionandSPI.transfer(0);asrfm69_header_t.sequenceNumberthe packets are now being parsed correctly:DEBUG TSF:MSG:READ,1-1-255,s=3,c=1,t=16,pt=1,l=1,sg=0:1 DEBUG TSF:MSG:BC -
After many hours trial and error I present you .. the raw-mysensors-client!!
MyGateway: ESP8266 + mysensorsMQTT
MyNode: https://github.com/Miceuz/PlantWateringAlarm
MyNode-MCU: Attiny44 (MemoryFootprint: 87% of 4KB)
ArduinoCore: https://github.com/SpenceKonde/ATTinyCore
ArduinoCore-PinLayout: Counterclockwise (like AttinyCore)
Note: The default "counterclockwise"pinout is the alternate pinout shown here: https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x4.mdThe important hint is here (http://tmrh20.github.io/RF24/ATTiny.html)
Connect MOSI of the RF24 to PA5 of the attiny and MISO of the RF24 to PA6 of the attiny.
CE = 8
CSN = 7To get the connection done right DONT .. i mean DO NOT BECAUSE IT DOESNT FUCKING WORK connect MOSI of the RF24 to MOSI of the attiny. RF24 uses a embedded implementation of the USI-engine found on some AtTiny's.
radio-initilisation
radio.begin(); // Start up the radio radio.setDataRate(RF24_250KBPS); radio.setAutoAck(1); // Ensure autoACK is enabled radio.setRetries(15,15); // Max delay between retries & number of retries //radio.setPayloadSize(8); radio.enableDynamicPayloads(); radio.setPALevel(RF24_PA_MAX); byte tx_address[] = { 0x00, 0xFC, 0xE1, 0xA8, 0xA8 }; //byte tx_address[] = { 0xA8, 0xA8, 0xE1, 0xFC, 0x00 }; radio.openWritingPipe(tx_address); radio.stopListening();Send-Function:
void sendHumidity(uint16_t humidity) { // snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); // X8X22<\0><\n>!<7>7AY0;255;3;0;9;TSF:MSG:READ,50-50-0,s=55,c=1,t=7,pt=1,l=1,sg=0:65<\n> // 0;255;3;0;9;Sending message on topic: domoticz/in/MyMQTT/50/55/1/0/7<\n> #define LAST_NODE_ID 50 // last #define NODE_ID 50 // sender #define GATEWAY_ID 0 // destination // version_length // 5 bit - Length of payload // 1 bit - Signed flag // 2 bit - Protocol version // command_ack_payload // 3 bit - Payload data type // 1 bit - Is ack messsage - Indicator that this is the actual ack message. // 1 bit - Request an ack - Indicator that receiver should send an ack back. // 3 bit - Command type #define SENSOR_TYPE 7 // type S_HUM = 7 #define SENSOR_ID 55 // sensor-id byte test[] = { LAST_NODE_ID, NODE_ID, GATEWAY_ID, 0b00010010, 0b01100001, SENSOR_TYPE, SENSOR_ID, (uint8_t)(humidity & 0x00FF), (uint8_t)((humidity >> 8) & 0x00FF), 0x00 }; radio.write(test,9); }I am not quite sure yet if the message-types etc. are right but I am trying to find this out. 'A' (dec 65) is the "value" of my humidity .. next step is to make this a real value ofc.
Proof at domoticz:

@gohan: In the file MyConfig.h I commented this out:
/** * @def MY_REGISTRATION_FEATURE * @brief If enabled, node has to register to gateway/controller before allowed to send sensor data. */ // #define MY_REGISTRATION_FEATUREThis will skip the whole hasse of registering the client properly (which I can't .. remember 87% of flash is full)