Browse Source

Migrate DS18B20 and counter to new sensor module

fastled
Xose Pérez 7 years ago
parent
commit
b2dd7e5b56
14 changed files with 257 additions and 603 deletions
  1. +2
    -0
      code/espurna/config/general.h
  2. +1
    -0
      code/espurna/config/prototypes.h
  3. +4
    -4
      code/espurna/config/sensors.h
  4. +0
    -103
      code/espurna/counter.ino
  5. +0
    -272
      code/espurna/dht.ino
  6. +0
    -147
      code/espurna/ds18b20.ino
  7. +0
    -12
      code/espurna/espurna.ino
  8. +56
    -9
      code/espurna/sensor.ino
  9. +2
    -22
      code/espurna/sensors/AnalogSensor.h
  10. +17
    -10
      code/espurna/sensors/BaseSensor.h
  11. +5
    -24
      code/espurna/sensors/DHTSensor.h
  12. +105
    -0
      code/espurna/sensors/DS18B20Sensor.h
  13. +64
    -0
      code/espurna/sensors/EventSensor.h
  14. +1
    -0
      code/html/custom.js

+ 2
- 0
code/espurna/config/general.h View File

@ -758,11 +758,13 @@ PROGMEM const char* const custom_reset_string[] = {
#define SENSOR_TEMPERATURE_DECIMALS 1 #define SENSOR_TEMPERATURE_DECIMALS 1
#define SENSOR_HUMIDITY_DECIMALS 0 #define SENSOR_HUMIDITY_DECIMALS 0
#define SENSOR_ANALOG_DECIMALS 0 #define SENSOR_ANALOG_DECIMALS 0
#define SENSOR_EVENTS_DECIMALS 0
#define SENSOR_UNKNOWN_TOPIC "unknown" #define SENSOR_UNKNOWN_TOPIC "unknown"
#define SENSOR_TEMPERATURE_TOPIC "temperature" #define SENSOR_TEMPERATURE_TOPIC "temperature"
#define SENSOR_HUMIDITY_TOPIC "humidity" #define SENSOR_HUMIDITY_TOPIC "humidity"
#define SENSOR_ANALOG_TOPIC "analog" #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_UNITS TMP_CELSIUS // Temperature units (TMP_CELSIUS | TMP_FAHRENHEIT)
#define SENSOR_TEMPERATURE_CORRECTION 0.0 // Offset correction #define SENSOR_TEMPERATURE_CORRECTION 0.0 // Offset correction


+ 1
- 0
code/espurna/config/prototypes.h View File

@ -75,6 +75,7 @@ template<typename T> bool idbSend(const char * topic, unsigned char id, T payloa
// Sensors // Sensors
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#include "sensors/BaseSensor.h" #include "sensors/BaseSensor.h"
#include <DallasTemperature.h> // WTF!
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Utils // Utils


+ 4
- 4
code/espurna/config/sensors.h View File

@ -35,7 +35,7 @@
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
#ifndef DHT_SUPPORT #ifndef DHT_SUPPORT
#define DHT_SUPPORT 1
#define DHT_SUPPORT 0
#endif #endif
#ifndef DHT_PIN #ifndef DHT_PIN
@ -92,7 +92,7 @@
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
#ifndef COUNTER_SUPPORT #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 #endif
#ifndef COUNTER_PIN #ifndef COUNTER_PIN
@ -121,11 +121,11 @@
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
#ifndef DS18B20_SUPPORT #ifndef DS18B20_SUPPORT
#define DS18B20_SUPPORT 0
#define DS18B20_SUPPORT 1
#endif #endif
#ifndef DS18B20_PIN #ifndef DS18B20_PIN
#define DS18B20_PIN 14
#define DS18B20_PIN 13
#endif #endif
#ifndef DS18B20_PULLUP #ifndef DS18B20_PULLUP


+ 0
- 103
code/espurna/counter.ino View File

@ -1,103 +0,0 @@
/*
COUNTER MODULE
Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#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

+ 0
- 272
code/espurna/dht.ino View File

@ -1,272 +0,0 @@
/*
DHT MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#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

+ 0
- 147
code/espurna/ds18b20.ino View File

@ -1,147 +0,0 @@
/*
DS18B20 MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if DS18B20_SUPPORT
#include <OneWire.h>
#include <DallasTemperature.h>
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

+ 0
- 12
code/espurna/espurna.ino View File

@ -314,12 +314,6 @@ void setup() {
#if INFLUXDB_SUPPORT #if INFLUXDB_SUPPORT
idbSetup(); idbSetup();
#endif #endif
#if DS18B20_SUPPORT
dsSetup();
#endif
#if COUNTER_SUPPORT
counterSetup();
#endif
#if RF_SUPPORT #if RF_SUPPORT
rfSetup(); rfSetup();
#endif #endif
@ -380,12 +374,6 @@ void loop() {
#if NOFUSS_SUPPORT #if NOFUSS_SUPPORT
nofussLoop(); nofussLoop();
#endif #endif
#if DS18B20_SUPPORT
dsLoop();
#endif
#if COUNTER_SUPPORT
counterLoop();
#endif
#if RF_SUPPORT #if RF_SUPPORT
rfLoop(); rfLoop();
#endif #endif


+ 56
- 9
code/espurna/sensor.ino View File

@ -28,6 +28,7 @@ unsigned char _counts[MAGNITUDE_MAX];
bool _sensor_realtime = API_REAL_TIME_VALUES; bool _sensor_realtime = API_REAL_TIME_VALUES;
unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS; unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS;
double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION; double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION;
unsigned char _sensor_isr = 0xFF;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Private // Private
@ -40,6 +41,8 @@ String _sensorTopic(magnitude_t type) {
return String(SENSOR_HUMIDITY_TOPIC); return String(SENSOR_HUMIDITY_TOPIC);
} else if (type == MAGNITUDE_ANALOG) { } else if (type == MAGNITUDE_ANALOG) {
return String(SENSOR_ANALOG_TOPIC); return String(SENSOR_ANALOG_TOPIC);
} else if (type == MAGNITUDE_EVENTS) {
return String(SENSOR_EVENTS_TOPIC);
} }
return String(SENSOR_UNKNOWN_TOPIC); return String(SENSOR_UNKNOWN_TOPIC);
} }
@ -51,6 +54,8 @@ unsigned char _sensorDecimals(magnitude_t type) {
return SENSOR_HUMIDITY_DECIMALS; return SENSOR_HUMIDITY_DECIMALS;
} else if (type == MAGNITUDE_ANALOG) { } else if (type == MAGNITUDE_ANALOG) {
return SENSOR_ANALOG_DECIMALS; return SENSOR_ANALOG_DECIMALS;
} else if (type == MAGNITUDE_EVENTS) {
return SENSOR_EVENTS_DECIMALS;
} }
return 0; return 0;
} }
@ -64,6 +69,8 @@ String _sensorUnits(magnitude_t type) {
} }
} else if (type == MAGNITUDE_HUMIDITY) { } else if (type == MAGNITUDE_HUMIDITY) {
return String("%"); return String("%");
} else if (type == MAGNITUDE_EVENTS) {
return String("/m");
} }
return String(); return String();
} }
@ -138,22 +145,56 @@ void _sensorAPISetup() {
// Values // 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 #if DHT_SUPPORT
#include "sensors/DHTSensor.h" #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 #endif
#if ANALOG_SUPPORT #if ANALOG_SUPPORT
#include "sensors/AnalogSensor.h" #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 #endif
// Read magnitudes
}
void sensorSetup() {
// Load sensors
sensorInit();
// Load magnitudes
for (unsigned char i=0; i<_sensors.size(); i++) { for (unsigned char i=0; i<_sensors.size(); i++) {
BaseSensor * sensor = _sensors[i]; BaseSensor * sensor = _sensors[i];
@ -234,6 +275,10 @@ void sensorLoop() {
value = magnitude.sensor->value(magnitude.local); value = magnitude.sensor->value(magnitude.local);
magnitude.filter->add(value); magnitude.filter->add(value);
// Special case
if (magnitude.type == MAGNITUDE_EVENTS) value = magnitude.filter->result();
value = _sensorProcess(magnitude.type, value); value = _sensorProcess(magnitude.type, value);
_magnitudes[i].current = value; _magnitudes[i].current = value;
@ -252,7 +297,9 @@ void sensorLoop() {
if (report_count == 0) { 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); value = _sensorProcess(magnitude.type, value);
_magnitudes[i].filtered = value; _magnitudes[i].filtered = value;
magnitude.filter->reset(); magnitude.filter->reset();


+ 2
- 22
code/espurna/sensors/AnalogSensor.h View File

@ -13,27 +13,7 @@ class AnalogSensor : public BaseSensor {
AnalogSensor(unsigned char gpio): BaseSensor() { AnalogSensor(unsigned char gpio): BaseSensor() {
_gpio = gpio; _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 // Descriptive name of the sensor
@ -61,7 +41,7 @@ class AnalogSensor : public BaseSensor {
} }
private:
protected:
unsigned char _gpio; unsigned char _gpio;


+ 17
- 10
code/espurna/sensors/BaseSensor.h View File

@ -31,26 +31,29 @@ class BaseSensor {
public: public:
BaseSensor() {
}
// Constructor
BaseSensor() {}
~BaseSensor() {
}
// Destructor
~BaseSensor() {}
// General interrupt handler
void InterruptHandler() {}
// Pre-read hook (usually to populate registers with up-to-date data) // Pre-read hook (usually to populate registers with up-to-date data)
virtual void pre();
void pre() {}
// Post-read hook (usually to reset things) // Post-read hook (usually to reset things)
virtual void post();
void post() {}
// Return sensor status (true for ready) // Return sensor status (true for ready)
virtual bool status();
bool status() { return _error == 0; }
// Return sensor last internal error // Return sensor last internal error
virtual int error();
int error() { return _error; }
// Number of available slots // Number of available slots
virtual unsigned char count();
unsigned char count() { return _count; }
// Descriptive name of the sensor // Descriptive name of the sensor
virtual String name(); virtual String name();
@ -65,6 +68,10 @@ class BaseSensor {
virtual double value(unsigned char index); virtual double value(unsigned char index);
private:
protected:
int _error = 0;
unsigned char _count = 0;
}; };

+ 5
- 24
code/espurna/sensors/DHTSensor.h View File

@ -23,9 +23,11 @@ class DHTSensor : public BaseSensor {
public: public:
DHTSensor(unsigned char gpio, unsigned char type): BaseSensor() {
DHTSensor(unsigned char gpio, unsigned char type, bool pull_up = false): BaseSensor() {
_gpio = gpio; _gpio = gpio;
_type = type; _type = type;
if (pull_up) pinMode(_gpio, INPUT_PULLUP);
_count = 2;
} }
// Pre-read hook (usually to populate registers with up-to-date data) // 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 // Descriptive name of the sensor
String name() { String name() {
char buffer[64];
char buffer[20];
snprintf(buffer, sizeof(buffer), "DHT%d @ GPIO%d", _type, _gpio); snprintf(buffer, sizeof(buffer), "DHT%d @ GPIO%d", _type, _gpio);
return String(buffer); return String(buffer);
} }
@ -170,7 +152,7 @@ class DHTSensor : public BaseSensor {
} }
private:
protected:
unsigned long _signal(int usTimeOut, bool state) { unsigned long _signal(int usTimeOut, bool state) {
unsigned long uSec = 1; unsigned long uSec = 1;
@ -183,7 +165,6 @@ class DHTSensor : public BaseSensor {
unsigned char _gpio; unsigned char _gpio;
unsigned char _type; unsigned char _type;
int _error;
unsigned long _last_ok = 0; unsigned long _last_ok = 0;
unsigned char _errors = 0; unsigned char _errors = 0;


+ 105
- 0
code/espurna/sensors/DS18B20Sensor.h View File

@ -0,0 +1,105 @@
// -----------------------------------------------------------------------------
// DHT Sensor
// -----------------------------------------------------------------------------
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#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;
};

+ 64
- 0
code/espurna/sensors/EventSensor.h View File

@ -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;
};

+ 1
- 0
code/html/custom.js View File

@ -31,6 +31,7 @@ function sensorType(type) {
if (type == 1) return "Temperature"; if (type == 1) return "Temperature";
if (type == 2) return "Humidity"; if (type == 2) return "Humidity";
if (type == 11) return "Analog"; if (type == 11) return "Analog";
if (type == 12) return "Events";
return null; return null;
} }


Loading…
Cancel
Save