Browse Source

Merge branch 'Trickx-dev' into dev

fastled^2
Xose Pérez 6 years ago
parent
commit
328d8f44d1
18 changed files with 2404 additions and 2028 deletions
  1. +3
    -3
      README.md
  2. +1
    -0
      code/espurna/config/arduino.h
  3. +6
    -0
      code/espurna/config/hardware.h
  4. +11
    -4
      code/espurna/config/progmem.h
  5. +35
    -1
      code/espurna/config/sensors.h
  6. +4
    -1
      code/espurna/config/types.h
  7. BIN
      code/espurna/data/index.html.gz
  8. +14
    -1
      code/espurna/sensor.ino
  9. +298
    -0
      code/espurna/sensors/GeigerSensor.h
  10. +2018
    -2016
      code/espurna/static/index.html.gz.h
  11. +3
    -2
      code/html/custom.js
  12. +11
    -0
      code/platformio.ini
  13. BIN
      images/devices/geiger_espurna_configuration.png
  14. BIN
      images/devices/geiger_espurna_status.png
  15. BIN
      images/devices/geiger_grafana_dashboard.png
  16. BIN
      images/devices/geiger_scope_following_pulses.png
  17. BIN
      images/devices/geiger_scope_single_pulse.png
  18. BIN
      images/devices/geiger_wiring_diagram.png

+ 3
- 3
README.md View File

