Hi all!
I have a problem, for which i couldn't find a solution. I'm using a Mega board, with W5510 Ethernet Module which is configured to use DHCP and MQTT.
Board is pure light relay controller with BME280 sensors function.
Now everything works just great when i have Ethernet connected.
But i wanted my gateway to work more or less independent from my network. So when i disconnect Ethernet with DHCP option enabled, i got this:
0 MCO:BGN:INIT GW,CP=R-NGA---,FQ=16,REL=255,VER=2.3.2
60682 !GWT:TPC:DHCP FAIL
60684 MCO:BGN:STP
Hello MySensors-Relay1!
60686 MCO:REG:NOT NEEDED
60690 MCO:BGN:INIT OK,TSP=NA
120810 !GWT:TPC:DHCP FAIL
Periodic send of Light state...
End of periodic send of Light state...
180931 !GWT:TPC:DHCP FAIL
Periodic send of Light state...
End of periodic send of Light state...
241052 !GWT:TPC:DHCP FAIL
Periodic send of Light state...
End of periodic send of Light state..
Which is great, however it looks like my script is doing something in background, and main loop() in executing very rarely, so it doesnt react on button input.
Please have look at my code:
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - Henrik Ekblad
* Version 1.1 - AnonymousZebra
*
* DESCRIPTION
* This is an example of using the Bosch BME280 module, which can measure temperature, humidity and airpressure,
* and do so really accurately, while using very little power. A 3.3v and a 5v version is available, make sure to check which one you have.
* It communicates over the I2C protocol.
*
* This script uses the BME280 library by Embedded Adventures. Download it, and place it in your Arduino library folder.
* https://github.com/embeddedadventures/BME280
*
* Connect your sensor's powerlines, and connect your sensor to the SDA and SCL pins of your board.
* On Arduino Nano SDA is pin A4, and SCL is pin A5.
* On the Ardunio Mega and Due the SDA in pin 20, and the SCL is pin 21.
* On the Arduino Leonardo and Pro Micro 2 the SDA in pin 2, and the SCL is pin 3.
*
* This script has been written in such a way that it can at the same time function as a repeater-node.
* It can also easily be used on battery power. Booth features can be turned on in the code below.
*
* Finally, you can decide if you want the forecast feature to be turned on. This is a cool feature,
* but there is a catch: it also means that you are locked into taking a measurement exactly once a
* minute, to build up prediction data for the algorithm.
*
* The reason so many variables have BME280 at the beginning, is so that it is easier to combine multiple sensors on one Arduino.
*
*
* The BME280 datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/4/1/9/BST-BME280_DS001-10.pdf
*
*/
#undef MY_TRANSPORT_SANITY_CHECK
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
// if you uncomment this, you can get test and debug updates about everything the sensor is doing by using the serial monitor tool.
#define MY_DEBUG
//#define MY_DEBUG_OTA
//#define MY_GATEWAY_SERIAL
#define MY_GATEWAY_W5100
#define MY_MAC_ADDRESS 0x00, 0x08, 0xDC, 0xAA, 0xBB, 0x01
#define MY_HOSTNAME "MySensors-Relay1"
#define SKETCH_VERSION "1.3"
//#define USE_STATIC_IP // Uncomment, if you don't want to use DHCP
#ifdef USE_STATIC_IP
#define MY_IP_ADDRESS 192,168,8,35 // Static IP Address
#define MY_IP_SUBNET_ADDRESS 255,255,255,0 // IP Netmask
#define MY_IP_GATEWAY_ADDRESS 192,168,8,1 // Internet (not MQTT) gateway address
#endif
#define MY_PORT 5003
#define MY_OTA_FIRMWARE_FEATURE
#define MY_GATEWAY_MQTT_CLIENT
// Set this node's subscribe and publish topic prefix
#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mysensors1-out"
#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mysensors1-in"
// Set MQTT client id
#define MY_MQTT_CLIENT_ID "mysensors-relay1"
// MQTT broker ip address or url. Define one or the other.
//#define MY_CONTROLLER_URL_ADDRESS "m20.cloudmqtt.com"
#define MY_CONTROLLER_IP_ADDRESS 192, 168, 8, 31
//
//// The MQTT broker port to to open
#define MY_PORT 1883
#define MY_MQTT_USER "mqtt"
#define MY_MQTT_PASSWORD "666mqtt"
#define DEBOUNCE_INTERVAL 25 // Debounce interval in ms
#define COMPARE_TEMP 0 // Send temperature only if it changed? 1 = Yes 0 = No. Can save battery.
#define COMPARE_HUM 0 // Send humidity only if changed? 1 = Yes 0 = No. Can save battery.
#define COMPARE_BARO 0 // Send barometric pressure only if changed? 1 = Yes 0 = No. Can save battery.
#define COMPARE_DEW_POINT 0 // Send dew point only if changed? 1 = Yes 0 = No. Can save battery.
#define TEMPERATURE_THRESHOLD 0.1 // Threshold when new temperature should be send to controller. Doesn't matter, if COMPARE_TEMP is set to 0
#define HUMIDITY_THRESHOLD 0.1 // Threshold when new humidity should be send to controller. Doesn't matter, if COMPARE_HUM is set to 0
#define BAROMETRIC_THRESHOLD 0.1 // Threshold when new pressure should be send to controller. Doesn't matter, if COMPARE_BARO is set to 0
#define DEW_POINT_THRESHOLD 0.1 // Threshold when new dew point should be send to controller. Doesn't matter, if COMPARE_DEW_POINT is set to 0
#define PERIODIC_LIGHT_SEND 1 // Send light states periodically? 1 = Yes, 0 = No, only when switch change.
#define PERIODIC_LIGHT_INTERVAL 10000 // Interval between Light sends, button press is always send immediately
#define BME_MEASUREMENTS_INTERVAL 60000 // Interval between BME280 reads, in ms
#define BME_ALTITUDE 220 // Change this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value, or use an online map.
#define MY_W5100_SPI_EN 10
// LIBRARIES
#include <SPI.h> // A communication backbone, the Serial Peripheral Interface.
#include <Ethernet.h> // Ethernet library
#include <MySensors.h> // The MySensors library. Hurray!
#include <Wire.h> // Enables the Wire communication protocol.
#include <BME280_MOD-1022.h> // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code, written originally by Embedded Adventures. https://github.com/embeddedadventures/BME280
#include <Bounce2.h>
// Ids of locally attached sensors. If you want to add some sensor besides to relays, add its name before SENSOR_LIGHT_START
typedef enum {
SENSOR_TEMPERATURE_ID = 0,
SENSOR_HUMIDITY_ID,
SENSOR_BARO_ID,
SENSOR_DEWPOINT_ID,
SENSOR_LIGHT_START,
SENSOR_MAX_ID
} sensorIds;
typedef struct {
uint8_t buttonPin; // GPIO Pin ID for input button
uint8_t relayPin; // GPIO Pin ID for output relay
bool inputLowActive; // True, if buttonPin should react on GND, false if on 5V
bool outputLowActive; // True, if ON state for relay will be GND, false if 5V
uint8_t currentState;
Bounce* debouncer; // Leave it, don't care, filled at initialization
MyMessage* message; // Leave it, don't care, filled at initialization
} tLightSwitch;
// RELAYS CONFIGURATION
static tLightSwitch m_lights[] = {
{
.buttonPin = A0,
.relayPin = 43,
}
};
const float ALTITUDE = BME_ALTITUDE;
unsigned long BME280measurementInterval = BME_MEASUREMENTS_INTERVAL;
const float tempThreshold = TEMPERATURE_THRESHOLD; // How big a temperature difference has to minimally be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
const float humThreshold = HUMIDITY_THRESHOLD; // How big a humidity difference has to minimally be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
const float presThreshold = BAROMETRIC_THRESHOLD; // How big a barometric difference has to minimally be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
const float dewPointThreshold = DEW_POINT_THRESHOLD; // How big a dew point difference has to minimally be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
// VARIABLES YOU PROBABLY SHOULDN'T CHANGE
float lastTemperature = -1; // Stores the previous measurement, so it can be compared with a new measurement.
float lastHumidity = -1; // Stores the previous measurement, so it can be compared with a new measurement.
float lastPressure = -1; // Stores the previous measurement, so it can be compared with a new measurement.
float lastDewPoint = -1;
unsigned long BME280measurementSleepTime = 0; // variable to store the calculated Sleep time if the node is battery powered.
#define CONVERSION_FACTOR (1.0/10.0) // used by forecast algorithm to convert from Pa to kPa, by dividing hPa by 10.
const uint8_t m_lights_size = sizeof(m_lights)/sizeof(m_lights[0]);
char uartBuffer[100];
unsigned long m_lights_send_interval = PERIODIC_LIGHT_INTERVAL;
#define RELAY_ON 0x80
#define RELAY_OFF 0x02
// Messages for sensors not related to light
MyMessage temperatureMsg(SENSOR_TEMPERATURE_ID, V_TEMP);
MyMessage humidityMsg(SENSOR_HUMIDITY_ID, V_HUM);
MyMessage pressureMsg(SENSOR_BARO_ID, V_PRESSURE);
MyMessage dewPointMsg(SENSOR_DEWPOINT_ID, V_TEMP);
void printUart(const char *format, ...) {
va_list args;
va_start(args, format);
vsprintf(uartBuffer, format, args);
Serial.print(uartBuffer);
Serial.print("\n");
va_end(args);
}
void switchRelay(uint8_t switchNo) {
tLightSwitch* light = &m_lights[switchNo];
uint8_t relayValue = light->currentState == RELAY_ON ? 1 : 0;
if(light->outputLowActive) {
relayValue = light->currentState == RELAY_ON ? 0 : 1;
}
printUart("Switch %u Pin %u %s, setting to %d\n", switchNo, light->relayPin, light->outputLowActive ? "LowActive" : "HighActive", light->currentState == RELAY_ON ? 1 : 0);
digitalWrite(light->relayPin, relayValue);
}
void configurePins() {
for(size_t i = 0; i < m_lights_size; ++i ) {
tLightSwitch* light = &m_lights[i];
pinMode(light->relayPin, OUTPUT);
pinMode(light->buttonPin, light->inputLowActive ? INPUT_PULLUP : INPUT);
light->currentState = RELAY_OFF;
light->message = new MyMessage(SENSOR_LIGHT_START + i, V_LIGHT);
light->debouncer = new Bounce();
light->debouncer->attach(light->buttonPin);
light->debouncer->interval(DEBOUNCE_INTERVAL);
}
}
void setup() {
Wire.begin(); // Wire.begin(sda, scl) // starts the wire communication protocol, used to chat with the BME280 sensor.
Serial.begin(115200); // for serial debugging over USB.
printUart("Hello %s!", MY_HOSTNAME);
configurePins();
}
void presentation() {
// Send the sketch version information to the gateway and Controller
sendSketchInfo(MY_HOSTNAME, SKETCH_VERSION);
// Tell the MySensors gateway what kind of sensors this node has, and what their ID's on the node are, as defined in the code above.
present(SENSOR_BARO_ID, S_BARO);
present(SENSOR_TEMPERATURE_ID, S_TEMP);
present(SENSOR_HUMIDITY_ID, S_HUM);
present(SENSOR_DEWPOINT_ID, S_TEMP);
for(size_t i = 0; i < m_lights_size; ++i ) {
present( SENSOR_LIGHT_START + i, S_LIGHT);
}
}
// Compute the dew point temperature, given temperature and humidity (temp in Celcius)
// Td = (f/100)^(1/8) * (112 + 0.9*T) + 0.1*T - 112
static float computeDewPointTemp(float temperature, float humidity_percentage)
{
return pow( humidity_percentage / 100.0, 0.125 ) * ( 112.0 + 0.9*temperature ) + 0.1 * temperature - 112.0;
}
void loop() {
// You should not change these variables:
static unsigned long previousBME280Millis = 0; // Used to remember the time that the BME280 sensor was asked for a measurement.
static unsigned long previousLightMillis = 0; // Used to remember the time that the BME280 sensor was asked for a measurement.
unsigned long currentMillis = millis(); // The time since the sensor started, counted in milliseconds. This script tries to avoid using the Sleep function, so that it could at the same time be a MySensors repeater.
static boolean BME280shouldAsk = true; // This is true when the time is right for a new measurement to be made.
static boolean BME280justAsked = false; // This indicates whether we have just asked the sensor module for a measurement, so the receiving part of the code (part 2) should be primed. This two-part construction helps to bridge the time where the BME280 module is busy, without blocking the entire node from doing anything else (like being a repeater, or working with other connected sensor modules).
// PART 1. If enough time has passed, a new measurement should be taken:
if (BME280shouldAsk == true && currentMillis - previousBME280Millis >= BME280measurementInterval) {
previousBME280Millis = currentMillis; // store the current time as the previous measurement start time.
BME280shouldAsk = false;
printUart("BME280 - Requesting new data from sensor module.");
BME280.readCompensationParams(); // Need to read the NVM compensation parameters.
// Normal mode for regular automatic samples
BME280.writeStandbyTime(tsb_0p5ms); // tsb = 0.5ms
BME280.writeFilterCoefficient(fc_16); // IIR Filter coefficient 16
BME280.writeOversamplingPressure(os16x); // pressure x16
BME280.writeOversamplingTemperature(os8x); // temperature x8
BME280.writeOversamplingHumidity(os8x); // humidity x8
BME280.writeMode(smNormal);
// As we exit part 1, in theory BME280.isMeasuring() should now be true.
BME280justAsked = true;
}
// Part 2. This will trigger if the sensor has just been asked for a measurement, and is also just done figuring out those measurements.
if(BME280justAsked == true && BME280.isMeasuring() == false) { //
BME280justAsked = false; // makes sure we don't do this part again in the next pass through the main loop.
printUart("BME280 - Sensor module has some new values ready:");
Serial.println("BME280 - Sensor module has some new values ready:");
// Read out the data - must do this before calling the getxxxxx routines
BME280.readMeasurements();
float temperature = BME280.getTemperatureMostAccurate(); // Must get the temperature first.
float humidity = BME280.getHumidityMostAccurate(); // Get the humidity.
float pressure_local = BME280.getPressureMostAccurate(); // Get pressure at current location
float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
float dewPoint = computeDewPointTemp(temperature, humidity);
// Useful for debugging
Serial.print("BME280 - Temperature = ");
Serial.print(temperature);
Serial.println(" Β°C");
Serial.print("BME280 - Humidity = ");
Serial.print(humidity);
Serial.println(" %");
Serial.print("BME280 - Pressure = ");
Serial.print(pressure);
Serial.println(" hPa");
Serial.print("BME280 - Dewpoint = ");
Serial.print(dewPoint);
Serial.println(" Β°C");
// Now, let's send the measurements to the gateway.
// Send temperature
if (COMPARE_TEMP == 1 && abs(temperature - lastTemperature) < tempThreshold) { // is the temperature difference bigger than the threshold?
Serial.print(temperature - lastTemperature);
Serial.print("- BME280 - Temperature difference too small, so not sending the new measurement to the gateway.\n");
} else {
Serial.print("BME280 - Sending the new temperature to the gateway.\n");
send(temperatureMsg.set(temperature, 1));
lastTemperature = temperature; // Save new temperatures to be able to compare in the next round.
}
// Send humidity
if (COMPARE_HUM == 1 && abs(humidity - lastHumidity) < humThreshold) { // is the humidity difference bigger than the threshold?
Serial.print(humidity - lastHumidity);
Serial.println("- BME280 - Humidity difference too small, so not sending the new measurement to the gateway.");
} else {
Serial.println("BME280 - Sending the new humidity to the gateway.");
send(humidityMsg.set(humidity, 1));
lastHumidity = humidity; // Save new humidity to be able to compare in the next round.
}
// Send pressure
if (COMPARE_BARO == 1 && abs(pressure - lastPressure) < presThreshold) { // is the pressure difference bigger than the threshold?
Serial.print(pressure - lastPressure);
Serial.println("- BME280 - Pressure difference too small, so not sending the new measurement to the gateway.");
} else {
Serial.println("BME280 - Sending the new pressure to the gateway.");
send(pressureMsg.set(pressure, 1));
lastPressure = pressure; // Save new pressure to be able to compare in the next round.
}
// Send Dew-Point
if (COMPARE_DEW_POINT == 1 && abs(dewPoint - lastDewPoint) < dewPointThreshold) { // is the pressure difference bigger than the threshold?
Serial.print(dewPoint - lastDewPoint);
Serial.println("- BME280 - DewPoint difference too small, so not sending the new measurement to the gateway.");
} else {
Serial.println("BME280 - Sending the new dew point to the gateway.");
send(dewPointMsg.set(dewPoint, 1));
lastDewPoint = dewPoint; // Save new pressure to be able to compare in the next round.
}
Serial.println("BME280 - Measurement complete. Going to wait until next measurement.");
BME280shouldAsk = true; // Ready for the new round.
}
for( size_t i = 0; i < m_lights_size; ++i) {
tLightSwitch* light = &m_lights[i];
if(light->debouncer->update()) {
if(light->debouncer->read() == HIGH) {
printUart("Button %d pressed...", i);
//light->currentState = !light->currentState;
light->currentState = light->currentState == RELAY_ON ? RELAY_OFF : RELAY_ON;
switchRelay(i);
send(light->message->set(light->currentState == RELAY_ON ? 0xFF : 0x00));
}
}
}
if( PERIODIC_LIGHT_SEND && currentMillis - previousLightMillis >= m_lights_send_interval ) {
printUart("Periodic send of Light state...");
for( size_t i = 0; i < m_lights_size; ++i) {
previousLightMillis = currentMillis;
tLightSwitch* light = &m_lights[i];
send(light->message->set(light->currentState == RELAY_ON ? 0xFF : 0x00));
}
printUart("End of periodic send of Light state...");
}
} // end of main loop.
void receive(const MyMessage &message) {
// We only expect one type of message from controller. But we better check anyway.
if (message.type == V_LIGHT) {
printUart("Received update of %d sensor, new value %u", message.sensor, message.getBool());
if(message.sensor >= SENSOR_LIGHT_START) {
uint8_t lightSwitchNo = message.sensor - SENSOR_LIGHT_START;
printUart("Updating light switch %u, new state: %u", lightSwitchNo, message.getBool());
tLightSwitch* light = &m_lights[lightSwitchNo];
light->currentState = message.getBool() ? RELAY_ON : RELAY_OFF;
switchRelay(lightSwitchNo);
}
}
}
My question is, it is a normal situation?
If not, could you please help me finding a problem in my script?
Thanks in advance!