GatewayESP32MQTT with local sensor crashes



  • Hi, all.

    I'm not a programmer and new to MySensors, so my problem may be something silly.

    My plan is to, eventually, get a network of, mostly, temperature nodes using some Rigado BMD-300 modules (nRF52832-based) with an ESP32 (Wemos Lolin32 / NRF24) running as a MQTT gateway.

    I'm starting with trying to get the gateway up and running, with a local BME280 sensor. I've used GatewayESP32MQTTClient as a starting point and added code from the MySensors BME280 sketch. The sketch was using a library which seems to not be available in PlatformIO, so I've modified it to use Adafruit_BME280 library (modified with code from Sparkfun to get isMeasuring).

    My modifications to the BME280 library look like this
    Adafruit_BME280.h

    bool isMeasuring(void);
    

    Adafruit_BME280.cpp

    bool Adafruit_BME280::isMeasuring(void)	{
      uint8_t stat = read8(0xF3);
      return(stat & (1<<3));	//If measuring bit (3) is set, return true
    }
    

    When the gateway code and the BME280 code are combined, the gateway runs fine until a minute has passed and it want to do a sampling from the local sensor. It then crashes and reboots when it wants to set the parameters for the BME280, with the message "Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled."

    The code which caused the crash is

        bme.setSampling(Adafruit_BME280::MODE_NORMAL,       //normal mode
                        Adafruit_BME280::SAMPLING_X8,       //temperature x8
                        Adafruit_BME280::SAMPLING_X16,      //pressure x16
                        Adafruit_BME280::SAMPLING_X8,       //humidity x8
                        Adafruit_BME280::FILTER_OFF,        //IIR Filter coefficient
                        Adafruit_BME280::STANDBY_MS_0_5);   //tsb = 0.5ms
    
    

    When I comment out the above section, it crashes when it reaches the next instance where it accesses the Adafruit_BME280-library, so it looks like it doesn't like this library. Anyone else used the same library with success?

    Anyone who have any ideas where I've goofed up, other than using the Adafruit_BME280-library?



  • It looks like that's the proper way to use the library - the couple of little snippets you added looked like they matched the library on github. But I would use the definition provided in the header:

    BME280_REGISTER_STATUS = 0XF3,
    

    Just to make your code easier to read.

    Maybe you need to provide the rest of your code to let us see that?

    How are you 'combining' the code for the gateway and the BME280 library? It sounds like the NRF52832 is running mysensors, so it should be running the BME280 code, but the ESP32 is running the gateway code. So I don't see how they could be combined? Really, we would need to see code for both boards, I think. I can't think of other things right now to help.



  • Thanks, ejlane.

    No, I have combined the code from the BME280 sensor example into the gateway code to have a local sensor on the gateway, which is supposed to be supported now. Btw, I'm using MySensors v2.3.2, not development branch. I have not started using any nodes so far, so just the ESP32 board is running.

    platformio.ini

    [env:lolin32]
    platform = espressif32
    board = lolin32
    framework = arduino
    monitor_speed = 115200
    lib_deps = 
    	mysensors/MySensors@^2.3.2
    	adafruit/Adafruit BME280 Library@^2.2.2
    
    

    main.cpp

    // Set Static Node ID
    #define MY_NODE_ID 12
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    
    // Enables and select radio type (if attached)
    #define MY_RADIO_RF24
    //#define MY_RADIO_RFM69
    //#define MY_RADIO_RFM95
    
    #define MY_GATEWAY_MQTT_CLIENT
    #define MY_GATEWAY_ESP32
    
    // Set this node's subscribe and publish topic prefix
    //#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
    //#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
    
    // Set MQTT client id
    //#define MY_MQTT_CLIENT_ID "mysensors-1"
    
    // Enable these if your MQTT broker requires usenrame/password
    //#define MY_MQTT_USER "username"
    //#define MY_MQTT_PASSWORD "password"
    
    // Set WIFI SSID and password
    //#define MY_WIFI_SSID "MySSID"
    //#define MY_WIFI_PASSWORD "MyVerySecretPassword"
    
    // Set the hostname for the WiFi Client. This is the hostname
    // passed to the DHCP server if not static.
    //#define MY_HOSTNAME "ESP32_MQTT_GW"
    
    // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
    //#define MY_IP_ADDRESS 192,168,178,87
    
    // If using static ip you can define Gateway and Subnet address as well
    //#define MY_IP_GATEWAY_ADDRESS 192,168,178,1
    //#define MY_IP_SUBNET_ADDRESS 255,255,255,0
    
    // MQTT broker ip address.
    //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 1, 5
    
    // The MQTT broker port to to open
    #define MY_PORT 1883
    
    #include <Arduino.h>
    #include <secrets.h>
    #include <MySensors.h>
    #include <SPI.h>                                  // A communication backbone, the Serial Peripheral Interface.
    #include <Wire.h>                                 // Enables the Wire communication protocol.
    #include <Adafruit_BME280.h>                    // alternative library you could try (DIY; no code for this is in here yet).
    
    // VARIABLES YOU CAN CHANGE
    const float ALTITUDE = 160;                        // Change this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value, or use an online map.
    unsigned long BME280measurementInterval = 60000;  // Sleep time between reads for the BME sensor (in ms). Keep this value at 60000 if you have enabled the forecast feature, as the forecast algorithm needs a sample every minute.
    #define COMPARE_TEMP 0                            // Send temperature only if it changed? 1 = Yes 0 = No. Can save battery.
    float tempThreshold = 0.1;                        // 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.
    #define COMPARE_HUM 0                             // Send humidity only if changed? 1 = Yes 0 = No. Can save battery.
    float humThreshold = 0.1;                         // 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.
    #define COMPARE_BARO 0                            // Send barometric pressure only if changed? 1 = Yes 0 = No. Can save battery.
    float presThreshold = 0.1;                        // 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.
                
    
    // VARIABLES YOU PROBABLY SHOULDN'T CHANGE
    #define TEMP_CHILD_ID 1        // for MySensors. Within this node each sensortype should have its own ID number.
    #define HUM_CHILD_ID 2        // for MySensors. Within this node each sensortype should have its own ID number.
    #define BARO_CHILD_ID 3       // for MySensors. Within this node each sensortype should have its own ID number.
    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.
    unsigned long BME280measurementSleepTime = 0;   // variable to store the calculated Sleep time if the node is battery powered.
    bool metric = true;       // Variable that stores if the sensor will output the temperature in Fahrenheit of Celsius. The gateway sends this preference to the node, so you dont need to change it here.
    bool receivedConfig = false;      // The MySensors gateway will tell the node if it should output in metric or not.
    
    // MYSENSORS COMMUNICATION VARIABLES
    MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP);
    MyMessage humidityMsg(HUM_CHILD_ID, V_HUM);
    MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE);
    #ifdef GENERATE_FORECAST
    MyMessage forecastMsg(BARO_CHILD_ID, V_FORECAST);
    #endif
    
    Adafruit_BME280 bme;         //I2C
    
    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.
      Serial.println("Hello world, I am a Gateway with sensor.");
    }
    
    
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Gateway_with_Sensor", "1.1");
    
      // 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(BARO_CHILD_ID, S_BARO);
      present(TEMP_CHILD_ID, S_TEMP);
      present(HUM_CHILD_ID, S_HUM);
    }
    
    
    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.
      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;
        Serial.println("");
        Serial.println("BME280 - Requesting new data from sensor module.");
    //    bme.readCoefficients();             // Read NVM compensation parameters
    //    BME280.readCompensationParams();    // Need to read the NVM compensation parameters.
    
        // Normal mode for regular automatic samples
        Serial.println("Just before setSampling");
        bme.setSampling(Adafruit_BME280::MODE_NORMAL,       //normal mode
                        Adafruit_BME280::SAMPLING_X8,       //temperature x8
                        Adafruit_BME280::SAMPLING_X16,      //pressure x16
                        Adafruit_BME280::SAMPLING_X8,       //humidity x8
                        Adafruit_BME280::FILTER_OFF,        //IIR Filter coefficient
                        Adafruit_BME280::STANDBY_MS_0_5);   //tsb = 0.5ms
    //    BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
    //    BME280.writeFilterCoefficient(fc_off);       // IIR Filter coefficient 16
    //    BME280.writeOversamplingPressure(os1x);    // pressure x16
    //    BME280.writeOversamplingTemperature(os1x);  // temperature x8
    //    BME280.writeOversamplingHumidity(os1x);     // humidity x8
    //    BME280.writeMode(smNormal);
    
        // As we exit part 1, in theory BME280.isMeasuring() should now be true.
        Serial.println("Just after setSampling");
        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) { // 
    Serial.println("Just before isMeasuring");
      if(BME280justAsked == true && bme.isMeasuring() == false) { // 
        Serial.println("After isMeasuring");
        BME280justAsked = false; // makes sure we don't do this part again in the next pass through the main loop.
        Serial.println("BME280 - Sensor module has some new values ready:");
          
        // Read out the data - must do this before calling the getxxxxx routines
    
        float temperature = bme.readTemperature();                    // Must get the temperature first.
        float humidity = bme.readHumidity();        // Get the humidity.
        float pressure_local = bme.readPressure();                    // Get pressure at current location
    //    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
    
        // 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.
        }
        Serial.println("BME280 - Measurement complete. Going to wait until next measurement.");
        BME280shouldAsk = true; // Ready for the new round.
      }
    }
    
    

    Some of the Serial.println are for debugging purposes to find where the code is crashing... 🙂

    Not sure if I should have a static node ID for the gateway. If so, it would probably be ID 1.
    The various usernames and passwords, etc. are included in the secrets.h-file, which I think should have been default with MySensors.


  • Mod

    @Stig isn’t is necessary to call bme.begin() before using the sensor?

    Their example does: https://github.com/adafruit/Adafruit_BME280_Library/blob/master/examples/advancedsettings/advancedsettings.ino#L41



  • Thanks, mfalkvidd! Whaddya know, that was the problem...

    Another thing I just thought of, is it correct to use send(temperatureMsg.set(temperature, 1)), etc., when the sensor is local, or is it treated by the gateway as any other remote sensor information coming in?
    Seems like it is not sending much useful date to the MQTT broker either. This is what is send every minute (according to the serial monitor)

    BME280 - Sensor module has some new values ready:
    BME280 - Sending the new temperature to the gateway.
    60093 GWT:TPS:TOPIC=mygateway1-out/0/1/1/0/0,MSG SENT
    BME280 - Sending the new humidity to the gateway.
    60106 GWT:TPS:TOPIC=mygateway1-out/0/2/1/0/1,MSG SENT
    BME280 - Sending the new pressure to the gateway.
    60116 GWT:TPS:TOPIC=mygateway1-out/0/3/1/0/4,MSG SENT
    BME280 - Measurement complete. Going to wait until next measurement.
    63579 GWT:TPC:IP=10.10.10.180
    63582 GWT:RMQ:CONNECTING...
    64290 GWT:RMQ:OK
    64291 GWT:TPS:TOPIC=mygateway1-out/0/255/0/0/18,MSG SENT
    64301 GWT:TPS:TOPIC=mygateway1-out/0/255/3/0/11,MSG SENT
    64308 GWT:TPS:TOPIC=mygateway1-out/0/255/3/0/12,MSG SENT
    64313 GWT:TPS:TOPIC=mygateway1-out/0/3/0/0/8,MSG SENT
    64319 GWT:TPS:TOPIC=mygateway1-out/0/1/0/0/6,MSG SENT
    64324 GWT:TPS:TOPIC=mygateway1-out/0/2/0/0/7,MSG SENT
    

    So far I only have the log from the MQTT broker (Mosquito) to look at and it looks like a lot of the messages aren't arriving at the broker. I may have to set up a MQTT client to look at the actual messages to get a better look at what is going out from the gateway.


  • Mod

    Nice work @Stig, thanks for reporting back.

    Yes, using send is correct. The log looks good to me. Were you expecting something different?



  • @Stig try mqtt-explorer to see what is happening on the mqtt network



  • @mfalkvidd,

    I would have expected more to see the actual message, not "MSG SENT", especially since they are debug messages (on the serial monitor)...

    @electrik, MQTT Explorer worked good to see the messages from the broker. Thanks for the suggestion.

    Now the "fun" part starts, trying to get the custom nRF52 boards working with PlatformIO instead of Arduino IDE... 🙂


  • Mod

    Thanks for explaining @Stig

    I guess it would be possible to use https://github.com/mysensors/MySensors/blob/253109d3ff00ec524c5d1e1dfcd8e197c96e54c2/core/MyMessage.cpp#L279 to get a string representation of the message and print it. Or would a hexadecimal representation make more sense? None of them would match the binary message posted to the mqtt topic though, unless your mqtt client does some conversion (to hexadecimal most likely).

    Edit: there is a 2 year old pr for adding binary support to mqtt explorer: https://github.com/thomasnordquist/MQTT-Explorer/pull/493
    If merged, mqtt explorer would support hex so maybe we should use hex as well?



  • @mfalkvidd,
    Personally, I think a string representation would make the most sense, as it is more human-readable than binary or hexadecimal, but if it was made selectable, developers could choose how they want to see it, best of both worlds... 🙂

    How far away is development from a new stable version? It's 3 years since last stable version.


  • Mod

    @Stig I wouldn't bet on anything soon.


Log in to reply
 

Suggested Topics

  • 1
  • 2
  • 5
  • 1
  • 1
  • 10

1
Online

11.4k
Users

11.1k
Topics

112.7k
Posts