@ -4,9 +4,9 @@ ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smar
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
[![version](https://img.shields.io/badge/version-1.13.0c-brightgreen.svg)](CHANGELOG.md)
[![branch](https://img.shields.io/badge/branch-dev-orange.svg)](https://github.org/xoseperez/espurna/tree/dev/)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/dev.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
[![branch](https://img.shields.io/badge/branch-Trickx-dev-orange.svg)](https://github.org/xoseperez/espurna/tree/Trickx-dev/)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=Trickx-dev)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/Trickx-dev.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
[![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE)
<br />
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)


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

@ -145,3 +145,4 @@
//#define SI7021_SUPPORT 1
//#define TMP3X_SUPPORT 1
//#define V9261F_SUPPORT 1
//#define GEIGER_SUPPORT 1

+ 6
- 0
code/espurna/config/hardware.h View File

@ -70,6 +70,12 @@
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
#elif defined(NODEMCU_BASIC)
// Info
// Generic NodeMCU Board without any buttons or relays connected.
#define MANUFACTURER "NODEMCU"
#define DEVICE "BASIC"
#elif defined(WEMOS_D1_MINI_RELAYSHIELD)
// Info


+ 11
- 4
code/espurna/config/progmem.h View File

@ -35,7 +35,8 @@ PROGMEM const unsigned char magnitude_decimals[] = {
3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 3, 3
0, 0, 3, 3,
4, 4 // Geiger Counter decimals
};
PROGMEM const char magnitude_unknown_topic[] = "unknown";
@ -61,6 +62,8 @@ PROGMEM const char magnitude_lux_topic[] = "lux";
PROGMEM const char magnitude_uv_topic[] = "uv";
PROGMEM const char magnitude_distance_topic[] = "distance";
PROGMEM const char magnitude_hcho_topic[] = "hcho";
PROGMEM const char magnitude_geiger_cpm_topic[] = "ldr_cpm"; // local dose rate [Counts per minute]
PROGMEM const char magnitude_geiger_sv_topic[] = "ldr_uSvh"; // local dose rate [µSievert per hour]
PROGMEM const char* const magnitude_topics[] = {
magnitude_unknown_topic, magnitude_temperature_topic, magnitude_humidity_topic,
@ -70,7 +73,8 @@ PROGMEM const char* const magnitude_topics[] = {
magnitude_analog_topic, magnitude_digital_topic, magnitude_events_topic,
magnitude_pm1dot0_topic, magnitude_pm2dot5_topic, magnitude_pm10_topic,
magnitude_co2_topic, magnitude_lux_topic, magnitude_uv_topic,
magnitude_distance_topic, magnitude_hcho_topic
magnitude_distance_topic, magnitude_hcho_topic,
magnitude_geiger_cpm_topic, magnitude_geiger_sv_topic // Geiger Counter topics
};
PROGMEM const char magnitude_empty[] = "";
@ -90,6 +94,9 @@ PROGMEM const char magnitude_lux[] = "lux";
PROGMEM const char magnitude_uv[] = "uv";
PROGMEM const char magnitude_distance[] = "m";
PROGMEM const char magnitude_mgm3[] = "mg/m³";
PROGMEM const char magnitude_geiger_cpm[] = "cpm"; // Counts per Minute: Unit of local dose rate (Geiger counting)
PROGMEM const char magnitude_geiger_sv[] = "µSv/h"; // µSievert per hour: 2nd unit of local dose rate (Geiger counting)
PROGMEM const char* const magnitude_units[] = {
magnitude_empty, magnitude_celsius, magnitude_percentage,
@ -99,8 +106,8 @@ PROGMEM const char* const magnitude_units[] = {
magnitude_empty, magnitude_empty, magnitude_empty,
magnitude_ugm3, magnitude_ugm3, magnitude_ugm3,
magnitude_ppm, magnitude_lux, magnitude_uv,
magnitude_distance, magnitude_mgm3
magnitude_distance, magnitude_mgm3,
magnitude_geiger_cpm, magnitude_geiger_sv // Geiger counter units
};
#endif

+ 35
- 1
code/espurna/config/sensors.h View File

@ -285,7 +285,36 @@
#define EVENTS_INTERRUPT_MODE RISING // RISING, FALLING, BOTH
#endif
#define EVENTS_DEBOUNCE 50 // Do not register events within less than 10 millis
#define EVENTS_DEBOUNCE 50 // Do not register events within less than 50 millis
//------------------------------------------------------------------------------
// Geiger sensor
// Enable support by passing GEIGER_SUPPORT=1 build flag
//------------------------------------------------------------------------------
#ifndef GEIGER_SUPPORT
#define GEIGER_SUPPORT 0 // Do not build with geiger support by default
#endif
#ifndef GEIGER_PIN
#define GEIGER_PIN D1 // GPIO to monitor "D1" => "GPIO5"
#endif
#ifndef GEIGER_PIN_MODE
#define GEIGER_PIN_MODE INPUT // INPUT, INPUT_PULLUP
#endif
#ifndef GEIGER_INTERRUPT_MODE
#define GEIGER_INTERRUPT_MODE RISING // RISING, FALLING, BOTH
#endif
#define GEIGER_DEBOUNCE 25 // Do not register events within less than 25 millis.
// Value derived here: Debounce time 25ms, because https://github.com/Trickx/espurna/wiki/Geiger-counter
#define GEIGER_CPM2SIEVERT 240 // CPM to µSievert per hour conversion factor
// Typically the literature uses the invers, but I find an integer type more convienient.
#define GEIGER_REPORT_SIEVERTS 1 // Enabler for local dose rate reports in µSv/h
#define GEIGER_REPORT_CPM 1 // Enabler for local dose rate reports in counts per minute
//------------------------------------------------------------------------------
// GUVAS12SD UV Sensor (analog)
@ -527,6 +556,7 @@
EMON_ADS1X15_SUPPORT || \
EMON_ANALOG_SUPPORT || \
EVENTS_SUPPORT || \
GEIGER_SUPPORT || \
GUVAS12SD_SUPPORT || \
HCSR04_SUPPORT || \
HLW8012_SUPPORT || \
@ -639,6 +669,10 @@
#include "../sensors/EventSensor.h"
#endif
#if GEIGER_SUPPORT
#include "../sensors/GeigerSensor.h" // The main file for geiger counting module
#endif
#if GUVAS12SD_SUPPORT
#include "../sensors/GUVAS12SDSensor.h"
#endif


+ 4
- 1
code/espurna/config/types.h View File

@ -267,6 +267,7 @@
#define SENSOR_TMP3X_ID 0x22
#define SENSOR_HCSR04_ID 0x23
#define SENSOR_SENSEAIR_ID 0x24
#define SENSOR_GEIGER_ID 0x25
//--------------------------------------------------------------------------------
// Magnitudes
@ -295,5 +296,7 @@
#define MAGNITUDE_UV 20
#define MAGNITUDE_DISTANCE 21
#define MAGNITUDE_HCHO 22
#define MAGNITUDE_GEIGER_CPM 23
#define MAGNITUDE_GEIGER_SIEVERT 24
#define MAGNITUDE_MAX 23
#define MAGNITUDE_MAX 25

BIN
code/espurna/data/index.html.gz View File


+ 14
- 1
code/espurna/sensor.ino View File

@ -59,6 +59,7 @@ unsigned char _magnitudeDecimals(unsigned char type) {
type == MAGNITUDE_POWER_REACTIVE) {
if (_sensor_power_units == POWER_KILOWATTS) return 3;
}
if (type == MAGNITUDE_GEIGER_SIEVERT) return 4; // TODO: Is this required? "magnitude_decimals" are defined in progmem.h
if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type);
return 0;
@ -450,6 +451,18 @@ void _sensorLoad() {
}
#endif
#if GEIGER_SUPPORT
{
GeigerSensor * sensor = new GeigerSensor(); // Create instance of thr Geiger module.
sensor->setGPIO(GEIGER_PIN); // Interrupt pin of the attached geiger counter board.
sensor->setMode(GEIGER_PIN_MODE); // This pin is an input.
sensor->setDebounceTime(GEIGER_DEBOUNCE); // Debounce time 25ms, because https://github.com/Trickx/espurna/wiki/Geiger-counter
sensor->setInterruptMode(GEIGER_INTERRUPT_MODE); // Interrupt triggering: edge detection rising.
sensor->setCPM2SievertFactor(GEIGER_CPM2SIEVERT); // Conversion factor from counts per minute to µSv/h
_sensors.push_back(sensor);
}
#endif
#if GUVAS12SD_SUPPORT
{
GUVAS12SDSensor * sensor = new GUVAS12SDSensor();
@ -592,7 +605,7 @@ void _sensorInit() {
new_magnitude.min_change = 0;
if (type == MAGNITUDE_DIGITAL) {
new_magnitude.filter = new MaxFilter();
} else if (type == MAGNITUDE_EVENTS) {
} else if (type == MAGNITUDE_EVENTS || type == MAGNITUDE_GEIGER_CPM|| type == MAGNITUDE_GEIGER_SIEVERT) { // For geiger counting moving average filter is the most appropriate if needed at all.
new_magnitude.filter = new MovingAverageFilter();
} else {
new_magnitude.filter = new MedianFilter();


+ 298
- 0
code/espurna/sensors/GeigerSensor.h View File

@ -0,0 +1,298 @@
// -----------------------------------------------------------------------------
// Geiger Sensor based on Event Counter Sensor
// Copyright (C) 2018 by Sven Kopetzki <skopetzki at web dot de>
// Documentation: https://github.com/Trickx/espurna/wiki/Geiger-counter
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && GEIGER_SUPPORT
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
class GeigerSensor : public BaseSensor {
public:
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
GeigerSensor() : BaseSensor() {
_count = 2;
_sensor_id = SENSOR_GEIGER_ID;
}
~GeigerSensor() {
_enableInterrupts(false);
}
// ---------------------------------------------------------------------
void setGPIO(unsigned char gpio) {
_gpio = gpio;
}
void setMode(unsigned char mode) {
_mode = mode;
}
void setInterruptMode(unsigned char mode) {
_interrupt_mode = mode;
}
void setDebounceTime(unsigned long debounce) {
_debounce = debounce;
}
void setCPM2SievertFactor(unsigned int cpm2sievert) {
_cpm2sievert = cpm2sievert;
}
// ---------------------------------------------------------------------
unsigned char getGPIO() {
return _gpio;
}
unsigned char getMode() {
return _mode;
}
unsigned char getInterruptMode() {
return _interrupt_mode;
}
unsigned long getDebounceTime() {
return _debounce;
}
unsigned long getCPM2SievertFactor() {
return _cpm2sievert;
}
// ---------------------------------------------------------------------
// Sensors API
// ---------------------------------------------------------------------
// Initialization method, must be idempotent
// Defined outside the class body
void begin() {
pinMode(_gpio, _mode);
_enableInterrupts(true);
_ready = true;
}
// Descriptive name of the sensor
String description() {
char buffer[20];
snprintf(buffer, sizeof(buffer), "µSv/h @ GPIO%d", _gpio);
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
char buffer[30];
unsigned char i=0;
#if GEIGER_REPORT_CPM
if (index == i++) {
snprintf(buffer, sizeof(buffer), "Counts per Minute @ GPIO%d", _gpio);
return String(buffer);
}
#endif
#if GEIGER_REPORT_SIEVERTS
if (index == i++) {
snprintf(buffer, sizeof(buffer), "CPM / %d = µSv/h", _cpm2sievert);
return String(buffer);
}
#endif
snprintf(buffer, sizeof(buffer), "Events @ GPIO%d", _gpio);
return String(buffer);
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_gpio);
}
// Type for slot # index
unsigned char type(unsigned char index) {
unsigned char i=0;
#if GEIGER_REPORT_CPM
if (index == i++) return MAGNITUDE_GEIGER_CPM;
#endif
#if GEIGER_REPORT_SIEVERTS
if (index == i++) return MAGNITUDE_GEIGER_SIEVERT;
#endif
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
unsigned char i=0;
#if GEIGER_REPORT_CPM
if (index == i++) {
unsigned long _period_begin = _lastreport_cpm;
_lastreport_cpm = millis();
double value = _events * 60000;
value = value / (_lastreport_cpm-_period_begin);
#if SENSOR_DEBUG
char data[128]; char buffer[10];
dtostrf(value, 1-sizeof(buffer), 4, buffer);
snprintf(data, sizeof(data), "Ticks: %u | Interval: %u | CPM: %s", _ticks, (_lastreport_cpm-_period_begin), buffer);
DEBUG_MSG("[GEIGER] %s\n", data);
#endif
_events = 0;
return value;
}
#endif
#if GEIGER_REPORT_SIEVERTS
if (index == i++) {
unsigned long _period_begin = _lastreport_sv;
_lastreport_sv = millis();
double value = _ticks * 60000 / _cpm2sievert;
value = value / (_lastreport_sv-_period_begin);
#if SENSOR_DEBUG
char data[128]; char buffer[10];
dtostrf(value, 1-sizeof(buffer), 4, buffer);
snprintf(data, sizeof(data), "Ticks: %u | Interval: %u | µSievert: %s", _ticks, (_lastreport_sv-_period_begin), buffer);
DEBUG_MSG("[GEIGER] %s\n", data);
#endif
_ticks = 0;
return value;
}
#endif
return 0;
}
// Handle interrupt calls
void handleInterrupt(unsigned char gpio) {
(void) gpio;
static unsigned long last = 0;
if (millis() - last > _debounce) {
_events = _events + 1;
_ticks = _ticks + 1;
last = millis();
}
}
protected:
// ---------------------------------------------------------------------
// Interrupt management
// ---------------------------------------------------------------------
void _attach(GeigerSensor * instance, unsigned char gpio, unsigned char mode);
void _detach(unsigned char gpio);
void _enableInterrupts(bool value) {
static unsigned char _interrupt_gpio = GPIO_NONE;
if (value) {
if (_interrupt_gpio != GPIO_NONE) _detach(_interrupt_gpio);
_attach(this, _gpio, _interrupt_mode);
_interrupt_gpio = _gpio;
} else if (_interrupt_gpio != GPIO_NONE) {
_detach(_interrupt_gpio);
_interrupt_gpio = GPIO_NONE;
}
}
// ---------------------------------------------------------------------
// Protected
// ---------------------------------------------------------------------
volatile unsigned long _events = 0;
volatile unsigned long _ticks = 0;
unsigned long _debounce = GEIGER_DEBOUNCE;
unsigned int _cpm2sievert = GEIGER_CPM2SIEVERT;
unsigned char _gpio;
unsigned char _mode;
unsigned char _interrupt_mode;
// Added for µSievert calculations
unsigned long _lastreport_cpm = millis();
unsigned long _lastreport_sv = _lastreport_cpm;
};
// -----------------------------------------------------------------------------
// Interrupt helpers
// -----------------------------------------------------------------------------
GeigerSensor * _geiger_sensor_instance[10] = {NULL};
void ICACHE_RAM_ATTR _geiger_sensor_isr(unsigned char gpio) {
unsigned char index = gpio > 5 ? gpio-6 : gpio;
if (_geiger_sensor_instance[index]) {
_geiger_sensor_instance[index]->handleInterrupt(gpio);
}
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_0() {
_geiger_sensor_isr(0);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_1() {
_geiger_sensor_isr(1);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_2() {
_geiger_sensor_isr(2);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_3() {
_geiger_sensor_isr(3);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_4() {
_geiger_sensor_isr(4);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_5() {
_geiger_sensor_isr(5);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_12() {
_geiger_sensor_isr(12);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_13() {
_geiger_sensor_isr(13);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_14() {
_geiger_sensor_isr(14);
}
void ICACHE_RAM_ATTR _geiger_sensor_isr_15() {
_geiger_sensor_isr(15);
}
static void (*_geiger_sensor_isr_list[10])() = {
_geiger_sensor_isr_0, _geiger_sensor_isr_1, _geiger_sensor_isr_2,
_geiger_sensor_isr_3, _geiger_sensor_isr_4, _geiger_sensor_isr_5,
_geiger_sensor_isr_12, _geiger_sensor_isr_13, _geiger_sensor_isr_14,
_geiger_sensor_isr_15
};
void GeigerSensor::_attach(GeigerSensor * instance, unsigned char gpio, unsigned char mode) {
if (!gpioValid(gpio)) return;
_detach(gpio);
unsigned char index = gpio > 5 ? gpio-6 : gpio;
_geiger_sensor_instance[index] = instance;
attachInterrupt(gpio, _geiger_sensor_isr_list[index], mode);
#if SENSOR_DEBUG
DEBUG_MSG_P(PSTR("[GEIGER] GPIO%d interrupt attached to %s\n"), gpio, instance->description().c_str());
#endif
}
void GeigerSensor::_detach(unsigned char gpio) {
if (!gpioValid(gpio)) return;
unsigned char index = gpio > 5 ? gpio-6 : gpio;
if (_geiger_sensor_instance[index]) {
detachInterrupt(gpio);
#if SENSOR_DEBUG
DEBUG_MSG_P(PSTR("[GEIGER] GPIO%d interrupt detached from %s\n"), gpio, _geiger_sensor_instance[index]->description().c_str());
#endif
_geiger_sensor_instance[index] = NULL;
}
}
#endif // SENSOR_SUPPORT && GEIGER_SUPPORT

+ 2018
- 2016
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 3
- 2
code/html/custom.js View File

@ -40,7 +40,7 @@ function sensorName(id) {
"HLW8012", "V9261F", "ECH1560", "Analog", "Digital",
"Events", "PMSX003", "BMX280", "MHZ19", "SI7021",
"SHT3X I2C", "BH1750", "PZEM004T", "AM2320 I2C", "GUVAS12SD",
"TMP3X", "HC-SR04", "SenseAir"
"TMP3X", "HC-SR04", "SenseAir", "GeigerTicks", "GeigerCPM"
];
if (1 <= id && id <= names.length) {
return names[id - 1];
@ -54,7 +54,8 @@ function magnitudeType(type) {
"Current", "Voltage", "Active Power", "Apparent Power",
"Reactive Power", "Power Factor", "Energy", "Energy (delta)",
"Analog", "Digital", "Events",
"PM1.0", "PM2.5", "PM10", "CO2", "Lux", "UV", "Distance" , "HCHO"
"PM1.0", "PM2.5", "PM10", "CO2", "Lux", "UV", "Distance" , "HCHO",
"Local Dose Rate", "Local Dose Rate"
];
if (1 <= type && type <= types.length) {
return types[type - 1];


+ 11
- 0
code/platformio.ini View File

@ -2227,3 +2227,14 @@ upload_speed = 115200
upload_port = "${env.ESPURNA_IP}"
upload_flags = --auth=${env.ESPURNA_AUTH} --port 8266
extra_scripts = ${common.extra_scripts}
[env:nodemcu-geiger]
platform = ${common.platform}
framework = arduino
board = nodemcu
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DNODEMCU_BASIC -DNOWSAUTH -DGEIGER_SUPPORT=1 -DEVENTS_SUPPORT=0 -DINFLUXDB_SUPPORT=1 -DALEXA_SUPPORT=0 -DALEXA_ENABLED=0
upload_speed = 460800
monitor_speed = 115200
extra_scripts = ${common.extra_scripts}

BIN
images/devices/geiger_espurna_configuration.png View File

Before After
Width: 2076  |  Height: 1564  |  Size: 247 KiB

BIN
images/devices/geiger_espurna_status.png View File

Before After
Width: 1800  |  Height: 1496  |  Size: 325 KiB

BIN
images/devices/geiger_grafana_dashboard.png View File

Before After
Width: 2414  |  Height: 658  |  Size: 457 KiB

BIN
images/devices/geiger_scope_following_pulses.png View File

Before After
Width: 800  |  Height: 480  |  Size: 39 KiB

BIN
images/devices/geiger_scope_single_pulse.png View File

Before After
Width: 800  |  Height: 480  |  Size: 38 KiB

BIN
images/devices/geiger_wiring_diagram.png View File

Before After
Width: 2152  |  Height: 864  |  Size: 1.9 MiB

Loading…
Cancel
Save