mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-02 10:51:57 +00:00
* CLI: removed "sub" and "unsub" (cannot support via command line)
* _SUBSCRIBE: binary req/resp payload changes (now keeps supplied 'push_tag') * Sensor: added MCU temperature support in telemetry
This commit is contained in:
@@ -55,8 +55,10 @@
|
|||||||
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
||||||
#define REQ_TYPE_GET_AVG_MIN_MAX 0x04
|
#define REQ_TYPE_GET_AVG_MIN_MAX 0x04
|
||||||
#define REQ_TYPE_GET_ACCESS_LIST 0x05
|
#define REQ_TYPE_GET_ACCESS_LIST 0x05
|
||||||
#define REQ_TYPE_SUBSCRIBE 0x10
|
#define REQ_TYPE_GET_NEIGHBOURS 0x06 // repeater only (at present)
|
||||||
#define REQ_TYPE_UNSUBSCRIBE 0x11
|
|
||||||
|
#define REQ_TYPE_SUBSCRIBE 0x08
|
||||||
|
#define REQ_TYPE_UNSUBSCRIBE 0x09
|
||||||
|
|
||||||
#define RESP_SERVER_LOGIN_OK 0 // response to ANON_REQ
|
#define RESP_SERVER_LOGIN_OK 0 // response to ANON_REQ
|
||||||
|
|
||||||
@@ -193,43 +195,6 @@ static float findTelemValue(const uint8_t* buf, uint8_t size, uint8_t channel, u
|
|||||||
return 0.0f; // not found
|
return 0.0f; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t compileLPPSpec(char* txt, uint8_t* dest, size_t max_len) {
|
|
||||||
const char* parts[3];
|
|
||||||
int n = mesh::Utils::parseTextParts(txt, parts, 3, ',');
|
|
||||||
uint8_t len = 0;
|
|
||||||
for (int i = 0; i < n && len + 6 <= max_len; i++) {
|
|
||||||
const char* cp = strchr(parts[i], ':');
|
|
||||||
if (cp) {
|
|
||||||
uint8_t t;
|
|
||||||
float factor = 1.0f;
|
|
||||||
cp++; // skip the ':'
|
|
||||||
char* ep = strchr(cp, 0) - 1; // find LAST char
|
|
||||||
if (*ep == 'V') { // Volts
|
|
||||||
t = LPP_VOLTAGE;
|
|
||||||
} else if (*ep == 'W') { // Watts
|
|
||||||
t = LPP_POWER;
|
|
||||||
} else if (*ep == 'C') { // Celcius
|
|
||||||
t = LPP_TEMPERATURE;
|
|
||||||
} else if (*ep == 'P') { // Pascals
|
|
||||||
t = LPP_BAROMETRIC_PRESSURE;
|
|
||||||
} else if (*ep == 'A') { // Amps
|
|
||||||
t = LPP_CURRENT;
|
|
||||||
} else if (*ep == 'm') {
|
|
||||||
t = LPP_DISTANCE; factor = 0.001f;
|
|
||||||
} else {
|
|
||||||
t = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t) {
|
|
||||||
dest[len++] = atoi(parts[i]); // channel number
|
|
||||||
dest[len++] = t; // LPP type
|
|
||||||
len += putFloat(&dest[len], atof(cp) * factor, getDataSize(t), getMultiplier(t), isSigned(t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------ end Cayenne LPP helpers ----------------------*/
|
/* ------------------ end Cayenne LPP helpers ----------------------*/
|
||||||
|
|
||||||
bool SensorMesh::telemHasChanged(const uint8_t* min_deltas, uint8_t min_deltas_len) {
|
bool SensorMesh::telemHasChanged(const uint8_t* min_deltas, uint8_t min_deltas_len) {
|
||||||
@@ -269,6 +234,10 @@ uint8_t SensorMesh::handleRequest(ClientInfo* from, uint32_t sender_timestamp, u
|
|||||||
// query other sensors -- target specific
|
// query other sensors -- target specific
|
||||||
sensors.querySensors(0xFF & perm_mask, telemetry); // allow all telemetry permissions for admin or guest
|
sensors.querySensors(0xFF & perm_mask, telemetry); // allow all telemetry permissions for admin or guest
|
||||||
// TODO: let requester know permissions they have: telemetry.addPresence(TELEM_CHANNEL_SELF, perms);
|
// TODO: let requester know permissions they have: telemetry.addPresence(TELEM_CHANNEL_SELF, perms);
|
||||||
|
float temperature = board.getMCUTemperature();
|
||||||
|
if (!isnan(temperature)) { // Supported boards with built-in temperature sensor. ESP32-C3 may return NAN
|
||||||
|
telemetry.addTemperature(TELEM_CHANNEL_SELF, temperature); // Built-in MCU Temperature
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t tlen = telemetry.getSize();
|
uint8_t tlen = telemetry.getSize();
|
||||||
memcpy(&reply_data[4], telemetry.getBuffer(), tlen);
|
memcpy(&reply_data[4], telemetry.getBuffer(), tlen);
|
||||||
@@ -322,10 +291,11 @@ uint8_t SensorMesh::handleRequest(ClientInfo* from, uint32_t sender_timestamp, u
|
|||||||
return ofs;
|
return ofs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (req_type == REQ_TYPE_SUBSCRIBE && payload_len >= 4 && (perms & PERM_ACL_ROLE_MASK) >= PERM_ACL_READ_ONLY) {
|
if (req_type == REQ_TYPE_SUBSCRIBE && payload_len >= 8 && (perms & PERM_ACL_ROLE_MASK) >= PERM_ACL_READ_ONLY) {
|
||||||
|
memcpy(&from->extra.sensor.push_tag, &payload[0], 4);
|
||||||
uint16_t timeout_secs;
|
uint16_t timeout_secs;
|
||||||
memcpy(&timeout_secs, &payload[0], 2);
|
memcpy(&timeout_secs, &payload[4], 2);
|
||||||
uint8_t reserved = payload[2];
|
uint8_t reserved = payload[6];
|
||||||
RegionEntry* r;
|
RegionEntry* r;
|
||||||
if (recv_pkt_region && !recv_pkt_region->isWildcard()) { // use request scope
|
if (recv_pkt_region && !recv_pkt_region->isWildcard()) { // use request scope
|
||||||
r = recv_pkt_region;
|
r = recv_pkt_region;
|
||||||
@@ -334,16 +304,17 @@ uint8_t SensorMesh::handleRequest(ClientInfo* from, uint32_t sender_timestamp, u
|
|||||||
}
|
}
|
||||||
from->extra.sensor.scope_region_id = r ? r->id : 0;
|
from->extra.sensor.scope_region_id = r ? r->id : 0;
|
||||||
from->extra.sensor.expiry_timestamp = r ? getRTCClock()->getCurrentTime() + timeout_secs : 0;
|
from->extra.sensor.expiry_timestamp = r ? getRTCClock()->getCurrentTime() + timeout_secs : 0;
|
||||||
from->extra.sensor.min_deltas_len = payload[3];
|
from->extra.sensor.min_deltas_len = min(sizeof(from->extra.sensor.min_deltas), (size_t)payload[7]);
|
||||||
// NOTE: curr impl truncates LPP min_diffs spec (re-do if better impl is needed)
|
// NOTE: curr impl truncates LPP min_diffs spec (re-do if better impl is needed)
|
||||||
memcpy(from->extra.sensor.min_deltas, &payload[4], min(sizeof(from->extra.sensor.min_deltas), (size_t)payload[3]));
|
memcpy(from->extra.sensor.min_deltas, &payload[8], from->extra.sensor.min_deltas_len);
|
||||||
|
|
||||||
memcpy(&reply_data[4], &from->extra.sensor.expiry_timestamp, 4); // reply with actual expiry timestamp (or 0 for error)
|
memcpy(&reply_data[4], &from->extra.sensor.expiry_timestamp, 4); // reply with actual expiry timestamp (or 0 for error)
|
||||||
strcpy((char *)&reply_data[8], r ? r->name : ""); // reply with name of scope that will be used
|
strcpy((char *)&reply_data[8], r ? r->name : ""); // reply with name of scope that will be used
|
||||||
return 6 + strlen((char *)&reply_data[8]);
|
return 8 + strlen((char *)&reply_data[8]);
|
||||||
}
|
}
|
||||||
if (req_type == REQ_TYPE_UNSUBSCRIBE && (perms & PERM_ACL_ROLE_MASK) >= PERM_ACL_READ_ONLY) {
|
if (req_type == REQ_TYPE_UNSUBSCRIBE && (perms & PERM_ACL_ROLE_MASK) >= PERM_ACL_READ_ONLY) {
|
||||||
from->extra.sensor.scope_region_id = 0;
|
from->extra.sensor.scope_region_id = 0;
|
||||||
|
from->extra.sensor.push_tag = 0;
|
||||||
from->extra.sensor.expiry_timestamp = 0;
|
from->extra.sensor.expiry_timestamp = 0;
|
||||||
// REVISIT: maybe return some stats, eg total number of telemetry pushes since SUBSCRIBE?
|
// REVISIT: maybe return some stats, eg total number of telemetry pushes since SUBSCRIBE?
|
||||||
reply_data[4] = 0; // success
|
reply_data[4] = 0; // success
|
||||||
@@ -597,43 +568,6 @@ void SensorMesh::handleCommand(ClientInfo* from, uint32_t sender_timestamp, char
|
|||||||
Serial.printf("\n");
|
Serial.printf("\n");
|
||||||
}
|
}
|
||||||
reply[0] = 0;
|
reply[0] = 0;
|
||||||
} else if (from != NULL && memcmp(command, "sub", 3) == 0 && (command[3] == ' ' || command[3] == 0)) { // subscribe
|
|
||||||
uint8_t perms = from->isAdmin() ? 0xFF : from->permissions;
|
|
||||||
if ((perms & PERM_ACL_ROLE_MASK) >= PERM_ACL_READ_ONLY) {
|
|
||||||
RegionEntry* r;
|
|
||||||
if (recv_pkt_region && !recv_pkt_region->isWildcard()) { // use request scope
|
|
||||||
r = recv_pkt_region;
|
|
||||||
} else { // use default scope
|
|
||||||
r = region_map.getDefaultRegion();
|
|
||||||
}
|
|
||||||
// defaults:
|
|
||||||
from->extra.sensor.min_deltas_len = 0; // no minimums (telemetry just needs to CHANGE)
|
|
||||||
uint16_t timeout_secs = 30*60; // expires after 30 mins
|
|
||||||
if (command[3] == ' ') { // eg. "sub 300 1:0.2V"
|
|
||||||
char* cp = &command[4];
|
|
||||||
while (*cp >= '0' && *cp <= '9') cp++;
|
|
||||||
if (cp > &command[4]) {
|
|
||||||
timeout_secs = atoi(&command[4]);
|
|
||||||
if (*cp == ' ') {
|
|
||||||
cp++; // skip the space
|
|
||||||
from->extra.sensor.min_deltas_len = compileLPPSpec(cp, from->extra.sensor.min_deltas, sizeof(from->extra.sensor.min_deltas));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
from->extra.sensor.scope_region_id = r ? r->id : 0;
|
|
||||||
from->extra.sensor.expiry_timestamp = r ? getRTCClock()->getCurrentTime() + timeout_secs : 0;
|
|
||||||
if (from->extra.sensor.expiry_timestamp) {
|
|
||||||
DateTime dt = DateTime(from->extra.sensor.expiry_timestamp);
|
|
||||||
sprintf(reply, "OK - sub expires: %02d:%02d (UTC)", dt.hour(), dt.minute());
|
|
||||||
} else {
|
|
||||||
strcpy(reply, "Err - region scope needed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
strcpy(reply, "Err - no permission");
|
|
||||||
}
|
|
||||||
} else if (from != NULL && strcmp(command, "unsub") == 0) { // unsubscribe
|
|
||||||
from->extra.sensor.scope_region_id = 0;
|
|
||||||
strcpy(reply, "OK - unsubscribed");
|
|
||||||
} else if (memcmp(command, "io ", 2) == 0) { // io {value}: write, io: read
|
} else if (memcmp(command, "io ", 2) == 0) { // io {value}: write, io: read
|
||||||
if (command[2] == ' ') { // it's a write
|
if (command[2] == ' ') { // it's a write
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
@@ -1172,6 +1106,11 @@ void SensorMesh::loop() {
|
|||||||
telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
|
telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
|
||||||
// query other sensors -- target specific
|
// query other sensors -- target specific
|
||||||
sensors.querySensors(0xFF, telemetry); // allow all telemetry permissions
|
sensors.querySensors(0xFF, telemetry); // allow all telemetry permissions
|
||||||
|
// This MCU temperature will be overridden by external sensors (if any)
|
||||||
|
float temperature = board.getMCUTemperature();
|
||||||
|
if (!isnan(temperature)) { // Supported boards with built-in temperature sensor. ESP32-C3 may return NAN
|
||||||
|
telemetry.addTemperature(TELEM_CHANNEL_SELF, temperature); // Built-in MCU Temperature
|
||||||
|
}
|
||||||
|
|
||||||
// compare with previous telemetry, check if any deltas are greater than subscriber minimums
|
// compare with previous telemetry, check if any deltas are greater than subscriber minimums
|
||||||
for (int i = 0; i < acl.getNumClients(); i++) {
|
for (int i = 0; i < acl.getNumClients(); i++) {
|
||||||
@@ -1184,11 +1123,12 @@ void SensorMesh::loop() {
|
|||||||
TransportKey scope;
|
TransportKey scope;
|
||||||
if (region_map.getTransportKeysFor(*r, &scope, 1) > 0) {
|
if (region_map.getTransportKeysFor(*r, &scope, 1) > 0) {
|
||||||
uint8_t tlen = telemetry.getSize();
|
uint8_t tlen = telemetry.getSize();
|
||||||
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique(); // this will be an unknown 'tag' to the client
|
memcpy(reply_data, &c->extra.sensor.push_tag, 4);
|
||||||
memcpy(reply_data, ×tamp, 4);
|
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
|
||||||
memcpy(&reply_data[4], telemetry.getBuffer(), tlen);
|
memcpy(&reply_data[4], ×tamp, 4);
|
||||||
|
memcpy(&reply_data[8], telemetry.getBuffer(), tlen);
|
||||||
|
|
||||||
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, c->id, c->shared_secret, reply_data, 4 + tlen);
|
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, c->id, c->shared_secret, reply_data, 8 + tlen);
|
||||||
if (reply) {
|
if (reply) {
|
||||||
if (c->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
|
if (c->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
|
||||||
sendDirect(reply, c->out_path, c->out_path_len, 0);
|
sendDirect(reply, c->out_path, c->out_path_len, 0);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ struct ClientInfo {
|
|||||||
} room;
|
} room;
|
||||||
struct {
|
struct {
|
||||||
uint32_t expiry_timestamp; // epoch seconds
|
uint32_t expiry_timestamp; // epoch seconds
|
||||||
|
uint32_t push_tag;
|
||||||
uint16_t scope_region_id; // scope to use when sending telemetry to this client/subscriber
|
uint16_t scope_region_id; // scope to use when sending telemetry to this client/subscriber
|
||||||
uint8_t min_deltas_len;
|
uint8_t min_deltas_len;
|
||||||
uint8_t min_deltas[14]; // LPP encoded
|
uint8_t min_deltas[14]; // LPP encoded
|
||||||
|
|||||||
Reference in New Issue
Block a user