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()); } }
-
@AterMentis said in Advanced combination script (OneWire+DHT+Relays) over serial usb to Pi runnung domoticz - HELP with timing and group ID:
// 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);Did you find a solution ?
On other topic you can find a posible solution:
Change order of reporting/presenting devices:// Register all sensors to gw (they will be created as child devices)
present(CHILD_ID_TEMP1, S_TEMP);
present(CHILD_ID_TEMP2, S_TEMP);
present(CHILD_ID_TEMP3, S_TEMP);
present(CHILD_ID_HUM1, S_HUM);
present(CHILD_ID_HUM2, S_HUM);
present(CHILD_ID_HUM3, S_HUM);