Advanced combination script (OneWire+DHT+Relays) over serial usb to Pi runnung domoticz - HELP with timing and group ID



  • Hi All,

    I would like to share my script i am using as an expansion shield for my domoticz home automation system. On this module i connect up to 10 DS18B20 (hardwired over the whole house on a star configuration using the Onewire protocol) as well as 3 DHT11 modules (2 bathrooms and a indoor garden) as well as 4 Finder brand relay modules to control 4 lights (2 for each bathroom). The choice of finde relays was done so that in a bathroom all the lights are interupted on 2 poles, hence the special relays from finder that switch a 5V PSU by using 4 2N2222A NGate transistors.

    This sketch is basically a combo from various other posts and scripts made by other users so all credit goes to them. The DS18B20 script qlso stores all chip IDs in the eeprom because i got sick and tired of how they would interchange inside of domoticz and thus jump from one sensor to the other.

    NOW my problem i am facing and also my cry for help:
    1)Is there anyone that can help me on the timing part of this script as i want to minimize delays caused by the data transfer of all the sensors. currently already miliseconds but still...
    2) MY biggest problem is the famous groupID issue within domoticz that i have found numerous posts about but cant seem to figure out or get working... All my DS18B20 show up seperatly now but all are grouped together even with the DHT sensors making them all show up as temp/humidity sensor (NOT OK). Also the DHT sensors are grouped wrong so the temperature and humidity are coupled wrong. In previous version of the script i got i working correctly but i lost it due to PC crash and am pretty stuck right now. I have tried stuff i found in other posts like spacing them apart in presentation (0-16 is for DS18B20 and 50-55 is for DHT with relays in between in 40 range) as well as making everything V_HUM but nothing seems to work....Any help or explaination on how to fix this would be greatly appreciated.

    Thx in advance

    /**
       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
       Example sketch showing how to send in DS1820B OneWire temperature readings back to the controller
       http://www.mysensors.org/build/temp
       Enhanced Version to keep SensorID icluding a lot of ideas from leodesigner and hauswart (forum.fhem.de)
       Improvements:
       - it will remember a sensor index in EEPROM (2 bytes per sensor)
          in case if you need to replace or add new sensor to the 1Wire bus - all other sensors will keep own sensor index#
      Last modifications:
      - Revert back to standard Mysensor EEPROM storage (in line with leodesigner code base)
      - First ID for DS has to be defined
      - Bug fixed with not changed "spot_used" value
      - Present Dallas-Hardware-ID as comment (still not working!!!)
      - Improve reading of code by opting for some more subroutines
    */
    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    // Enable and select radio type attached
    //#define MY_RADIO_NRF24
    //#define MY_RF24_PA_LEVEL RF24_PA_MIN              // This sets a low-power mode for the radio. Useful if you use the version with the bigger antenna, but don' want to power that from a separate source. It can also fix problems with fake Chinese versions of the radio.
    //#define MY_RADIO_RFM69
    // Enable serial gateway
    #define MY_GATEWAY_SERIAL
    #include <SPI.h>
    #include <MySensors.h>
    #include <DallasTemperature.h>
    #include <OneWire.h>
    #include <DHT.h>   
    
    /////////////////*CODE FOR DS18B20*/////////////////////////////
    #define COMPARE_TEMP 1 // Send temperature only if changed?
    #define ERASE_HASH // Clear EEPROM, if no 1w-device is present?
    #define SEND_ID // Send also Dallas-Addresses?
    #define ONE_WIRE_BUS 11 // Pin where dallase sensor is connected 
    #define MAX_ATTACHED_DS18B20 16
    #define EEPROM_DEVICE_ADDR_START  64     // start byte in eeprom for remembering our sensors
    #define EEPROM_DEVICE_ADDR_END    EEPROM_DEVICE_ADDR_START+MAX_ATTACHED_DS18B20*2
    
    uint8_t DS_First_Child_ID = 0; //First Child-ID to be used by Dallas Bus; set this to be higher than other Child-ID's who need EEPROM storage to avoid conflicts
    uint16_t SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature.
    float lastTemperature[MAX_ATTACHED_DS18B20];
    uint8_t numSensors = 0;
    DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
    int  resolution = 12;
    int  conversionTime = 0;
    char* charAddr = "Check for faults";
    uint8_t ts_spot[MAX_ATTACHED_DS18B20]; // array for matching bus-id to EEPROM-index
    bool spot_used[MAX_ATTACHED_DS18B20]; // used spot array
    // Initialize temperature message
    MyMessage msgTemp(0, V_TEMP);
    #ifdef SEND_ID
    MyMessage msgId(0, V_ID);
    #endif
    boolean receivedConfig = false;
    boolean metric = true;
    
    /////////////////*CODE FOR DHT*/////////////////////////////
    #define CHILD_ID_HUM1 51
    #define CHILD_ID_TEMP1 50
    #define DHT1_DATA_PIN 12
    
    #define SENSOR_TEMP1_OFFSET 0
    
    #define CHILD_ID_HUM2 53
    #define CHILD_ID_TEMP2 52
    #define DHT2_DATA_PIN 5
    
    #define SENSOR_TEMP2_OFFSET 0
    
    #define CHILD_ID_HUM3 55
    #define CHILD_ID_TEMP3 54
    #define DHT3_DATA_PIN 6
    
    #define SENSOR_TEMP3_OFFSET 0
    
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    static const uint8_t FORCE_UPDATE_N_READS = 2;
    
    // Must be >1000ms for DHT22 and >2000ms for DHT11
    static const uint64_t UPDATE_INTERVAL = 30000;
    
    DHT dht1;
    DHT dht2;
    DHT dht3;
    
    float lastTemp1;
    float lastHum1;
    float lastTemp2;
    float lastHum2;
    float lastTemp3;
    float lastHum3;
    uint8_t nNoUpdatesTemp1;
    uint8_t nNoUpdatesHum1;
    uint8_t nNoUpdatesTemp2;
    uint8_t nNoUpdatesHum2;
    uint8_t nNoUpdatesTemp3;
    uint8_t nNoUpdatesHum3;
    
    MyMessage msgTemp1(CHILD_ID_TEMP1, V_TEMP);
    MyMessage msgHum1(CHILD_ID_HUM1, V_HUM);
    MyMessage msgTemp2(CHILD_ID_TEMP2, V_TEMP);
    MyMessage msgHum2(CHILD_ID_HUM2, V_HUM);
    MyMessage msgTemp3(CHILD_ID_TEMP3, V_TEMP);
    MyMessage msgHum3(CHILD_ID_HUM3, V_HUM);
    
    
    /////////////////*CODE FOR FINDER RELAYS*/////////////////////////////
    #define RELAY_PIN 7  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
    #define NUMBER_OF_RELAYS 4 // Total number of attached relays
    #define RELAY_ON 1  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
    
    
    
    void before() {
      conversionTime = 750 / (1 << (12 - resolution));
      // Startup up the OneWire library
      sensors.begin();
      // requestTemperatures() will not block current thread
      sensors.setWaitForConversion(false);
      // Fetch the number of attached temperature sensors
      numSensors = sensors.getDeviceCount();
      // use the 1.1 V internal reference
      initialiseIdArray();
      for (int sensor=41, pin=RELAY_PIN; sensor<=NUMBER_OF_RELAYS+40; sensor++, pin++) {
            // Then set relay pins in output mode
            pinMode(pin, OUTPUT);
            // Set relay to last known state (using eeprom storage)
            digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
        }
    }
    
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("1WIRE SHIELD", "V2");
      // Present all sensors to controller
      for (int i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) {
        sensors.getAddress(tempDeviceAddress, i);
        Serial.print("Hardware presented: ");
        charAddr = addrToChar(tempDeviceAddress);
        Serial.println(charAddr);
        present(ts_spot[i], S_TEMP, charAddr);
        sensors.setResolution(tempDeviceAddress, resolution);
      }
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_TEMP1, S_TEMP);
      present(CHILD_ID_HUM1, S_HUM);
      present(CHILD_ID_TEMP2, S_TEMP);
      present(CHILD_ID_HUM2, S_HUM);
      present(CHILD_ID_TEMP3, S_TEMP);
      present(CHILD_ID_HUM3, S_HUM);
    
      metric = getControllerConfig().isMetric;
    
        for (int sensor=41, pin=RELAY_PIN; sensor<=NUMBER_OF_RELAYS+40; sensor++, pin++) {
            // Register all sensors to gw (they will be created as child devices)
            present(sensor, S_BINARY);
        }
    }
    
    void setup() {
    #ifdef SEND_ID
      for (int i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) {
        sensors.getAddress(tempDeviceAddress, i);
        //charAddr = addrToChar(tempDeviceAddress);
        //8 sorgt dafür, dass alle 16 Stellen übermittelt werden
        send(msgId.setSensor(ts_spot[i]).set(tempDeviceAddress, 8));
      }
    #endif
    
     dht1.setup(DHT1_DATA_PIN);
     dht2.setup(DHT2_DATA_PIN);
     dht3.setup(DHT3_DATA_PIN);
    
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht1.getMinimumSamplingPeriod());
      sleep(dht2.getMinimumSamplingPeriod());
      sleep(dht3.getMinimumSamplingPeriod());
    
    }
    
    void loop() {
    
        // Force reading sensor, so it works also after sleep()
      dht1.readSensor(true);
      dht2.readSensor(true);
      dht3.readSensor(true);
      //Get Temp DHT1
      float temperature1 = dht1.getTemperature();
      if (isnan(temperature1)) {
        Serial.println("Failed reading temperature from DHT1!");
      } else if (temperature1 != lastTemp1 || nNoUpdatesTemp1 == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp1 = temperature1;
        if (!metric) {
          temperature1 = dht1.toFahrenheit(temperature1);
        }
        // Reset no updates counter
        nNoUpdatesTemp1 = 0;
        temperature1 += SENSOR_TEMP1_OFFSET;
        send(msgTemp1.set(temperature1, 1));
    
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature1);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp2++;
      }
      // Get humidity from DHT library
      float humidity1 = dht1.getHumidity();
      if (isnan(humidity1)) {
        Serial.println("Failed reading humidity from DHT1");
      } else if (humidity1 != lastHum1 || nNoUpdatesHum1 == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum1 = humidity1;
        // Reset no updates counter
        nNoUpdatesHum1 = 0;
        send(msgHum1.set(humidity1, 1));
    
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity1);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum1++;
      }
      float temperature2 = dht2.getTemperature();
      if (isnan(temperature2)) {
        Serial.println("Failed reading temperature from DHT2!");
      } else if (temperature2 != lastTemp2 || nNoUpdatesTemp2 == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp2 = temperature2;
        if (!metric) {
          temperature2 = dht2.toFahrenheit(temperature2);
        }
        // Reset no updates counter
        nNoUpdatesTemp2 = 0;
        temperature2 += SENSOR_TEMP2_OFFSET;
        send(msgTemp2.set(temperature2, 1));
    
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature2);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp2++;
      }
    
      // Get humidity from DHT library
      float humidity2 = dht2.getHumidity();
      if (isnan(humidity2)) {
        Serial.println("Failed reading humidity from DHT2");
      } else if (humidity2 != lastHum2 || nNoUpdatesHum2 == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum2 = humidity2;
        // Reset no updates counter
        nNoUpdatesHum2 = 0;
        send(msgHum2.set(humidity2, 1));
    
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity2);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum2++;
      }
      float temperature3 = dht3.getTemperature();
      if (isnan(temperature3)) {
        Serial.println("Failed reading temperature from DHT3!");
      } else if (temperature3 != lastTemp3 || nNoUpdatesTemp3 == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp3 = temperature3;
        if (!metric) {
          temperature3 = dht3.toFahrenheit(temperature3);
        }
        // Reset no updates counter
        nNoUpdatesTemp3 = 0;
        temperature3 += SENSOR_TEMP3_OFFSET;
        send(msgTemp3.set(temperature3, 1));
    
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature3);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp3++;
      }
    
      // Get humidity from DHT library
      float humidity3 = dht3.getHumidity();
      if (isnan(humidity3)) {
        Serial.println("Failed reading humidity from DHT3");
      } else if (humidity3 != lastHum3 || nNoUpdatesHum3 == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum3 = humidity3;
        // Reset no updates counter
        nNoUpdatesHum3 = 0;
        send(msgHum3.set(humidity3, 1));
    
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity3);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum3++;
      }
      
      // Sleep for a while to save energy
      sleep(UPDATE_INTERVAL); 
    
      // Fetch temperatures from Dallas sensors
      sensors.requestTemperatures();
      // query conversion time and sleep until conversion completed
      // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
      wait(conversionTime);
      // Read temperatures and send them to controller
      for (int i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) {
        // Fetch and round temperature to one decimal
        float temperature = static_cast<float>(static_cast<int>((metric ? sensors.getTempCByIndex(i) : sensors.getTempFByIndex(i)) * 10.)) / 10.;
        // Only send data if temperature has changed and no error
    #if COMPARE_TEMP == 1
        if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) {
    #else
        if (temperature != -127.00 && temperature != 85.00) {
    #endif
          // Send in the new temperature
          send(msgTemp.setSensor(ts_spot[i]).set(temperature, 1));
          // Save new temperatures for next compare
          lastTemperature[i] = temperature;
        }
      }
      wait(SLEEP_TIME);
    }
    
    
      
    // Subroutines
    //##########################################################
    //
    void initialiseIdArray() {
      uint8_t knownSensors = 0;
    #ifdef ERASE_HASH
      if (numSensors < 1) {
        for (uint8_t i = EEPROM_DEVICE_ADDR_START; i < EEPROM_DEVICE_ADDR_END + 1; i++) {
          saveState(i, 0xFF); //0xFF seems to be better in line with mysensors standards, was 0x00
        }
        Serial.println("EEPROM cleared...");
      }
    #endif
      //initialise spot_used array to default false
      for (uint8_t i = 0; i < MAX_ATTACHED_DS18B20; i++) {
        spot_used[i] = false;
      }
      // first loop: filling Address-Array with IDs already stored, and clear used spot array
      for (uint8_t i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) {
        sensors.getAddress(tempDeviceAddress, i);
        // check if we know this sensor
        int8_t sidx = getSensorIndex(tempDeviceAddress);
        if (sidx < 0) {
          ts_spot[i] = 0;
        }
        else {
          // we know this sensor
          ts_spot[i] = sidx + DS_First_Child_ID;
          spot_used[sidx] = true;
          knownSensors++;
        }
      }
    #ifdef MY_DEBUG
      Serial.println();
      Serial.print(F("# Stored Devices: "));
      Serial.println(knownSensors);
    #endif
      // second loop for filling Address-Array with IDs not stored yet
      for (uint8_t i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) {
        sensors.getAddress(tempDeviceAddress, i);
        // check if we do not know this sensor yet
        if (ts_spot[i] == 0) {
          uint8_t k = getUnusedSpot();
          ts_spot[i] = k + DS_First_Child_ID;
          spot_used[k] = true;
          storeSensorAddr(tempDeviceAddress, k);
        }
      }
    #ifdef MY_DEBUG
      for (int i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) {
        sensors.getAddress(tempDeviceAddress, i);
        Serial.println();
        Serial.print(i);
        Serial.print(F(" index: "));
        Serial.print(ts_spot[i]);
        Serial.print(F(" address: "));
        charAddr = addrToChar(tempDeviceAddress);
        Serial.println(charAddr);
    #endif
      }
    }
    
    // a simple hash function for 1wire address to reduce id to two bytes
    uint16_t simpleAddrHash(DeviceAddress a) {
      return ((a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5] ^ a[6]) << 8) + a[7];
    }
    
    // search for device address hash in eeprom
    // return -1 if not found
    int8_t getSensorIndex(DeviceAddress a) {
      uint16_t hash = simpleAddrHash(a);
      int8_t idx = -1;
      uint8_t aidx = 0;
      uint8_t ptr = EEPROM_DEVICE_ADDR_START;
      while (ptr < EEPROM_DEVICE_ADDR_END && idx == -1) {
        uint8_t hash1 = loadState(ptr);
        uint8_t hash2 = loadState(ptr + 1);
        if ( hash1 == (uint8_t)(hash >> 8) && hash2 == (uint8_t)(hash & 0x00FF)) {
          // found device index
          idx = aidx;
        }
        aidx++;
        ptr += 2;
      }
      return idx;
    }
    
    // search for first unused spot in eeprom
    uint8_t getUnusedSpot() {
      int8_t j = 0;
      while (spot_used[j] == true) {
        j++;
      }
      return j;
    }
    
    // save address hash in EEPROM under index
    void storeSensorAddr(DeviceAddress a, uint8_t index) {
      uint16_t hash = simpleAddrHash(a);
      uint8_t ptr = EEPROM_DEVICE_ADDR_START + index * 2;
      if (ptr < EEPROM_DEVICE_ADDR_END) {
        saveState(ptr,   hash >> 8);
        saveState(ptr + 1, hash & 0x00FF);
      }
    #ifdef MY_DEBUG
      Serial.print(F("storeSensorAddr under index: "));
      Serial.println(index);
    #endif
    }
    
    char* addrToChar(uint8_t* data) {
      String strAddr = String(data[0], HEX); //Chip Version; should be higher than 16
      byte first ;
      int j = 0;
      for (uint8_t i = 1; i < 8; i++) {
        if (data[i] < 16) strAddr = strAddr + 0;
        strAddr = strAddr + String(data[i], HEX);
        strAddr.toUpperCase();
      }
      for (int j = 0; j < 16; j++) {
        charAddr[j] = strAddr[j];
      }
      return charAddr;
      }
    
    
    
    void receive(const MyMessage &message)
    {
        // We only expect one type of message from controller. But we better check anyway.
        if (message.type==V_STATUS) {
            // Change relay state
            digitalWrite(message.sensor-41+RELAY_PIN, message.getBool()?RELAY_ON:RELAY_OFF);
            // Store state in eeprom
            saveState(message.sensor, message.getBool());
            // Write some debug info
            Serial.print("Incoming change for sensor:");
            Serial.print(message.sensor);
            Serial.print(", New status: ");
            Serial.println(message.getBool());
        }
    }
        
    

Log in to reply
 

Suggested Topics

  • 5
  • 11
  • 2
  • 1
  • 2
  • 22
  • 7
  • 1

288
Online

9.8k
Users

10.3k
Topics

106.8k
Posts