Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

213 lines
6.1 KiB

// -----------------------------------------------------------------------------
// Abstract sensor class (other sensor classes extend this class)
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#pragma once
#include <Arduino.h>
#include <ArduinoJson.h>
typedef enum magnitude_t {
MAGNITUDE_NONE = 0,
MAGNITUDE_TEMPERATURE,
MAGNITUDE_HUMIDITY,
MAGNITUDE_PRESSURE,
MAGNITUDE_CURRENT,
MAGNITUDE_VOLTAGE,
MAGNITUDE_POWER_ACTIVE,
MAGNITUDE_POWER_APPARENT,
MAGNITUDE_POWER_REACTIVE,
MAGNITUDE_ENERGY,
MAGNITUDE_ENERGY_DELTA,
MAGNITUDE_POWER_FACTOR,
MAGNITUDE_ANALOG,
MAGNITUDE_DIGITAL,
MAGNITUDE_EVENTS,
MAGNITUDE_PM1dot0,
MAGNITUDE_PM2dot5,
MAGNITUDE_PM10,
MAGNITUDE_CO2,
MAGNITUDE_MAX,
} magnitude_t;
#define GPIO_NONE 0x99
#define SENSOR_ERROR_OK 0 // No error
#define SENSOR_ERROR_OUT_OF_RANGE 1 // Result out of sensor range
#define SENSOR_ERROR_WARM_UP 2 // Sensor is warming-up
#define SENSOR_ERROR_TIMEOUT 3 // Response from sensor timed out
#define SENSOR_ERROR_UNKNOWN_ID 4 // Sensor did not report a known ID
#define SENSOR_ERROR_CRC 5 // Sensor data corrupted
#define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address
class BaseSensor {
public:
// Constructor
BaseSensor() {}
// Destructor
~BaseSensor() {}
// Initialization method, must be idempotent
virtual void begin() {}
// Loop-like method, call it in your main loop
virtual void tick() {}
// Pre-read hook (usually to populate registers with up-to-date data)
virtual void pre() {}
// Post-read hook (usually to reset things)
virtual void post() {}
// Descriptive name of the sensor
virtual String description() {}
// Type for slot # index
virtual magnitude_t type(unsigned char index) {}
// Current value for slot # index
virtual double value(unsigned char index) {}
// Retrieve current instance configuration
virtual void getConfig(JsonObject& root) {};
// Save current instance configuration
virtual void setConfig(JsonObject& root) {};
// Load the configuration manifest
static void manifest(JsonArray& root) {};
// Descriptive name of the slot # index
String slot(unsigned char index) { return description(); }
// Sensor ID
unsigned char getID() { return _sensor_id; };
// Specific for I2C sensors
unsigned char lock_i2c(unsigned char address, size_t size, unsigned char * addresses) {
// Check if we should release a previously locked address
if (_previous_address != address) {
i2cReleaseLock(_previous_address);
}
// If we have already an address, check it is not locked
if (address && !i2cGetLock(address)) {
_error = SENSOR_ERROR_I2C;
// If we don't have an address...
} else {
// Trigger auto-discover
address = i2cFindAndLock(size, addresses);
// If still nothing exit with error
if (address == 0) _error = SENSOR_ERROR_I2C;
}
_previous_address = address;
return address;
}
// Interrupt attach callback
void attached(unsigned char gpio) {
#if SENSOR_DEBUG
DEBUG_MSG("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, description().c_str());
#endif
}
// Interrupt detach callback
void detached(unsigned char gpio) {
#if SENSOR_DEBUG
DEBUG_MSG("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, description().c_str());
#endif
}
// Return sensor status (true for ready)
bool status() { return _error == 0; }
// Return sensor last internal error
int error() { return _error; }
// Number of available slots
unsigned char count() { return _count; }
// Handle interrupt calls
virtual void handleInterrupt(unsigned char gpio) {}
protected:
// Attach interrupt
void attach(BaseSensor * instance, unsigned char gpio, unsigned char mode);
// Detach interrupt
void detach(unsigned char gpio);
unsigned char _sensor_id = 0x00;
int _error = 0;
bool _dirty = true;
unsigned char _count = 0;
// I2C
unsigned char _previous_address = 0;
unsigned char _address = 0;
};
// -----------------------------------------------------------------------------
// Interrupt helpers
// -----------------------------------------------------------------------------
BaseSensor * _isr_sensor_instance[16] = {NULL};
void _sensor_isr(unsigned char gpio) {
if (_isr_sensor_instance[gpio]) {
_isr_sensor_instance[gpio]->handleInterrupt(gpio);
}
}
void _sensor_isr_0() { _sensor_isr(0); }
void _sensor_isr_2() { _sensor_isr(2); }
void _sensor_isr_4() { _sensor_isr(4); }
void _sensor_isr_5() { _sensor_isr(5); }
void _sensor_isr_12() { _sensor_isr(12); }
void _sensor_isr_13() { _sensor_isr(13); }
void _sensor_isr_14() { _sensor_isr(14); }
void _sensor_isr_15() { _sensor_isr(15); }
void (*_sensor_isrs[16])() = {
_sensor_isr_0, NULL, _sensor_isr_2, NULL, _sensor_isr_4, _sensor_isr_5,
NULL, NULL, NULL, NULL, NULL, NULL,
_sensor_isr_12, _sensor_isr_13, _sensor_isr_14, _sensor_isr_15
};
void BaseSensor::attach(BaseSensor * instance, unsigned char gpio, unsigned char mode) {
detach(gpio);
if (_sensor_isrs[gpio]) {
_isr_sensor_instance[gpio] = instance;
attachInterrupt(gpio, _sensor_isrs[gpio], mode);
instance->attached(gpio);
}
}
void BaseSensor::detach(unsigned char gpio) {
if (_isr_sensor_instance[gpio]) {
detachInterrupt(gpio);
_isr_sensor_instance[gpio]->detached(gpio);
_isr_sensor_instance[gpio] = NULL;
}
}