Skip to content

Commit d62ca6d

Browse files
authored
Add multi-message support (#1517) (#1515)
Excellent contribution by @cpetra ! Thanks to @virtual-maker for extensive feedback on the PR.
1 parent aa76d26 commit d62ca6d

File tree

6 files changed

+440
-2
lines changed

6 files changed

+440
-2
lines changed

MySensors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
440440

441441
#include "core/MyCapabilities.h"
442442
#include "core/MyMessage.cpp"
443+
#include "core/MyMultiMessage.cpp"
443444
#include "core/MySplashScreen.cpp"
444445
#include "core/MySensorsCore.cpp"
445446

core/MyMessage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ typedef enum {
183183
V_VAR = 54, //!< S_POWER, Reactive power: volt-ampere reactive (var)
184184
V_VA = 55, //!< S_POWER, Apparent power: volt-ampere (VA)
185185
V_POWER_FACTOR = 56, //!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1]
186+
V_MULTI_MESSAGE = 57, //!< Special type, multiple sensors in one message
186187
} mysensors_data_t;
187188
#endif
188189

core/MyMultiMessage.cpp

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* The MySensors Arduino library handles the wireless radio link and protocol
3+
* between your home built sensors/actuators and HA controller of choice.
4+
* The sensors forms a self healing radio network with optional repeaters. Each
5+
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
6+
* network topology allowing messages to be routed to nodes.
7+
*
8+
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
9+
* Copyright (C) 2013-2020 Sensnology AB
10+
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
11+
*
12+
* Documentation: http://www.mysensors.org
13+
* Support Forum: http://forum.mysensors.org
14+
*
15+
* Multi message feature added by Constantin Petra <constantin.petra@gmail.com>
16+
* Copyright (C) 2022 Constantin Petra
17+
*
18+
* This program is free software; you can redistribute it and/or
19+
* modify it under the terms of the GNU General Public License
20+
* version 2 as published by the Free Software Foundation.
21+
*/
22+
23+
#include "Version.h"
24+
#include "MyConfig.h"
25+
#include "MyEepromAddresses.h"
26+
#include "MyMessage.h"
27+
#include "MyMultiMessage.h"
28+
#include "stddef.h"
29+
30+
#define SET_PAYLOAD_TYPE(u, type) BF_SET(u, type, V2_MYS_HEADER_CEP_PAYLOADTYPE_POS, \
31+
V2_MYS_HEADER_CEP_PAYLOADTYPE_SIZE)
32+
#define GET_PAYLOAD_TYPE(u) BF_GET(u, V2_MYS_HEADER_CEP_PAYLOADTYPE_POS, \
33+
V2_MYS_HEADER_CEP_PAYLOADTYPE_SIZE)
34+
#define SET_COMMAND(u, command) BF_SET(u, command, V2_MYS_HEADER_CEP_COMMAND_POS, \
35+
V2_MYS_HEADER_CEP_COMMAND_SIZE)
36+
#define GET_COMMAND(u) BF_GET(u, V2_MYS_HEADER_CEP_COMMAND_POS, \
37+
V2_MYS_HEADER_CEP_COMMAND_SIZE)
38+
#define SET_LENGTH(u, finalLength) BF_SET(u, finalLength, V2_MYS_HEADER_VSL_LENGTH_POS, \
39+
V2_MYS_HEADER_VSL_LENGTH_SIZE)
40+
#define GET_LENGTH(u) BF_GET(u, V2_MYS_HEADER_VSL_LENGTH_POS, \
41+
V2_MYS_HEADER_VSL_LENGTH_SIZE)
42+
#define SET_VERSION(u) BF_SET(u, V2_MYS_HEADER_PROTOCOL_VERSION, \
43+
V2_MYS_HEADER_VSL_VERSION_POS, V2_MYS_HEADER_VSL_VERSION_SIZE);
44+
45+
#define MAX_BLOB_SIZE (MAX_PAYLOAD_SIZE)
46+
47+
// replicates part of the MyMesgage structure related to a single sensor data.
48+
typedef struct {
49+
uint8_t command_echo_payload;
50+
uint8_t type;
51+
uint8_t sensor;
52+
union {
53+
uint8_t bValue;
54+
uint16_t uiValue;
55+
int16_t iValue;
56+
uint32_t ulValue;
57+
int32_t lValue;
58+
struct {
59+
float fValue;
60+
uint8_t fPrecision;
61+
};
62+
} __attribute__((packed));
63+
} __attribute__((packed)) blob;
64+
65+
MyMultiMessage::~MyMultiMessage()
66+
{
67+
68+
}
69+
70+
MyMultiMessage::MyMultiMessage(MyMessage *msg)
71+
{
72+
_msg = msg;
73+
_offset = 0;
74+
_msg->setPayloadType(P_CUSTOM);
75+
}
76+
77+
void *MyMultiMessage::common(uint8_t messageType, uint8_t sensor, uint8_t ptype, uint8_t size,
78+
uint8_t cmd)
79+
{
80+
blob *b;
81+
if (_offset + size > MAX_BLOB_SIZE) {
82+
return NULL;
83+
}
84+
b = (blob *)(_msg->data + _offset);
85+
SET_PAYLOAD_TYPE(b->command_echo_payload, ptype);
86+
SET_COMMAND(b->command_echo_payload, cmd);
87+
b->type = messageType;
88+
b->sensor = sensor;
89+
_offset += size;
90+
SET_LENGTH(_msg->version_length, _offset);
91+
SET_VERSION(_msg->version_length);
92+
return b;
93+
}
94+
95+
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, uint8_t value)
96+
{
97+
blob *b = (blob *)common(messageType, sensor, P_BYTE, 4, C_SET);
98+
if (b == NULL) {
99+
return false;
100+
}
101+
b->bValue = value;
102+
return true;
103+
}
104+
105+
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, uint16_t value)
106+
{
107+
blob *b = (blob *)common(messageType, sensor, P_UINT16, 5, C_SET);
108+
if (b == NULL) {
109+
return false;
110+
}
111+
b->uiValue = value;
112+
return true;
113+
}
114+
115+
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, int16_t value)
116+
{
117+
blob *b = (blob *)common(messageType, sensor, P_INT16, 5, C_SET);
118+
if (b == NULL) {
119+
return false;
120+
}
121+
b->uiValue = value;
122+
return true;
123+
}
124+
125+
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, uint32_t value)
126+
{
127+
blob *b = (blob *)common(messageType, sensor, P_ULONG32, 7, C_SET);
128+
if (b == NULL) {
129+
return false;
130+
}
131+
b->ulValue = value;
132+
return true;
133+
}
134+
135+
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, int32_t value)
136+
{
137+
blob *b = (blob *)common(messageType, sensor, P_LONG32, 7, C_SET);
138+
139+
if (b == NULL) {
140+
return false;
141+
}
142+
b->lValue = value;
143+
return true;
144+
}
145+
146+
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, float value, uint8_t decimals)
147+
{
148+
blob *b = (blob *)common(messageType, sensor, P_FLOAT32, 8, C_SET);
149+
150+
if (b == NULL) {
151+
return false;
152+
}
153+
b->fValue = value;
154+
b->fPrecision = decimals;
155+
return true;
156+
}
157+
158+
bool MyMultiMessage::setBattery(uint8_t value)
159+
{
160+
blob *b = (blob *)common(I_BATTERY_LEVEL, NODE_SENSOR_ID, P_BYTE, 4, C_INTERNAL);
161+
162+
if (b == NULL) {
163+
return false;
164+
}
165+
b->bValue = value;
166+
return true;
167+
}
168+
169+
170+
bool MyMultiMessage::getNext(MyMessage &m)
171+
{
172+
uint8_t size = GET_LENGTH(_msg->version_length);
173+
uint8_t type;
174+
175+
blob *b;
176+
if (_offset >= size) {
177+
return false;
178+
}
179+
180+
m.last = _msg->last;
181+
m.sender = _msg->sender;
182+
m.destination = _msg->destination;
183+
m.version_length = _msg->version_length;
184+
185+
b = (blob *)(_msg->data + _offset);
186+
m.type = b->type;
187+
m.sensor = b->sensor;
188+
189+
type = GET_PAYLOAD_TYPE(b->command_echo_payload);
190+
m.command_echo_payload = b->command_echo_payload;
191+
192+
if (type == P_BYTE) {
193+
m.bValue = b->bValue;
194+
_offset += 4;
195+
return true;
196+
} else if (type == P_UINT16) {
197+
m.uiValue = b->uiValue;
198+
_offset += 5;
199+
return true;
200+
} else if (type == P_INT16) {
201+
m.iValue = b->iValue;
202+
_offset += 5;
203+
return true;
204+
} else if (type == P_ULONG32) {
205+
m.ulValue = b->ulValue;
206+
_offset += 7;
207+
return true;
208+
} else if (type == P_LONG32) {
209+
m.lValue = b->lValue;
210+
_offset += 7;
211+
return true;
212+
} else if (type == P_FLOAT32) {
213+
m.fValue = b->fValue;
214+
m.fPrecision = b->fPrecision;
215+
_offset += 8;
216+
return true;
217+
}
218+
return false;
219+
}
220+
221+
void MyMultiMessage::reset()
222+
{
223+
_offset = 0;
224+
SET_LENGTH(_msg->version_length, _offset);
225+
}

0 commit comments

Comments
 (0)