Пример использования кастомного режима работы ноды - хапи нода. Примерно что то похожее на пассивную ноду, но сохранены все подтверждения отправки доставки, работа с с гейтом, перестроение маршрутов через репитеры. Прошу потестируйте, вродебы завалить даже эту простую версию низя. Скетч под мой датчик bme280(распостраняется бесплатно, платы, корпус, код) -
Код: Выделить всё
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
//#define MY_DEBUG
#define MY_RADIO_NRF5_ESB
#define MY_DISABLED_SERIAL
int16_t mtwr;
#define MY_TRANSPORT_WAIT_READY_MS (mtwr)
#include <MySensors.h>
typedef enum {
I_SIGNAL_REPORT_QUALITY = 35, //!< Device signal quality
} custom_mysensors_internal_t;
bool flag_fcount;
bool flag_no_present;
bool flag_nogateway_mode;
bool flag_find_parent_process;
bool sleep_flag;
bool last_sent_value;
bool flag_update_transport_param;
bool Ack_FP;
bool Ack_TL;
bool PRESENT_ACK;
bool SKETCH_VERSION_ACK;
bool SKETCH_NAME_ACK;
bool flag_sendRoute_parent;
bool metric = true;
byte err_delivery_beat;
byte problem_mode_count;
int16_t myid;
int16_t mypar;
int16_t old_mypar = -1;
int16_t master_id;
int16_t RSSIQuality;
uint16_t currentBatteryPercent;
uint16_t lastBatteryPercent = 1000;
uint16_t battery_vcc_min = 2150;
uint16_t battery_vcc_max = 2950;
uint16_t batteryVoltage;
uint16_t battery_alert_level = 25;
uint32_t default_sleep_time = 60000;
uint32_t SLEEP_TIME;
uint32_t newmillisforbatt;
uint32_t battsendinterval = 3600000;
float tempThreshold = 0.5;
float humThreshold = 5;
float presThreshold = 1;
float pres_mmThreshold = 1;
float temperature;
float pressure;
float pressure_mm;
float humidity;
float lastTemperature = -1;
float lastHumidity = -1;
float lastPressure = -1;
float lastPressure_mm = -1;
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme;
#define TEMP_CHILD_ID 0
#define HUM_CHILD_ID 1
#define BARO_CHILD_ID 2
#define CHILD_ID_VOLT 254
MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE);
MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP);
MyMessage humidityMsg(HUM_CHILD_ID, V_HUM);
MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE);
void preHwInit() {
pinMode(21, INPUT);
pinMode(25, OUTPUT);
digitalWrite(25, HIGH);
pinMode(26, OUTPUT);
digitalWrite(26, HIGH);
pinMode(27, OUTPUT);
digitalWrite(27, HIGH);
}
void before() {
NRF_POWER->DCDCEN = 1;
disableNfc();
turnOffAdc();
pinMode(BLUE_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
digitalWrite(BLUE_LED, HIGH);
digitalWrite(RED_LED, HIGH);
happy_init();
digitalWrite(27, LOW);
}
void setup()
{
digitalWrite(27, HIGH);
config_Happy_node();
bme_initAsleep();
}
void presentation() {
if (!sendSketchInfo("EFEKTA BME280 Sensor", "1.2")) {
_transportSM.failedUplinkTransmissions = 0;
sleep(2000);
if (!sendSketchInfo("EFEKTA BME280 Sensor", "1.2")) {
_transportSM.failedUplinkTransmissions = 0;
//...
}
}
present(CHILD_ID_VOLT, S_MULTIMETER, "Battery", 1);
wait(3000, C_PRESENTATION, S_MULTIMETER);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
if (PRESENT_ACK == 0) {
_transportSM.failedUplinkTransmissions = 0;
sleep(2000);
present(CHILD_ID_VOLT, S_MULTIMETER, "Battery", 1);
wait(3000, C_PRESENTATION, S_MULTIMETER);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
_transportSM.failedUplinkTransmissions = 0;
} else {
PRESENT_ACK = 0;
}
present(TEMP_CHILD_ID, S_TEMP, "TEMPERATURE [C or F]", 1);
wait(3000, C_PRESENTATION, S_TEMP);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
if (PRESENT_ACK == 0) {
_transportSM.failedUplinkTransmissions = 0;
sleep(2000);
present(TEMP_CHILD_ID, S_TEMP, "TEMPERATURE [C or F]", 1);
wait(3000, C_PRESENTATION, S_TEMP);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
_transportSM.failedUplinkTransmissions = 0;
} else {
PRESENT_ACK = 0;
}
present(HUM_CHILD_ID, S_HUM, "HUMIDITY [%]", 1);
wait(3000, C_PRESENTATION, S_HUM);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
if (PRESENT_ACK == 0) {
_transportSM.failedUplinkTransmissions = 0;
sleep(2000);
present(HUM_CHILD_ID, S_HUM, "HUMIDITY [%]", 1);
wait(3000, C_PRESENTATION, S_HUM);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
_transportSM.failedUplinkTransmissions = 0;
} else {
PRESENT_ACK = 0;
}
present(BARO_CHILD_ID, S_BARO, "PRESSURE [hPa or mmHg]", 1);
wait(3000, C_PRESENTATION, S_BARO);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
if (PRESENT_ACK == 0) {
_transportSM.failedUplinkTransmissions = 0;
sleep(2000);
present(BARO_CHILD_ID, S_BARO, "PRESSURE [hPa or mmHg]", 1);
wait(3000, C_PRESENTATION, S_BARO);
CORE_DEBUG(PSTR("MyS: TEST WAIT AFTER PRESENT SENSOR\n"));
_transportSM.failedUplinkTransmissions = 0;
} else {
PRESENT_ACK = 0;
}
}
void loop() {
if (flag_update_transport_param == 1) {
update_Happy_transport();
}
if (flag_sendRoute_parent == 1) {
present_only_parent();
}
if (isTransportReady() == true) {
if (flag_nogateway_mode == 0) {
if (flag_find_parent_process == 1) {
find_parent_process();
}
wait(10);
bme.takeForcedMeasurement();
wait(100);
sendData();
if (millis() - newmillisforbatt >= battsendinterval) {
sleep_flag = 1;
sendBatteryStatus();
}
} else {
check_parent();
}
}
if (_transportSM.failureCounter > 0)
{
_transportConfig.parentNodeId = loadState(101);
_transportConfig.nodeId = myid;
_transportConfig.distanceGW = loadState(103);
mypar = _transportConfig.parentNodeId;
sleep_flag = 0;
flag_fcount = 1;
err_delivery_beat = 4;
happy_node_mode();
gateway_fail();
}
if (sleep_flag == 0) {
CORE_DEBUG(PSTR("ERROR DELIVERY COUNTER: %d\n"), err_delivery_beat);
sleep(SLEEP_TIME);
sleep_flag = 1;
}
}
void blinky(uint8_t pulses, uint8_t repit, uint8_t ledColor) {
for (int x = 0; x < repit; x++) {
if (x > 0) {
sleep(500);
}
for (int i = 0; i < pulses; i++) {
if (i > 0) {
sleep(100);
}
digitalWrite(ledColor, LOW);
wait(20);
digitalWrite(ledColor, HIGH);
}
}
}
void sendBatteryStatus() {
wait(20);
batteryVoltage = hwCPUVoltage();
wait(2);
if (batteryVoltage > battery_vcc_max) {
currentBatteryPercent = 100;
}
else if (batteryVoltage < battery_vcc_min) {
currentBatteryPercent = 0;
}
else {
if (lastBatteryPercent == 1000) {
currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min) + 5;
} else {
currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min) - 5;
}
}
//if (currentBatteryPercent != lastBatteryPercent) {
//if (currentBatteryPercent < lastBatteryPercent) {
lastBatteryPercent = currentBatteryPercent;
if (_transportConfig.parentNodeId == 0) {
//if (send(voltMsg.setDestination(master_id).set(batteryVoltage))) {
if (sendBatteryLevel(currentBatteryPercent)) {
//sleep_flag = 0;
err_delivery_beat = 0;
if (flag_nogateway_mode == 1) {
flag_nogateway_mode = 0;
CORE_DEBUG(PSTR("MyS: NORMAL GATEWAY MODE\n"));
err_delivery_beat = 0;
}
} else {
_transportSM.failedUplinkTransmissions = 0;
if (err_delivery_beat < 4) {
err_delivery_beat++;
}
if (err_delivery_beat == 3) {
if (flag_nogateway_mode == 0) {
gateway_fail();
CORE_DEBUG(PSTR("MyS: LOST GATEWAY MODE\n"));
}
}
}
//wait(200);
}
if (_transportConfig.parentNodeId > 0) {
//send(voltMsg.setDestination(master_id).set(batteryVoltage), 1);
//wait(3000, C_SET, V_VOLTAGE);
sendBatteryLevel(currentBatteryPercent, 1);
wait(3000, C_INTERNAL, I_BATTERY_LEVEL);
if (Ack_TL == 1) {
Ack_TL = 0;
err_delivery_beat = 0;
//sleep_flag = 0;
if (flag_nogateway_mode == 1) {
flag_nogateway_mode = 0;
CORE_DEBUG(PSTR("MyS: NORMAL GATEWAY MODE\n"));
err_delivery_beat = 0;
}
} else {
_transportSM.failedUplinkTransmissions = 0;
if (err_delivery_beat < 4) {
err_delivery_beat++;
}
if (err_delivery_beat == 3) {
if (flag_nogateway_mode == 0) {
gateway_fail();
CORE_DEBUG(PSTR("MyS: LOST GATEWAY MODE\n"));
}
}
}
//wait(200);
}
if (lastBatteryPercent < battery_alert_level) {
blinky(3, 1, RED_LED);
}
else {
blinky((last_sent_value == true ? 2 : 1), 1, BLUE_LED);
}
sleep(1000);
RSSIQuality = calculationRssiRxQuality();
sendSignalStrength(RSSIQuality, 1);
wait(3000, C_INTERNAL, I_SIGNAL_REPORT_QUALITY);
CORE_DEBUG(PSTR("MyS: TEST WAIT\n"));
// }
//} else {
// sleep_flag = 0;
// }
sleep_flag = 0;
newmillisforbatt = millis();
}
void disableNfc() {
NRF_NFCT->TASKS_DISABLE = 1;
NRF_NVMC->CONFIG = 1;
NRF_UICR->NFCPINS = 0;
NRF_NVMC->CONFIG = 0;
}
void turnOffAdc() {
if (NRF_SAADC->ENABLE) {
NRF_SAADC->TASKS_STOP = 1;
while (NRF_SAADC->EVENTS_STOPPED) {}
NRF_SAADC->ENABLE = 0;
while (NRF_SAADC->ENABLE) {}
}
}
/*
void i2c_off()
{
NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
*(volatile uint32_t *)0x40004FFC = 0;
*(volatile uint32_t *)0x40004FFC;
*(volatile uint32_t *)0x40004FFC = 1;
wait(100);
}
*/
void happy_init() {
//hwWriteConfig(EEPROM_NODE_ID_ADDRESS, 255); // ******************** checking the node config reset *************************
if (hwReadConfig(EEPROM_NODE_ID_ADDRESS) == 0) {
hwWriteConfig(EEPROM_NODE_ID_ADDRESS, 255);
}
if (loadState(100) == 0) {
saveState(100, 255);
}
CORE_DEBUG(PSTR("EEPROM NODE ID: %d\n"), hwReadConfig(EEPROM_NODE_ID_ADDRESS));
CORE_DEBUG(PSTR("USER MEMORY SECTOR NODE ID: %d\n"), loadState(100));
if (hwReadConfig(EEPROM_NODE_ID_ADDRESS) == 255) {
mtwr = 0;
} else {
mtwr = 10000;
no_present();
}
CORE_DEBUG(PSTR("MY_TRANSPORT_WAIT_MS: %d\n"), mtwr);
}
void no_present() {
_coreConfig.presentationSent = true;
_coreConfig.nodeRegistered = true;
}
void happy_node_mode() {
_transportSM.findingParentNode = false;
_transportSM.transportActive = true;
_transportSM.uplinkOk = true;
_transportSM.pingActive = false;
transportSwitchSM(stReady);
_transportSM.failureCounter = 0;
}
void gateway_fail() {
flag_nogateway_mode = 1;
flag_update_transport_param = 0;
SLEEP_TIME = default_sleep_time / 2;
}
void sendData() {
temperature = bme.readTemperature();
wait(20);
humidity = bme.readHumidity();
wait(20);
pressure = bme.readPressure() / 100.0F;
if (!metric) {
temperature = temperature * 9.0 / 5.0 + 32.0;
} else {
pressure = pressure * 0.75006375541921;
}
CORE_DEBUG(PSTR("MY_TEMPERATURE: %d\n"), (int)temperature);
CORE_DEBUG(PSTR("MY_HUMIDITY: %d\n"), (int)humidity);
CORE_DEBUG(PSTR("MY_PRESSURE: %d\n"), (int)pressure);
if (_transportConfig.parentNodeId == 0) {
if (abs(temperature - lastTemperature) >= tempThreshold) {
if (send(temperatureMsg.setDestination(master_id).set(temperature, 1))) {
err_delivery_beat = 0;
if (flag_nogateway_mode == 1) {
flag_nogateway_mode = 0;
CORE_DEBUG(PSTR("MyS: NORMAL GATEWAY MODE\n"));
err_delivery_beat = 0;
}
} else {
_transportSM.failedUplinkTransmissions = 0;
if (err_delivery_beat < 4) {
err_delivery_beat++;
}
if (err_delivery_beat == 3) {
if (flag_nogateway_mode == 0) {
gateway_fail();
CORE_DEBUG(PSTR("MyS: LOST GATEWAY MODE\n"));
}
}
}
lastTemperature = temperature;
sleep(1000);
}
if (abs(humidity - lastHumidity) >= humThreshold) {
if (send(humidityMsg.setDestination(master_id).set(humidity, 0))) {
err_delivery_beat = 0;
if (flag_nogateway_mode == 1) {
flag_nogateway_mode = 0;
CORE_DEBUG(PSTR("MyS: NORMAL GATEWAY MODE\n"));
err_delivery_beat = 0;
}
} else {
_transportSM.failedUplinkTransmissions = 0;
if (err_delivery_beat < 4) {
err_delivery_beat++;
}
if (err_delivery_beat == 3) {
if (flag_nogateway_mode == 0) {
gateway_fail();
CORE_DEBUG(PSTR("MyS: LOST GATEWAY MODE\n"));
}
}
}
lastHumidity = humidity;
sleep(1000);
}
if (abs(pressure - lastPressure) >= presThreshold) {
if (send(pressureMsg.setDestination(master_id).set(pressure, 0))) {
err_delivery_beat = 0;
if (flag_nogateway_mode == 1) {
flag_nogateway_mode = 0;
CORE_DEBUG(PSTR("MyS: NORMAL GATEWAY MODE\n"));
err_delivery_beat = 0;
}
} else {
_transportSM.failedUplinkTransmissions = 0;
if (err_delivery_beat < 4) {
err_delivery_beat++;
}
if (err_delivery_beat == 3) {
if (flag_nogateway_mode == 0) {
gateway_fail();
CORE_DEBUG(PSTR("MyS: LOST GATEWAY MODE\n"));
}
}
}
lastPressure = pressure;
sleep(1000);
}
}
sleep_flag = 0;
}
void update_Happy_transport() {
CORE_DEBUG(PSTR("MyS: UPDATE TRANSPORT CONFIGURATION\n"));
mypar = _transportConfig.parentNodeId;
master_id = 0; // *************************** master slave mode is not initialized in this example, ..stub *******************************
if (mypar != loadState(101))
{
saveState(101, mypar);
}
if (_transportConfig.distanceGW != loadState(102))
{
saveState(102, _transportConfig.distanceGW);
}
present_only_parent();
wait(1000);
sleep_flag = 0;
flag_update_transport_param = 0;
}
void config_Happy_node() {
if (mtwr == 0) {
myid = getNodeId();
saveState(100, myid);
mypar = _transportConfig.parentNodeId;
old_mypar = mypar;
master_id = 0; // *************************** master slave mode is not initialized in this example, ..stub *******************************
saveState(101, mypar);
saveState(102, _transportConfig.distanceGW);
//first_send_param ();
SLEEP_TIME = default_sleep_time;
sendBatteryStatus();
}
if (mtwr != 0) {
myid = getNodeId();
if (myid != loadState(100)) {
saveState(100, myid);
}
if (isTransportReady() == true) {
mypar = _transportConfig.parentNodeId;
master_id = 0; // *************************** master slave mode is not initialized in this example, ..stub *******************************
if (mypar != loadState(101)) {
saveState(101, mypar);
}
if (_transportConfig.distanceGW != loadState(102)) {
saveState(102, _transportConfig.distanceGW);
}
//first_send_param ();
SLEEP_TIME = default_sleep_time;
present_only_parent();
sendBatteryStatus();
}
if (isTransportReady() == false)
{
no_present();
flag_fcount = 1;
err_delivery_beat = 4;
_transportConfig.nodeId = myid;
_transportConfig.parentNodeId = loadState(101);
_transportConfig.distanceGW = loadState(102);
mypar = _transportConfig.parentNodeId;
happy_node_mode();
gateway_fail();
}
}
//wdt_enable(WDTO_4S);
//CORE_DEBUG(PSTR("MyS: WDT ENABLE\n"));
}
void present_only_parent() {
if (old_mypar != mypar) {
CORE_DEBUG(PSTR("MyS: SEND LITTLE PRESENT:) WITH PARENT ID\n"));
if (_sendRoute(build(_msgTmp, 0, NODE_SENSOR_ID, 3, 6).set(mypar))) {
//wait(3000, 3, 6);
flag_sendRoute_parent = 0;
old_mypar = mypar;
} else {
flag_sendRoute_parent = 1;
}
}
}
void check_parent() {
_transportSM.findingParentNode = true;
CORE_DEBUG(PSTR("MyS: SEND FIND PARENT REQUEST, WAIT RESPONSE\n"));
_sendRoute(build(_msg, 255, NODE_SENSOR_ID, 3, 7).set(""));
wait(3000, 3, 8);
if (_msg.sensor == 255) {
if (mGetCommand(_msg) == 3) {
if (_msg.type == 8) {
Ack_FP = 1;
CORE_DEBUG(PSTR("MyS: PARENT RESPONSE FOUND\n"));
}
}
}
if (Ack_FP == 1) {
CORE_DEBUG(PSTR("MyS: FIND PARENT PROCESS\n"));
Ack_FP = 0;
transportSwitchSM(stParent);
flag_nogateway_mode = 0;
flag_find_parent_process = 1;
SLEEP_TIME = default_sleep_time;
problem_mode_count = 0;
} else {
_transportSM.findingParentNode = false;
CORE_DEBUG(PSTR("MyS: PARENT RESPONSE NOT FOUND\n"));
_transportSM.failedUplinkTransmissions = 0;
sleep_flag = 0;
if (problem_mode_count < 24) {
CORE_DEBUG(PSTR("PROBLEM MODE COUNTER: %d\n"), problem_mode_count);
problem_mode_count++;
SLEEP_TIME = SLEEP_TIME / 100 * 120;
} else if (problem_mode_count == 24) {
SLEEP_TIME = default_sleep_time * 30;
CORE_DEBUG(PSTR("PROBLEM MODE COUNTER: %d\n"), problem_mode_count);
}
}
}
void find_parent_process() {
flag_update_transport_param = 1;
flag_find_parent_process = 0;
CORE_DEBUG(PSTR("MyS: STANDART TRANSPORT MODE IS RESTORED\n"));
err_delivery_beat = 0;
}
void receive(const MyMessage & message) {
if (message.type == V_VOLTAGE) {
if (message.sensor == CHILD_ID_VOLT) {
if (mGetCommand(message) == 1) {
if (message.isAck()) {
Ack_TL = 1;
} else {
}
}
if (mGetCommand(message) == 2) {
}
}
}
if (mGetCommand(message) == 0) {
PRESENT_ACK = 1;
CORE_DEBUG(PSTR("MyS: !!!ACK OF THE PRESENTATION IN THE FUNCTION RECEIVE RECEIVED!!!\n"));
}
}
void bme_initAsleep() {
if (! bme.begin(&Wire)) {
while (1);
}
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF );
wait(1000);
}
//****************************** very experimental *******************************
bool sendSignalStrength(const int16_t level, const bool ack)
{
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SIGNAL_REPORT_QUALITY,
ack).set(level));
}
int16_t calculationRssiRxQuality() {
int16_t nRFRSSI_temp = transportGetReceivingRSSI();
int16_t nRFRSSI = map(nRFRSSI_temp, -85, -40, 0, 100);
if (nRFRSSI < 0) {
nRFRSSI = 0;
}
if (nRFRSSI > 100) {
nRFRSSI = 100;
}
return nRFRSSI;
}