diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 3c6fee20..1556159a 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -758,11 +758,13 @@ PROGMEM const char* const custom_reset_string[] = { #define SENSOR_TEMPERATURE_DECIMALS 1 #define SENSOR_HUMIDITY_DECIMALS 0 #define SENSOR_ANALOG_DECIMALS 0 +#define SENSOR_EVENTS_DECIMALS 0 #define SENSOR_UNKNOWN_TOPIC "unknown" #define SENSOR_TEMPERATURE_TOPIC "temperature" #define SENSOR_HUMIDITY_TOPIC "humidity" #define SENSOR_ANALOG_TOPIC "analog" +#define SENSOR_EVENTS_TOPIC "events" #define SENSOR_TEMPERATURE_UNITS TMP_CELSIUS // Temperature units (TMP_CELSIUS | TMP_FAHRENHEIT) #define SENSOR_TEMPERATURE_CORRECTION 0.0 // Offset correction diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index a1eb1665..19382aeb 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -75,6 +75,7 @@ template bool idbSend(const char * topic, unsigned char id, T payloa // Sensors // ----------------------------------------------------------------------------- #include "sensors/BaseSensor.h" +#include // WTF! // ----------------------------------------------------------------------------- // Utils diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index 3b93a8e9..3e55f885 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -35,7 +35,7 @@ //-------------------------------------------------------------------------------- #ifndef DHT_SUPPORT -#define DHT_SUPPORT 1 +#define DHT_SUPPORT 0 #endif #ifndef DHT_PIN @@ -92,7 +92,7 @@ //-------------------------------------------------------------------------------- #ifndef COUNTER_SUPPORT -#define COUNTER_SUPPORT 0 // Do not build with counter support by default +#define COUNTER_SUPPORT 1 // Do not build with counter support by default #endif #ifndef COUNTER_PIN @@ -121,11 +121,11 @@ //-------------------------------------------------------------------------------- #ifndef DS18B20_SUPPORT -#define DS18B20_SUPPORT 0 +#define DS18B20_SUPPORT 1 #endif #ifndef DS18B20_PIN -#define DS18B20_PIN 14 +#define DS18B20_PIN 13 #endif #ifndef DS18B20_PULLUP diff --git a/code/espurna/counter.ino b/code/espurna/counter.ino deleted file mode 100644 index 44cef225..00000000 --- a/code/espurna/counter.ino +++ /dev/null @@ -1,103 +0,0 @@ -/* - -COUNTER MODULE - -Copyright (C) 2017 by Xose Pérez - -*/ - -#if COUNTER_SUPPORT - -volatile unsigned long _counterCurrent = 0; -volatile unsigned long _counterLast = 0; - -unsigned long _counterBuffer[COUNTER_REPORT_EVERY] = {0}; -unsigned char _counterBufferPointer = 0; -unsigned long _counterValue = 0; - -// ----------------------------------------------------------------------------- -// COUNTER -// ----------------------------------------------------------------------------- - -void ICACHE_RAM_ATTR _counterISR() { - if (millis() - _counterLast > COUNTER_DEBOUNCE) { - ++_counterCurrent; - _counterLast = millis(); - } -} - -void _counterWebSocketOnSend(JsonObject& root) { - root["counterVisible"] = 1; - root["counterValue"] = getCounter(); -} - -// ----------------------------------------------------------------------------- - -unsigned long getCounter() { - return _counterValue; -} - -void counterSetup() { - - pinMode(COUNTER_PIN, COUNTER_PIN_MODE); - attachInterrupt(COUNTER_PIN, _counterISR, COUNTER_INTERRUPT_MODE); - - #if WEB_SUPPORT - - // Websockets - wsOnSendRegister(_counterWebSocketOnSend); - - // API - apiRegister(COUNTER_TOPIC, COUNTER_TOPIC, [](char * buffer, size_t len) { - snprintf_P(buffer, len, PSTR("%d"), getCounter()); - }); - - #endif - - DEBUG_MSG_P(PSTR("[COUNTER] Counter on GPIO %d\n"), COUNTER_PIN); - -} - -void counterLoop() { - - // Check if we should read new data - static unsigned long last_update = 0; - if ((millis() - last_update) < COUNTER_UPDATE_INTERVAL) return; - last_update = millis(); - - // Update buffer counts - _counterValue = _counterValue - _counterBuffer[_counterBufferPointer] + _counterCurrent; - _counterBuffer[_counterBufferPointer] = _counterCurrent; - _counterCurrent = 0; - _counterBufferPointer = (_counterBufferPointer + 1) % COUNTER_REPORT_EVERY; - - DEBUG_MSG_P(PSTR("[COUNTER] Value: %d\n"), _counterValue); - - // Update websocket clients - #if WEB_SUPPORT - wsSend(_counterWebSocketOnSend); - #endif - - // Do we have to report? - if (_counterBufferPointer == 0) { - - // Send MQTT messages - #if MQTT_SUPPORT - mqttSend(getSetting("counterTopic", COUNTER_TOPIC).c_str(), String(_counterValue).c_str()); - #endif - - // Send to Domoticz - #if DOMOTICZ_SUPPORT - domoticzSend("dczCountIdx", 0, String(_counterValue).c_str()); - #endif - - // Send to InfluxDB - #if INFLUXDB_SUPPORT - idbSend(COUNTER_TOPIC, _counterValue); - #endif - - } - -} - -#endif // COUNTER_SUPPORT diff --git a/code/espurna/dht.ino b/code/espurna/dht.ino deleted file mode 100644 index 572a1e0f..00000000 --- a/code/espurna/dht.ino +++ /dev/null @@ -1,272 +0,0 @@ -/* - -DHT MODULE - -Copyright (C) 2016-2017 by Xose Pérez - -*/ - -#if DHT_SUPPORT - -double _dhtTemperature = 0; -unsigned int _dhtHumidity = 0; -bool _dhtIsConnected = false; - -// ----------------------------------------------------------------------------- -// HAL -// https://github.com/gosouth/DHT22/blob/master/main/DHT22.c -// ----------------------------------------------------------------------------- - -#define DHT_MAX_DATA 5 -#define DHT_MAX_ERRORS 5 -#define DHT_MIN_INTERVAL 2000 -#define DHT_OK 0 -#define DHT_CHECKSUM_ERROR -1 -#define DHT_TIMEOUT_ERROR -2 - -#define DHT11 11 -#define DHT22 22 -#define DHT21 21 -#define AM2301 21 - -unsigned long _getSignalLevel(unsigned char gpio, int usTimeOut, bool state) { - unsigned long uSec = 1; - while (digitalRead(gpio) == state) { - if (++uSec > usTimeOut) return 0; - delayMicroseconds(1); - } - return uSec; -} - -int readDHT(unsigned char gpio, unsigned char type) { - - static unsigned long last_ok = 0; - if ((last_ok > 0) && (millis() - last_ok < DHT_MIN_INTERVAL)) return DHT_OK; - - unsigned long low = 0; - unsigned long high = 0; - - static unsigned char errors = 0; - uint8_t dhtData[DHT_MAX_DATA] = {0}; - uint8_t byteInx = 0; - uint8_t bitInx = 7; - - // Send start signal to DHT sensor - if (++errors > DHT_MAX_ERRORS) { - errors = 0; - digitalWrite(gpio, HIGH); - delay(250); - } - pinMode(gpio, OUTPUT); - noInterrupts(); - digitalWrite(gpio, LOW); - delayMicroseconds(500); - digitalWrite(gpio, HIGH); - delayMicroseconds(40); - pinMode(gpio, INPUT_PULLUP); - - // No errors, read the 40 data bits - for( int k = 0; k < 41; k++ ) { - - // Starts new data transmission with >50us low signal - low = _getSignalLevel(gpio, 56, LOW); - if (low==0) return DHT_TIMEOUT_ERROR; - - // Check to see if after >70us rx data is a 0 or a 1 - high = _getSignalLevel(gpio, 75, HIGH); - if (high==0) return DHT_TIMEOUT_ERROR; - - // Skip the first bit - if (k==0) continue; - - // add the current read to the output data - // since all dhtData array where set to 0 at the start, - // only look for "1" (>28us us) - if (high > low) dhtData[byteInx] |= (1 << bitInx); - - // index to next byte - if (bitInx == 0) { - bitInx = 7; - ++byteInx; - } else { - --bitInx; - } - - } - - interrupts(); - - // Verify checksum - if (dhtData[4] != ((dhtData[0] + dhtData[1] + dhtData[2] + dhtData[3]) & 0xFF)) { - return DHT_CHECKSUM_ERROR; - } - - // Get humidity from Data[0] and Data[1] - if (type == DHT11) { - _dhtHumidity = dhtData[0]; - } else { - _dhtHumidity = dhtData[0] * 256 + dhtData[1]; - _dhtHumidity /= 10; - } - - // Get temp from Data[2] and Data[3] - if (type == DHT11) { - _dhtTemperature = dhtData[2]; - } else { - _dhtTemperature = (dhtData[2] & 0x7F) * 256 + dhtData[3]; - _dhtTemperature /= 10; - if (dhtData[2] & 0x80) _dhtTemperature *= -1; - } - - last_ok = millis(); - errors = 0; - return DHT_OK; - -} - -int readDHT() { - return readDHT(DHT_PIN, DHT_TYPE); -} - -// ----------------------------------------------------------------------------- -// Private -// ----------------------------------------------------------------------------- - -void _dhtWebSocketOnSend(JsonObject& root) { - root["dhtVisible"] = 1; - root["dhtConnected"] = getDHTIsConnected(); - if (getDHTIsConnected()) { - root["dhtTmp"] = getDHTTemperature(); - root["dhtHum"] = getDHTHumidity(); - } - root["tmpUnits"] = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt(); -} - -// ----------------------------------------------------------------------------- -// Values -// ----------------------------------------------------------------------------- - -bool getDHTIsConnected() { - return _dhtIsConnected; -} - -double getDHTTemperature(bool celsius) { - double value = celsius ? _dhtTemperature : _dhtTemperature * 1.8 + 32; - double correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat(); - return roundTo(value + correction, TEMPERATURE_DECIMALS); -} - -double getDHTTemperature() { - bool celsius = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt() == TMP_CELSIUS; - return getDHTTemperature(celsius); -} - -unsigned int getDHTHumidity() { - return _dhtHumidity; -} - -void dhtSetup() { - - #if DHT_PULLUP - pinMode(DHT_PIN, INPUT_PULLUP); - #endif - - #if WEB_SUPPORT - - // Websockets - wsOnSendRegister(_dhtWebSocketOnSend); - - apiRegister(DHT_TEMPERATURE_TOPIC, DHT_TEMPERATURE_TOPIC, [](char * buffer, size_t len) { - dtostrf(getDHTTemperature(), 1-len, 1, buffer); - }); - apiRegister(DHT_HUMIDITY_TOPIC, DHT_HUMIDITY_TOPIC, [](char * buffer, size_t len) { - snprintf_P(buffer, len, PSTR("%d"), getDHTHumidity()); - }); - - #endif - -} - -void dhtLoop() { - - static unsigned long last_update = 0; - static double last_temperature = 0.0; - static unsigned int last_humidity = 0; - - // Check if we should read new data - if ((millis() - last_update > DHT_UPDATE_INTERVAL) || (last_update == 0)) { - last_update = millis(); - - // Read sensor data - int response = readDHT(DHT_PIN, DHT_TYPE); - if (response != DHT_OK) { - DEBUG_MSG_P(PSTR("[DHT] Error: %d\n"), response); - return; - } - _dhtIsConnected = true; - - // Get values - bool celsius = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt() == TMP_CELSIUS; - double t = getDHTTemperature(celsius); - unsigned int h = getDHTHumidity(); - - // Build strings - char temperature[6]; - char humidity[6]; - dtostrf(t, 1-sizeof(temperature), 1, temperature); - itoa((unsigned int) h, humidity, 10); - - // Debug - DEBUG_MSG_P(PSTR("[DHT] Temperature: %s%s\n"), temperature, celsius ? "ºC" : "ºF"); - DEBUG_MSG_P(PSTR("[DHT] Humidity: %s\n"), humidity); - - // If the new temperature & humidity are different from the last - if ((fabs(t - last_temperature) >= TEMPERATURE_MIN_CHANGE) - || (abs(h - last_humidity) >= HUMIDITY_MIN_CHANGE)) { - - last_temperature = t; - last_humidity = h; - - // Send MQTT messages - #if MQTT_SUPPORT - mqttSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature); - mqttSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity); - #endif - - // Send to Domoticz - #if DOMOTICZ_SUPPORT - { - domoticzSend("dczTmpIdx", 0, temperature); - int status; - if (h > 70) { - status = HUMIDITY_WET; - } else if (h > 45) { - status = HUMIDITY_COMFORTABLE; - } else if (h > 30) { - status = HUMIDITY_NORMAL; - } else { - status = HUMIDITY_DRY; - } - char buffer[2]; - snprintf_P(buffer, sizeof(buffer), PSTR("%d"), status); - domoticzSend("dczHumIdx", humidity, buffer); - } - #endif - - #if INFLUXDB_SUPPORT - idbSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature); - idbSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity); - #endif - - } - - // Update websocket clients - #if WEB_SUPPORT - wsSend(_dhtWebSocketOnSend); - #endif - - } - -} - -#endif diff --git a/code/espurna/ds18b20.ino b/code/espurna/ds18b20.ino deleted file mode 100644 index 701c18ea..00000000 --- a/code/espurna/ds18b20.ino +++ /dev/null @@ -1,147 +0,0 @@ -/* - -DS18B20 MODULE - -Copyright (C) 2016-2017 by Xose Pérez - -*/ - -#if DS18B20_SUPPORT - -#include -#include - -OneWire oneWire(DS18B20_PIN); -DallasTemperature ds18b20(&oneWire); - -bool _dsIsConnected = false; -double _dsTemperature = 0; - -// ----------------------------------------------------------------------------- -// Private -// ----------------------------------------------------------------------------- - -void _dsWebSocketOnSend(JsonObject& root) { - root["dsVisible"] = 1; - root["dsConnected"] = getDSIsConnected(); - if (getDSIsConnected()) { - root["dsTmp"] = getDSTemperature(); - } - root["tmpUnits"] = getSetting("tmpUnits", TMP_UNITS).toInt(); -} - -// ----------------------------------------------------------------------------- -// DS18B20 -// ----------------------------------------------------------------------------- - -bool getDSIsConnected() { - return _dsIsConnected; -} - -double getDSTemperature(bool celsius) { - double value = celsius ? _dsTemperature : _dsTemperature * 1.8 + 32; - double correction = getSetting("tmpCorrection", TEMPERATURE_CORRECTION).toFloat(); - return roundTo(value + correction, TEMPERATURE_DECIMALS); -} - -double getDSTemperature() { - bool celsius = getSetting("tmpUnits", TMP_UNITS).toInt() == TMP_CELSIUS; - return getDSTemperature(celsius); -} - -void dsSetup() { - - #if DS18B20_PULLUP - pinMode(DS18B20_PIN, INPUT_PULLUP); - #endif - - ds18b20.begin(); - ds18b20.setWaitForConversion(false); - - #if WEB_SUPPORT - - wsOnSendRegister(_dsWebSocketOnSend); - - apiRegister(DS18B20_TEMPERATURE_TOPIC, DS18B20_TEMPERATURE_TOPIC, [](char * buffer, size_t len) { - dtostrf(getDSTemperature(), 1-len, 1, buffer); - }); - - #endif - -} - -void dsLoop() { - - static unsigned long last_update = 0; - static double last_temperature = 0.0; - static bool requested = false; - - if ((millis() - last_update > DS18B20_UPDATE_INTERVAL) || (last_update == 0)) { - - if (!requested) { - ds18b20.requestTemperatures(); - requested = true; - // Requesting takes time, so data will probably not be available in this round - return; - } - - // Check if requested data is already available - if (!ds18b20.isConversionComplete()) return; - requested = false; - last_update = millis(); - - // Read sensor data - double t = ds18b20.getTempCByIndex(0); - - // Check returned value - if (t == DEVICE_DISCONNECTED_C) { - _dsIsConnected = false; - DEBUG_MSG_P(PSTR("[DS18B20] Not connected\n")); - return; - } else { - _dsIsConnected = true; - } - - // Save & convert - _dsTemperature = t; - bool celsius = getSetting("tmpUnits", TMP_UNITS).toInt() == TMP_CELSIUS; - t = getDSTemperature(celsius); - - // Build string - char temperature[6]; - dtostrf(getDSTemperature(celsius), 1-sizeof(temperature), 1, temperature); - - // Debug - DEBUG_MSG_P(PSTR("[DS18B20] Temperature: %s%s\n"), temperature, celsius ? "ºC" : "ºF"); - - // If the new temperature is different from the last - if (fabs(_dsTemperature - last_temperature) >= TEMPERATURE_MIN_CHANGE) { - - last_temperature = _dsTemperature; - - // Send MQTT messages - #if MQTT_SUPPORT - mqttSend(getSetting("dsTmpTopic", DS18B20_TEMPERATURE_TOPIC).c_str(), temperature); - #endif - - // Send to Domoticz - #if DOMOTICZ_SUPPORT - domoticzSend("dczTmpIdx", 0, temperature); - #endif - - #if INFLUXDB_SUPPORT - idbSend(getSetting("dsTmpTopic", DS18B20_TEMPERATURE_TOPIC).c_str(), temperature); - #endif - - } - - // Update websocket clients - #if WEB_SUPPORT - wsSend(_dsWebSocketOnSend); - #endif - - } - -} - -#endif diff --git a/code/espurna/espurna.ino b/code/espurna/espurna.ino index 421e079b..074429cf 100644 --- a/code/espurna/espurna.ino +++ b/code/espurna/espurna.ino @@ -314,12 +314,6 @@ void setup() { #if INFLUXDB_SUPPORT idbSetup(); #endif - #if DS18B20_SUPPORT - dsSetup(); - #endif - #if COUNTER_SUPPORT - counterSetup(); - #endif #if RF_SUPPORT rfSetup(); #endif @@ -380,12 +374,6 @@ void loop() { #if NOFUSS_SUPPORT nofussLoop(); #endif - #if DS18B20_SUPPORT - dsLoop(); - #endif - #if COUNTER_SUPPORT - counterLoop(); - #endif #if RF_SUPPORT rfLoop(); #endif diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino index 52e6406f..506dd431 100644 --- a/code/espurna/sensor.ino +++ b/code/espurna/sensor.ino @@ -28,6 +28,7 @@ unsigned char _counts[MAGNITUDE_MAX]; bool _sensor_realtime = API_REAL_TIME_VALUES; unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS; double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION; +unsigned char _sensor_isr = 0xFF; // ----------------------------------------------------------------------------- // Private @@ -40,6 +41,8 @@ String _sensorTopic(magnitude_t type) { return String(SENSOR_HUMIDITY_TOPIC); } else if (type == MAGNITUDE_ANALOG) { return String(SENSOR_ANALOG_TOPIC); + } else if (type == MAGNITUDE_EVENTS) { + return String(SENSOR_EVENTS_TOPIC); } return String(SENSOR_UNKNOWN_TOPIC); } @@ -51,6 +54,8 @@ unsigned char _sensorDecimals(magnitude_t type) { return SENSOR_HUMIDITY_DECIMALS; } else if (type == MAGNITUDE_ANALOG) { return SENSOR_ANALOG_DECIMALS; + } else if (type == MAGNITUDE_EVENTS) { + return SENSOR_EVENTS_DECIMALS; } return 0; } @@ -64,6 +69,8 @@ String _sensorUnits(magnitude_t type) { } } else if (type == MAGNITUDE_HUMIDITY) { return String("%"); + } else if (type == MAGNITUDE_EVENTS) { + return String("/m"); } return String(); } @@ -138,22 +145,56 @@ void _sensorAPISetup() { // Values // ----------------------------------------------------------------------------- -void sensorSetup() { +void sensorISR() { + _sensors[_sensor_isr]->InterruptHandler(); +} + +void sensorRegister(BaseSensor * sensor) { + _sensors.push_back(sensor); +} + +unsigned char sensorCount() { + return _sensors.size(); +} + +void sensorInterrupt(unsigned char sensor_id, unsigned char gpio, int mode) { + _sensor_isr = sensor_id; + attachInterrupt(gpio, sensorISR, mode); +} + +void sensorInit() { - // Load sensors #if DHT_SUPPORT #include "sensors/DHTSensor.h" - _sensors.push_back(new DHTSensor(DHT_PIN, DHT_TYPE)); - #if DHT_PULLUP - pinMode(DHT_PIN, INPUT_PULLUP); - #endif + sensorRegister(new DHTSensor(DHT_PIN, DHT_TYPE, DHT_PULLUP)); + #endif + + #if DS18B20_SUPPORT + #include "sensors/DS18B20Sensor.h" + sensorRegister(new DS18B20Sensor(DS18B20_PIN, DS18B20_PULLUP)); #endif + #if ANALOG_SUPPORT #include "sensors/AnalogSensor.h" - _sensors.push_back(new AnalogSensor(ANALOG_PIN)); + sensorRegister(new AnalogSensor(ANALOG_PIN)); + #endif + + #if COUNTER_SUPPORT + if (_sensor_isr == 0xFF) { + #include "sensors/EventSensor.h" + sensorRegister(new EventSensor(COUNTER_PIN, COUNTER_PIN_MODE, COUNTER_DEBOUNCE)); + sensorInterrupt(sensorCount()-1, COUNTER_PIN, COUNTER_INTERRUPT_MODE); + } #endif - // Read magnitudes +} + +void sensorSetup() { + + // Load sensors + sensorInit(); + + // Load magnitudes for (unsigned char i=0; i<_sensors.size(); i++) { BaseSensor * sensor = _sensors[i]; @@ -234,6 +275,10 @@ void sensorLoop() { value = magnitude.sensor->value(magnitude.local); magnitude.filter->add(value); + + // Special case + if (magnitude.type == MAGNITUDE_EVENTS) value = magnitude.filter->result(); + value = _sensorProcess(magnitude.type, value); _magnitudes[i].current = value; @@ -252,7 +297,9 @@ void sensorLoop() { if (report_count == 0) { - double value = magnitude.filter->result(); + // TODO: option to report only if it has change (configurable amount) + + value = magnitude.filter->result(); value = _sensorProcess(magnitude.type, value); _magnitudes[i].filtered = value; magnitude.filter->reset(); diff --git a/code/espurna/sensors/AnalogSensor.h b/code/espurna/sensors/AnalogSensor.h index 59502f5a..ecbb8452 100644 --- a/code/espurna/sensors/AnalogSensor.h +++ b/code/espurna/sensors/AnalogSensor.h @@ -13,27 +13,7 @@ class AnalogSensor : public BaseSensor { AnalogSensor(unsigned char gpio): BaseSensor() { _gpio = gpio; - } - - // Pre-read hook (usually to populate registers with up-to-date data) - void pre() {} - - // Post-read hook (usually to reset things) - void post() {} - - // Return sensor status (true for ready) - bool status() { - return true; - } - - // Return sensor last internal error - int error() { - return 0; - } - - // Number of available slots - unsigned char count() { - return 1; + _count = 1; } // Descriptive name of the sensor @@ -61,7 +41,7 @@ class AnalogSensor : public BaseSensor { } - private: + protected: unsigned char _gpio; diff --git a/code/espurna/sensors/BaseSensor.h b/code/espurna/sensors/BaseSensor.h index da700088..92a4c252 100644 --- a/code/espurna/sensors/BaseSensor.h +++ b/code/espurna/sensors/BaseSensor.h @@ -31,26 +31,29 @@ class BaseSensor { public: - BaseSensor() { - } + // Constructor + BaseSensor() {} - ~BaseSensor() { - } + // Destructor + ~BaseSensor() {} + + // General interrupt handler + void InterruptHandler() {} // Pre-read hook (usually to populate registers with up-to-date data) - virtual void pre(); + void pre() {} // Post-read hook (usually to reset things) - virtual void post(); + void post() {} // Return sensor status (true for ready) - virtual bool status(); + bool status() { return _error == 0; } // Return sensor last internal error - virtual int error(); + int error() { return _error; } // Number of available slots - virtual unsigned char count(); + unsigned char count() { return _count; } // Descriptive name of the sensor virtual String name(); @@ -65,6 +68,10 @@ class BaseSensor { virtual double value(unsigned char index); - private: + protected: + + int _error = 0; + unsigned char _count = 0; + }; diff --git a/code/espurna/sensors/DHTSensor.h b/code/espurna/sensors/DHTSensor.h index b531a394..f1ac59f1 100644 --- a/code/espurna/sensors/DHTSensor.h +++ b/code/espurna/sensors/DHTSensor.h @@ -23,9 +23,11 @@ class DHTSensor : public BaseSensor { public: - DHTSensor(unsigned char gpio, unsigned char type): BaseSensor() { + DHTSensor(unsigned char gpio, unsigned char type, bool pull_up = false): BaseSensor() { _gpio = gpio; _type = type; + if (pull_up) pinMode(_gpio, INPUT_PULLUP); + _count = 2; } // Pre-read hook (usually to populate registers with up-to-date data) @@ -123,29 +125,9 @@ class DHTSensor : public BaseSensor { } - // Post-read hook (usually to reset things) - void post() { - - } - - // Return sensor status (true for ready) - bool status() { - return (_last_ok > 0) & (_error == 0); - } - - // Return sensor last internal error - int error() { - return _error; - } - - // Number of available slots - unsigned char count() { - return 2; - } - // Descriptive name of the sensor String name() { - char buffer[64]; + char buffer[20]; snprintf(buffer, sizeof(buffer), "DHT%d @ GPIO%d", _type, _gpio); return String(buffer); } @@ -170,7 +152,7 @@ class DHTSensor : public BaseSensor { } - private: + protected: unsigned long _signal(int usTimeOut, bool state) { unsigned long uSec = 1; @@ -183,7 +165,6 @@ class DHTSensor : public BaseSensor { unsigned char _gpio; unsigned char _type; - int _error; unsigned long _last_ok = 0; unsigned char _errors = 0; diff --git a/code/espurna/sensors/DS18B20Sensor.h b/code/espurna/sensors/DS18B20Sensor.h new file mode 100644 index 00000000..7f0f2b38 --- /dev/null +++ b/code/espurna/sensors/DS18B20Sensor.h @@ -0,0 +1,105 @@ +// ----------------------------------------------------------------------------- +// DHT Sensor +// ----------------------------------------------------------------------------- + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" +#include +#include + +#define DS18B20_OK 0 +#define DS18B20_NOT_FOUND 1 +#define DS18B20_OUT_OF_RANGE 2 +#define DS18B20_CONVERSION_ERROR 3 + +class DS18B20Sensor : public BaseSensor { + + public: + + DS18B20Sensor(unsigned char gpio, bool pull_up = false): BaseSensor() { + _gpio = gpio; + if (pull_up) pinMode(_gpio, INPUT_PULLUP); + init(); + } + + // Pre-read hook (usually to populate registers with up-to-date data) + void pre() { + + _device->requestTemperatures(); + + // TODO: enable? + /* + while (!_device->isConversionComplete()) { + delay(1); + } + */ + + } + + // Descriptive name of the sensor + String name() { + char buffer[20]; + snprintf(buffer, sizeof(buffer), "DS18B20 %s@ GPIO%d", + _device->isParasitePowerMode() ? "(P) " : "", + _gpio + ); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + if (index < _count) { + DeviceAddress address; + _device->getAddress(address, index); + char buffer[40]; + snprintf(buffer, sizeof(buffer), "%02X%02X%02X%02X%02X%02X%02X%02X @ %s", + address[0], address[1], address[2], address[3], + address[4], address[5], address[6], address[7], + name().c_str() + ); + return String(buffer); + } + _error = DS18B20_OUT_OF_RANGE; + return String(); + } + + // Type for slot # index + magnitude_t type(unsigned char index) { + if (index < _count) return MAGNITUDE_TEMPERATURE; + _error = DS18B20_OUT_OF_RANGE; + return MAGNITUDE_NONE; + } + + // Current value for slot # index + double value(unsigned char index) { + if (index < _count) { + double t = _device->getTempCByIndex(index); + if (t != DEVICE_DISCONNECTED_C) { + _error = DS18B20_OK; + return t; + } + _error = DS18B20_CONVERSION_ERROR; + } + _error = DS18B20_OUT_OF_RANGE; + return 0; + } + + protected: + + void init() { + OneWire * wire = new OneWire(_gpio); + _device = new DallasTemperature(wire); + _device->begin(); + _device->setWaitForConversion(false); + _count = _device->getDeviceCount(); + if (_count == 0) _error = DS18B20_NOT_FOUND; + } + + unsigned char _gpio; + + DallasTemperature * _device; + + +}; diff --git a/code/espurna/sensors/EventSensor.h b/code/espurna/sensors/EventSensor.h new file mode 100644 index 00000000..ad6dcccf --- /dev/null +++ b/code/espurna/sensors/EventSensor.h @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------------- +// DHT Sensor +// ----------------------------------------------------------------------------- + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" + +class EventSensor : public BaseSensor { + + public: + + void InterruptHandler() { + static unsigned long last = 0; + if (millis() - last > _debounce) { + _events = _events + 1; + last = millis(); + } + } + + EventSensor(unsigned char gpio, int pin_mode, unsigned long debounce): BaseSensor() { + _gpio = gpio; + _count = 1; + _debounce = debounce; + pinMode(_gpio, pin_mode); + } + + // Descriptive name of the sensor + String name() { + char buffer[20]; + snprintf(buffer, sizeof(buffer), "EVENT @ GPIO%d", _gpio); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return name(); + } + + // Type for slot # index + magnitude_t type(unsigned char index) { + if (index == 0) return MAGNITUDE_EVENTS; + return MAGNITUDE_NONE; + } + + // Current value for slot # index + double value(unsigned char index) { + double value = 0; + if (index == 0) { + value = _events; + _events = 0; + }; + return value; + } + + + protected: + + volatile unsigned long _events = 0; + unsigned long _debounce = 0; + unsigned char _gpio; + +}; diff --git a/code/html/custom.js b/code/html/custom.js index 8146ff5b..5b4a0160 100644 --- a/code/html/custom.js +++ b/code/html/custom.js @@ -31,6 +31,7 @@ function sensorType(type) { if (type == 1) return "Temperature"; if (type == 2) return "Humidity"; if (type == 11) return "Analog"; + if (type == 12) return "Events"; return null; }