Combining BinarySwitch with PressureSensor



  • I am having troubles combining these two sketches, for some reason whatever how I do it, pressure and temperature is always working, binary switch is not(actually window magnet)

    This is what I end up with... Anyone who can show me where it goes sour?

    TIA

    /**
     * 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.
     *
     *******************************
     *
     * DESCRIPTION
     *
     * Simple binary switch example 
     * Connect button or door/window reed switch between 
     * digitial I/O pin 3 (BUTTON_PIN below) and GND.
     * http://www.mysensors.org/build/binary
     */
    
    
    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    #include <Wire.h>
    #include <Adafruit_BMP085.h>
    
    #define CHILD_ID 3
    #define BUTTON_PIN  3  // Arduino Digital I/O pin for button/reed switch
    #define BARO_CHILD 0
    #define TEMP_CHILD 1
    
    const float ALTITUDE = 93; // <-- adapt this value to your own location's altitude.
    
    // Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute.
    const unsigned long SLEEP_TIME = 60000; 
    
    const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
    enum FORECAST
    {
    	STABLE = 0,			// "Stable Weather Pattern"
    	SUNNY = 1,			// "Slowly rising Good Weather", "Clear/Sunny "
    	CLOUDY = 2,			// "Slowly falling L-Pressure ", "Cloudy/Rain "
    	UNSTABLE = 3,		// "Quickly rising H-Press",     "Not Stable"
    	THUNDERSTORM = 4,	// "Quickly falling L-Press",    "Thunderstorm"
    	UNKNOWN = 5			// "Unknown (More Time needed)
    };
    
    Adafruit_BMP085 bmp = Adafruit_BMP085();      // Digital Pressure Sensor 
    
    MySensor gw;
    Bounce debouncer = Bounce(); 
    int oldValue=-1;
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(CHILD_ID,V_TRIPPED);
    
    float lastPressure = -1;
    float lastTemp = -1;
    int lastForecast = -1;
    
    const int LAST_SAMPLES_COUNT = 5;
    float lastPressureSamples[LAST_SAMPLES_COUNT];
    
    // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
    // get kPa/h be dividing hPa by 10 
    #define CONVERSION_FACTOR (1.0/10.0)
    
    int minuteCount = 0;
    bool firstRound = true;
    // average value is used in forecast algorithm.
    float pressureAvg;
    // average after 2 hours is used as reference value for the next iteration.
    float pressureAvg2;
    
    float dP_dt;
    boolean metric;
    MyMessage tempMsg(TEMP_CHILD, V_TEMP);
    MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
    MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
    
    void setup()  
    {  
      gw.begin();
    
     // Setup the button
      pinMode(BUTTON_PIN,INPUT);
      // Activate internal pull-up
      digitalWrite(BUTTON_PIN,HIGH);
      
      // After setting up the button, setup debouncer
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
      
      // Register binary input sensor to gw (they will be created as child devices)
      // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. 
      // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
      gw.present(CHILD_ID, S_DOOR);  
      
      
    	// Send the sketch version information to the gateway and Controller
    	gw.sendSketchInfo("Pressure Sensor", "1.1");
    
    	if (!bmp.begin()) 
    	{
    		Serial.println("Could not find a valid BMP085 sensor, check wiring!");
    		while (1) {}
    	}
    
    	// Register sensors to gw (they will be created as child devices)
    	gw.present(BARO_CHILD, S_BARO);
    	gw.present(TEMP_CHILD, S_TEMP);
    	metric = gw.getConfig().isMetric;
    }
    
    
    //  Check if digital input has changed and send in new value
    void loop() 
    {
      debouncer.update();
      // Get the update value
      int value = debouncer.read();
     
      if (value != oldValue) {
         // Send in the new value
         gw.send(msg.set(value==HIGH ? 1 : 0));
         oldValue = value;
      }
    	float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0;
    	float temperature = bmp.readTemperature();
    
    	if (!metric) 
    	{
    		// Convert to fahrenheit
    		temperature = temperature * 9.0 / 5.0 + 32.0;
    	}
    
    	int forecast = sample(pressure);
    
    	Serial.print("Temperature = ");
    	Serial.print(temperature);
    	Serial.println(metric ? " *C" : " *F");
    	Serial.print("Pressure = ");
    	Serial.print(pressure);
    	Serial.println(" hPa");
    	Serial.print("Forecast = ");
    	Serial.println(weather[forecast]);
    
    
    	if (temperature != lastTemp) 
    	{
    		gw.send(tempMsg.set(temperature, 1));
    		lastTemp = temperature;
    	}
    
    	if (pressure != lastPressure) 
    	{
    		gw.send(pressureMsg.set(pressure, 0));
    		lastPressure = pressure;
    	}
    
    	if (forecast != lastForecast)
    	{
    		gw.send(forecastMsg.set(weather[forecast]));
    		lastForecast = forecast;
    	}
    
    	gw.sleep(SLEEP_TIME);
      } 
    float getLastPressureSamplesAverage()
    {
    	float lastPressureSamplesAverage = 0;
    	for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
    	{
    		lastPressureSamplesAverage += lastPressureSamples[i];
    	}
    	lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
    
    	return lastPressureSamplesAverage;
    }
    
    
    
    // Algorithm found here
    // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
    // Pressure in hPa -->  forecast done by calculating kPa/h
    int sample(float pressure)
    {
    	// Calculate the average of the last n minutes.
    	int index = minuteCount % LAST_SAMPLES_COUNT;
    	lastPressureSamples[index] = pressure;
    
    	minuteCount++;
    	if (minuteCount > 185)
    	{
    		minuteCount = 6;
    	}
    
    	if (minuteCount == 5)
    	{
    		pressureAvg = getLastPressureSamplesAverage();
    	}
    	else if (minuteCount == 35)
    	{
    		float lastPressureAvg = getLastPressureSamplesAverage();
    		float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    		if (firstRound) // first time initial 3 hour
    		{
    			dP_dt = change * 2; // note this is for t = 0.5hour
    		}
    		else
    		{
    			dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
    		}
    	}
    	else if (minuteCount == 65)
    	{
    		float lastPressureAvg = getLastPressureSamplesAverage();
    		float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    		if (firstRound) //first time initial 3 hour
    		{
    			dP_dt = change; //note this is for t = 1 hour
    		}
    		else
    		{
    			dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
    		}
    	}
    	else if (minuteCount == 95)
    	{
    		float lastPressureAvg = getLastPressureSamplesAverage();
    		float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    		if (firstRound) // first time initial 3 hour
    		{
    			dP_dt = change / 1.5; // note this is for t = 1.5 hour
    		}
    		else
    		{
    			dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
    		}
    	}
    	else if (minuteCount == 125)
    	{
    		float lastPressureAvg = getLastPressureSamplesAverage();
    		pressureAvg2 = lastPressureAvg; // store for later use.
    		float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    		if (firstRound) // first time initial 3 hour
    		{
    			dP_dt = change / 2; // note this is for t = 2 hour
    		}
    		else
    		{
    			dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
    		}
    	}
    	else if (minuteCount == 155)
    	{
    		float lastPressureAvg = getLastPressureSamplesAverage();
    		float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    		if (firstRound) // first time initial 3 hour
    		{
    			dP_dt = change / 2.5; // note this is for t = 2.5 hour
    		}
    		else
    		{
    			dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
    		}
    	}
    	else if (minuteCount == 185)
    	{
    		float lastPressureAvg = getLastPressureSamplesAverage();
    		float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    		if (firstRound) // first time initial 3 hour
    		{
    			dP_dt = change / 3; // note this is for t = 3 hour
    		}
    		else
    		{
    			dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
    		}
    		pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
    		firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
    	}
    
    	int forecast = UNKNOWN;
    	if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
    	{
    		forecast = UNKNOWN;
    	}
    	else if (dP_dt < (-0.25))
    	{
    		forecast = THUNDERSTORM;
    	}
    	else if (dP_dt > 0.25)
    	{
    		forecast = UNSTABLE;
    	}
    	else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
    	{
    		forecast = CLOUDY;
    	}
    	else if ((dP_dt > 0.05) && (dP_dt < 0.25))
    	{
    		forecast = SUNNY;
    	}
    	else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
    	{
    		forecast = STABLE;
    	}
    	else
    	{
    		forecast = UNKNOWN;
    	}
    
    	// uncomment when debugging
    	//Serial.print(F("Forecast at minute "));
    	//Serial.print(minuteCount);
    	//Serial.print(F(" dP/dt = "));
    	//Serial.print(dP_dt);
    	//Serial.print(F("kPa/h --> "));
    	//Serial.println(weather[forecast]);
    
    	return forecast;
    }
    

  • Mod

    The sketch looks pretty good, except two things:

    • it is not correctly formatted (use CMD/Ctrl+T in the Arduino IDE). This will make the code much more readable, both for yourself and anyone reading your code on the forum.
    • The sensor goes to sleep, which will prevent it from detecting a change in the window magnet. The binary switch example) doesn't sleep, while the pressure example always sleeps for SLEEP_TIME milliseconds. Change your current sleep to
    gw.sleep(digitalPinToInterrupt(BUTTON_PIN), CHANGE, SLEEP_TIME);
    

    to wake up if the switch is changed.

    I think that's it. If it isn't, please post the serial debug from the node.

    This simple change will cause the sensor to send temp and pressure every time the switch is changed but I don't think that will be a problem.



  • Does this mean the temp and pressure data will only be sent every time the switch is changed? If this is the case and since this is not gonna be run from battery, is there a easy way to let pressure and temp be updated every 60 seconds, and let it check for the state of the switch reasonable often?

    According to Henrik Ekblad the forecast algorithm needs this info at that rate.

    TIA


  • Mod

    The node will wake up at SLEEP_TIME if the window switch doesn't change, so you'll get data at least as often as SLEEP_TIME.



  • I've change the line

    gw.sleep(SLEEP_TIME);
    

    to

    gw.sleep(digitalPinToInterrupt(BUTTON_PIN), CHANGE, SLEEP_TIME);
    

    This was what you meant? It doesn't seem to do more than wake up as you said every 60 seconds to transfer the status of all sensors - pressure, switch and temp.

    Did I misunderstand what you meant maybe? :)

    TIA


  • Mod

    Good thinking. Let's make sure we have the same goal :-)

    • The sensor should send temp/pressure data at least every 60 seconds
    • The sensor should also send switch information every time there is a change (window is opened or closed)

    correct?



  • @mfalkvidd Yes as far as I understand that should be it, unless the forecast algorithm is not for some reason depending on it updating exactly every 60 seconds?

    I am actually gonna be using the switch info to know the state of my garage door, making sure it's not by mistake left open when it shouldn't.


  • Mod

    Great. Then your code change should be enough. What does the serial debug log of the node say?



  • From what the serial monitor is telling me is that it is updating at least temp and pressure, I don't know where I see the actual switch? Domoticz only update temp and pressure every time the switch is triggered, it is not telling me the new state of the switch until at least 60sec from what it seems.

    send: 2-2-0-0 s=0,c=1,t=4,pt=7,l=5,sg=0,st=ok:1019
    Temperature = 25.40 *C
    Pressure = 1019.35 hPa
    Forecast = stable
    send: 2-2-0-0 s=0,c=1,t=4,pt=7,l=5,sg=0,st=ok:1019
    Temperature = 25.40 *C
    Pressure = 1019.32 hPa
    Forecast = stable
    send: 2-2-0-0 s=0,c=1,t=4,pt=7,l=5,sg=0,st=ok:1019
    Temperature = 25.40 *C
    Pressure = 1019.37 hPa
    Forecast = stable
    send: 2-2-0-0 s=0,c=1,t=4,pt=7,l=5,sg=0,st=ok:1019
    Temperature = 25.40 *C
    Pressure = 1019.38 hPa
    Forecast = stable
    send: 2-2-0-0 s=0,c=1,t=4,pt=7,l=5,sg=0,st=ok:1019


  • Mod

    Could you include output from startup as well? You should get at least one switch message when the node is reset.

    Next step is probably to add som Serial.println in various places to see what is happening.

    You have double-checked the wiring? The switch is connected to GND on one side and pin 3 on the other sie?



  • Yes it is clear that it is working partly because it will eventually update the state of the switch, but it will not do this as often as temp/pressure. Temp/pressure is updated every time switch is triggered, but still the state of the switch is not reported every time , only when 60+ seconds have passed.

    This is the startup.

    send: 2-2-0-0 s=255,c=3,t=15,pt=2,l=2,sg=0,st=ok:0
    send: 2-2-0-0 s=255,c=0,t=17,pt=0,l=5,sg=0,st=ok:1.5.4
    send: 2-2-0-0 s=255,c=3,t=6,pt=1,l=1,sg=0,st=ok:0
    read: 0-0-2 s=255,c=3,t=6,pt=0,l=1,sg=0:M
    sensor started, id=2, parent=0, distance=1
    send: 2-2-0-0 s=3,c=0,t=0,pt=0,l=0,sg=0,st=ok:
    send: 2-2-0-0 s=255,c=3,t=11,pt=0,l=15,sg=0,st=ok:Pressure Sensor
    send: 2-2-0-0 s=255,c=3,t=12,pt=0,l=3,sg=0,st=ok:1.1
    send: 2-2-0-0 s=0,c=0,t=8,pt=0,l=0,sg=0,st=ok:
    send: 2-2-0-0 s=1,c=0,t=6,pt=0,l=0,sg=0,st=ok:
    send: 2-2-0-0 s=3,c=1,t=16,pt=2,l=2,sg=0,st=ok:0
    Temperature = 25.30 *C
    Pressure = 1019.42 hPa
    Forecast = unknown
    send: 2-2-0-0 s=1,c=1,t=0,pt=7,l=5,sg=0,st=ok:25.3
    send: 2-2-0-0 s=0,c=1,t=4,pt=7,l=5,sg=0,st=ok:1019
    send: 2-2-0-0 s=0,c=1,t=5,pt=0,l=7,sg=0,st=ok:unknown


  • Mod

    If you load the pure binary switch example, does the switch work then? My best guess is that the reed switch is broken or incorrectly wired.



  • I've actually already tried that, worked with no problem. Maybe i've missed something or something similair, lets see what happens after a good nights sleep. Thank you for you help so far. :)


  • Plugin Developer

    @Øyvind-Lauritzen

    Debouncer Bounce won't work with sleep. Use a short sleep of 5 ms to debounce instead. Look at the binary switch sleep example.


Log in to reply
 

Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.