Multiple I2C sensors sketch



  • Hello Guys,

    I am happy user of Mysensors project 🙂

    I have many nodes up and running around my house. My new project is to build node with RFID functionality. I would like to use Lux sensor (BH1750) running on I2C bus with RFID sensor (red PN532) which is also running on I2C bus. How I can connect two I2C sensors together and make correct Mysensors sketch for it? Do you know maybe already explained tutorial so I could dig into it ? 😄 I know that each of I2C sensor will have its own bus address but I do not know how it is looks like from MySensors library perspective.

    Looking forward for your reply.

    Regards,
    Maciek

    P.S. I also have around 5x (blue) RFID RC522 I only know sketches for PN532, but maybe you know how to use them with Arduino MySensors also ? 😄


  • Contest Winner

    @macieiks You need to know the i2c addresses of each individual device. You can use the i2c scanner for that. Hooking up is real easy. See this:

    alt text

    You need pullup resistors (10K if I'm not mistaken).



  • Hey,

    Thanks for the reply. In overall I know concept of I2C, however I am looking for the guide which describes "How to" and also example ofMysensors sketch with support of min 2 I2C sensors together 🙂

    Regards,
    Maciek


  • Hardware Contributor

    @macieiks
    Hi.
    not sure if it's the right section 😉
    In fact it's not really complicated. i2c or others sensors are almost the same when you want to mix sketch.
    Add includes for your desired sensors libs, declarations for your sensors id, present sensors like it's done for one sensor sketch, and use send function to send infos in sketch.
    The best is to start with your rfid sketch. Check it works ok. Then add to it, the bh1750 sketch parts. if you're not sure, add things step by step.
    If you have some problems, post your sketch and we will help you 🙂



  • Thank you guys for your input.

    Yes, I will start step by step as I do with mixing Mysensors sketches. The thing was about theses multiple I2C how they will be discovered. I will try to start with example RFID sketch, make it 100% work and then I will start with example lux sensor 🙂 We will see what will happend. For sure I will provide my output here hehe 😄

    Regards,
    Maciek


  • Contest Winner

    @macieiks I don't think you're question is really related to MySensors, it's more an Arduino related question. The problem you might have is the memory capacity of the Arduino. Here's the sketch for the first mySensor node I made. It uses an I2C lux and i2c barometric pressure sensor and an HDT11 humidity sensor.

    /**
     * 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
     * 
     * DESCRIPTION
     * This sketch provides an example how to implement a humidity/temperature
     * sensor using DHT11/DHT-22 
     * http://www.mysensors.org/build/humidity
     */
     
    // #define DEBUG 
     
    #include <SPI.h>
    #include <MySensor.h>  
    #include <DHT.h>
    #include <Wire.h>
    #include <Adafruit_BMP085.h>
    #include <Adafruit_TSL2561_U.h>
    #include <Adafruit_Sensor.h>
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_BARO 2
    #define CHILD_ID_LIGHT 3
    
    #define HUMIDITY_SENSOR_DIGITAL_PIN 3
    
    const float ALTITUDE = 28; // <-- adapt this value to your own location's altitude. Lijkt dus in meters te zijn
    unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds)
    
    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();
    MySensor gw;
    Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);
    
    DHT dht;
    float lastTemp = -1000;
    float lastHum = -1;
    float lastPressure = -1;
    int lastForecast = -1;
    int lastLightLevel = -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;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage pressureMsg(CHILD_ID_BARO, V_PRESSURE);
    MyMessage forecastMsg(CHILD_ID_BARO, V_FORECAST);
    MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
    
    
    /**************************************************************************/
    /*
        Displays some basic information on this sensor from the unified
        sensor API sensor_t type (see Adafruit_Sensor for more information)
    */
    /**************************************************************************/
    #ifdef DEBUG
    void displaySensorDetails(void)
    {
      sensor_t sensor;
      tsl.getSensor(&sensor);
      Serial.println("------------------------------------");
      Serial.print  ("Sensor:       "); Serial.println(sensor.name);
      Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
      Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
      Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" lux");
      Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" lux");
      Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" lux");  
      Serial.println("------------------------------------");
      Serial.println("");
      delay(500);
    }
    #endif
    
    /**************************************************************************/
    /*
        Configures the gain and integration time for the TSL2561
    */
    /**************************************************************************/
    void configureSensor(void)
    {
      /* You can also manually set the gain or enable auto-gain support */
      // tsl.setGain(TSL2561_GAIN_1X);      /* No gain ... use in bright light to avoid sensor saturation */
      // tsl.setGain(TSL2561_GAIN_16X);     /* 16x gain ... use in low light to boost sensitivity */
      tsl.enableAutoRange(true);            /* Auto-gain ... switches automatically between 1x and 16x */
      
      /* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
      tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);      /* fast but low resolution */
      // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS);  /* medium resolution and speed   */
      // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);  /* 16-bit data but slowest conversions */
    
      /* Update these values depending on what you've set above! */
    #ifdef DEBUG
        Serial.println("------------------------------------");
      Serial.print  ("Gain:         "); Serial.println("Auto");
      Serial.print  ("Timing:       "); Serial.println("13 ms");
      Serial.println("------------------------------------");
    #endif
    }
    
    void setup()  
    { 
      gw.begin();
    
    #ifdef DEBUG
      Serial.begin(115200);
      Serial.println("Light Sensor Test"); Serial.println("115200");
    #endif
    
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN); 
    
      // Send the Sketch Version Information to the Gateway
      gw.sendSketchInfo("Inside weather conditions", "1.0");
    
      /* Only presenting the sensors if they're available */  
      if (bmp.begin()) {
        gw.present(CHILD_ID_BARO, S_BARO);
      }
    #ifdef DEBUG
      else {
        Serial.println( 'Barometer not found' );
      }
    #endif
    
      if(!tsl.begin())
      {
    #ifdef DEBUG
        /* There was a problem detecting the ADXL345 ... check your connections */
        Serial.print( "Ooops, no TSL2561 detected ... Check your wiring or I2C ADDR!" );
    #endif
     //    while(1);
      } 
      else {
    #ifdef DEBUG
        /* Display some basic information on this sensor */
        displaySensorDetails();
    #endif  
        /* Setup the sensor gain and integration time */
        configureSensor();
        gw.present(CHILD_ID_LIGHT, S_LIGHT_LEVEL); 
      }
    
      // Register all sensors to gw (they will be created as child devices)
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      gw.sendBatteryLevel( 100 );
    }
    
    void loop()      
    {  
      delay(dht.getMinimumSamplingPeriod());
    
      float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0;
      float temperature = bmp.readTemperature();
      
      int forecast = sample(pressure);
      
    #ifdef DEBUG
      float dhtTemperature = dht.getTemperature();
      Serial.print("Temperature = ");
      Serial.print(temperature);
      Serial.println( " *C" );
      Serial.print("Pressure = ");
      Serial.print(pressure);
      Serial.println(" hPa");
      Serial.print("Forecast = ");
      Serial.println(weather[forecast]);
    
      Serial.print( "Dht Temp: " );
      Serial.print(dhtTemperature);
      Serial.println( " *C" );
    #endif
    
      if (isnan(temperature)) {
    #ifdef DEBUG    
          Serial.println("Failed reading temperature from DHT");
    #endif
      }
      else if (temperature != lastTemp) {
        lastTemp = temperature;
        gw.send(msgTemp.set(temperature, 1));
    #ifdef DEBUG    
        Serial.print("T: ");
        Serial.println(temperature);
    #endif    
      }
      
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
    #ifdef DEBUG
      Serial.println("Failed reading humidity from DHT");
    #endif  
      } 
      else if (humidity != lastHum) {
          lastHum = humidity;
          gw.send(msgHum.set(humidity, 1));
    #ifdef DEBUG      
          Serial.print("H: ");
          Serial.println(humidity);
    #endif      
      }
      
       sensors_event_t event;
    
     // maybe a delay between the sensor readings
      tsl.getEvent(&event);
     
      /* Display the results (light is measured in lux) */
      // if (event.light) { // removed test to see if we get a 0 meeting during the evening and night.
    #ifdef DEBUG
        Serial.print(event.light); 
        Serial.println(" lux");
    #endif
        if ( event.light != lastLightLevel ) {
          gw.send(lightMsg.set((uint16_t)event.light));
          lastLightLevel = event.light;
        }
    /*  } // removed test to see if we get a 0 meeting during the evening and night.
      else
      {
        // If event.light = 0 lux the sensor is probably saturated and no reliable data could be generated! 
     #ifdef DEBUG
       Serial.println("Sensor overload");
     #endif  
      }
      */
      
      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); //sleep a bit
    }
    
    
    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
    #ifdef DEBUG
    	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]);
    #endif
    	return forecast;
    }
    

Log in to reply
 

Suggested Topics

68
Online

11.4k
Users

11.1k
Topics

112.7k
Posts