mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 12:17:05 +00:00
Compare commits
134
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56fd1e0203 | ||
|
|
890487fcae | ||
|
|
9b9dce0aaf | ||
|
|
da6edeab86 | ||
|
|
cdcf041073 | ||
|
|
ec99795c1e | ||
|
|
0bc8570b4a | ||
|
|
2d8e14eb87 | ||
|
|
4917dab1d3 | ||
|
|
42e1eb33ef | ||
|
|
c2fdd50655 | ||
|
|
a643596c48 | ||
|
|
04465454f4 | ||
|
|
190783f382 | ||
|
|
e51c5d8504 | ||
|
|
3849befeaf | ||
|
|
05c61879f9 | ||
|
|
71f6b58dd7 | ||
|
|
c30074afc5 | ||
|
|
5aef196306 | ||
|
|
e09f5ca0a1 | ||
|
|
716ae30d9d | ||
|
|
116c653db5 | ||
|
|
dcfc1e3689 | ||
|
|
7ba981eaea | ||
|
|
ede5ed8b0d | ||
|
|
b8877c53ed | ||
|
|
296271007b | ||
|
|
d49a91c4a2 | ||
|
|
2b567f5578 | ||
|
|
8469188f75 | ||
|
|
2409df4f5b | ||
|
|
c5c33cf6b6 | ||
|
|
cea1d8b825 | ||
|
|
982ed4d677 | ||
|
|
d424803cac | ||
|
|
6cd3f514a6 | ||
|
|
b5d4b96f14 | ||
|
|
f9ce235b32 | ||
|
|
491fa5c0a2 | ||
|
|
1bbbaa18f7 | ||
|
|
eff68b2173 | ||
|
|
8b6adac269 | ||
|
|
e0edd56413 | ||
|
|
c95d04aa6b | ||
|
|
9a88269e28 | ||
|
|
d5847f9ea1 | ||
|
|
b3a75c0105 | ||
|
|
3ba2f38408 | ||
|
|
b455a676d8 | ||
|
|
e5dbb3c680 | ||
|
|
7d236e8564 | ||
|
|
ae18a47bc9 | ||
|
|
5dd4d49517 | ||
|
|
d708d6a057 | ||
|
|
c3db03ea5e | ||
|
|
b65812ebf3 | ||
|
|
698299f918 | ||
|
|
277d12205d | ||
|
|
52b3c2e962 | ||
|
|
f6cadc43f3 | ||
|
|
e393d66283 | ||
|
|
10e33de018 | ||
|
|
842dc38805 | ||
|
|
52ef5c06fd | ||
|
|
1c63589b3d | ||
|
|
3e230310b9 | ||
|
|
ce249aaa4a | ||
|
|
bd216674d4 | ||
|
|
32c4b1d614 | ||
|
|
1847746077 | ||
|
|
56741b425c | ||
|
|
4f3a8e6acb | ||
|
|
f40d8c3cf4 | ||
|
|
d7a3c74ad9 | ||
|
|
b5049cd9ca | ||
|
|
55536cc4b3 | ||
|
|
cbbec517d6 | ||
|
|
db2624d49d | ||
|
|
d7116735e9 | ||
|
|
43ba235e68 | ||
|
|
2c3c8f6e0d | ||
|
|
6dc816869f | ||
|
|
5fff3c6ce7 | ||
|
|
fe85b0908c | ||
|
|
612742f669 | ||
|
|
8d2303db5f | ||
|
|
97b90a09db | ||
|
|
dcdf095575 | ||
|
|
9ecfce472d | ||
|
|
20e5bc0081 | ||
|
|
5136d4757c | ||
|
|
2729e341c8 | ||
|
|
6d0399c6c7 | ||
|
|
72d07bc303 | ||
|
|
c55bb28038 | ||
|
|
0a746d017e | ||
|
|
de4517f614 | ||
|
|
0dcd89a653 | ||
|
|
f70970c6f3 | ||
|
|
4d28d2b837 | ||
|
|
b63e76adfe | ||
|
|
77eedf5d6c | ||
|
|
01ff98be05 | ||
|
|
6222041a30 | ||
|
|
302e0d7fa7 | ||
|
|
894e9c3ff6 | ||
|
|
66bda6d531 | ||
|
|
f3c7c68248 | ||
|
|
093767f2b1 | ||
|
|
50f6c403e8 | ||
|
|
3c41155ee4 | ||
|
|
dcc2dbf0c6 | ||
|
|
fd1da876a4 | ||
|
|
93fc1b6140 | ||
|
|
80fb17ca05 | ||
|
|
ee0069ffa4 | ||
|
|
b1bd7d63f6 | ||
|
|
ef8059cf56 | ||
|
|
8d246947c1 | ||
|
|
8bcf29fa11 | ||
|
|
4b900daa67 | ||
|
|
a84567c14e | ||
|
|
d4420b9e36 | ||
|
|
6daa9a1e3c | ||
|
|
6a4f8a6942 | ||
|
|
41974d12e5 | ||
|
|
ea5168c08a | ||
|
|
d07bb3574a | ||
|
|
fb83badfce | ||
|
|
1a9eedc6d6 | ||
|
|
b26b4a1a93 | ||
|
|
f3e7dffec4 | ||
|
|
9341bde0da |
@@ -1,3 +1,5 @@
|
||||
**NOTE: This is not a support forum! For questions and support go here: https://www.letscontrolit.com/forum/viewforum.php?f=1**
|
||||
|
||||
### Steps to reproduce
|
||||
How can we trigger this problem?
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@ Check here to learn how to use this branch and help us improving ESPEasy: http:/
|
||||
* v2.0.0-devX: these are the current development releases. use these if you want bleeding edge features, or if you want to help us testing and developing. new release every month.
|
||||
* v2.0.0-betaX: as soon as we think its stable/complete enough for real testing, we will start numbering beta's.
|
||||
* v2.0.0-rcX: release candidates (probably stable)
|
||||
* v2.0.0: This will be the first stable release
|
||||
|
||||
After this we will use more standard numbering. Next bugfix release will probably be 2.0.1.
|
||||
* v2.0.0: This will be the first stable release. After this we will use more standard numbering. Next bugfix release will probably be 2.0.1.
|
||||
|
||||
## Firmware binary releases
|
||||
|
||||
@@ -39,7 +37,7 @@ ESPEasy_v2.0.0-dev9_normal_8285.bin | ESP8285 | Stable
|
||||
|
||||
## More info
|
||||
|
||||
Details and discussion are on the Experimental forum: http://www.letscontrolit.com/forum/viewtopic.php?f=18&t=2257&p=13600#p13600
|
||||
Details and discussion are on the Experimental forum: https://www.letscontrolit.com/forum/viewforum.php?f=18
|
||||
|
||||
We're also on IRC: #ESPEasy @freenode
|
||||
|
||||
|
||||
Vendored
+181
@@ -1,3 +1,184 @@
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0.0-dev12 (since v2.0.0-dev11)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Sep 22 01:25:29 CEST 2017
|
||||
|
||||
Daniel Tedenljung (1):
|
||||
This plugin is tested and working good. (#428)
|
||||
|
||||
Edwin Eefting (6):
|
||||
first set of changes for #235. added spiffs error checking and loging, and cleaner flashguarding code. next change will show feedback in web interface as well. also need to cleanup loose SPIFFS filehandling at other places in webserver.ino (create a save-function for all those things and use FLASH_GUARD)
|
||||
missed return after setting event buffer
|
||||
fixes bug #486 in counter-plugin
|
||||
plugin is not generic enough, so its disabled by default
|
||||
automaticly updated release notes for 2.0.0-dev12
|
||||
fixed release-notes bug
|
||||
|
||||
Gerben Meijer (1):
|
||||
Add SENSOR_TYPE_TRIPLE support to Domoticz MQTT (#468)
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[MH-Z19] Add 'ABC disable' option to web config (#472)
|
||||
|
||||
Jeroen (1):
|
||||
Create _P071_Kamstrup401.ino (#504)
|
||||
|
||||
Jochen Krapf (4):
|
||||
Added Plugins for SHT3x and LM75A - Issue #433 (#442)
|
||||
Descriptive GPIO-Names (#448)
|
||||
Rework of Plugin _P056_SDS011-Dust (#451)
|
||||
Fixed HTML text box length for controller settings - Issue #453 (#455)
|
||||
|
||||
Ovidiu Schiopu (1):
|
||||
Added _P070_NeoPixel_Clock.ino (#489)
|
||||
|
||||
SightofSilence (1):
|
||||
Add files via upload (#493)
|
||||
|
||||
beic (2):
|
||||
Moving from Temperature to Environment naming (#492)
|
||||
Moving from Temperature to Environment naming (#506)
|
||||
|
||||
mvdbro (4):
|
||||
Custom WEB page handler (SPIFFS)
|
||||
Finished work on Level Control & config
|
||||
Fixed a tasksettings load bug that was introduced with commit dcfc1e3 on july 18th.
|
||||
Moved HTML template logging to level LOG_LEVEL_DEBUG_DEV
|
||||
|
||||
papperone (1):
|
||||
HDC1080 plugin (#497)
|
||||
|
||||
|
||||
-----------------------------
|
||||
Changes in release v2.0.0-dev11
|
||||
-----------------------------
|
||||
|
||||
Release date: Mon Jul 17 00:55:29 CEST 2017
|
||||
|
||||
Daniel Tedenljung (5):
|
||||
Fixed decimal values (#329)
|
||||
Senseair update (#333)
|
||||
Reading error code in other way (#394)
|
||||
Added relay control from commands (#395)
|
||||
Renamed command to be unique. (#427)
|
||||
|
||||
DatuX (3):
|
||||
Update README.md
|
||||
Update issue_template.md
|
||||
Update issue_template.md
|
||||
|
||||
Edwin Eefting (27):
|
||||
cleaned up RTC initialisation. fixed some fuzzy issues after flashing/factory reset. improved flash-counter messages and added powercycle tips
|
||||
started working on regression testing scripts for The Rig
|
||||
large changes to wifi handling. code cleanup, more efficent connecting, only one connect retry in deepsleep. better serial logging for connections and APmode. always enable ap mode when wifi is disconnected
|
||||
prevent recursion when processing background tasks. might help with issue #117
|
||||
added option do deepsleep on connection failures. had to change boot order a bit, so the rebooted/warmboot message is the first one now. (this also makes more sense). issue #206
|
||||
better rtc error logging
|
||||
Fixed crashbug in email notification
|
||||
Fixed variable naming bug in FEATURE_ADC_VCC
|
||||
working on test framework
|
||||
esptesting framework
|
||||
dont want wifi passwords on github
|
||||
dont want wifi passwords on github
|
||||
converted all commands to python
|
||||
backup
|
||||
saved ~800 bytes ram in handle_devices(), issue #352. left old code commented for reference, in case i created bugs. will remove later
|
||||
accidently enabled FEATURE_ARDUINO_OTA
|
||||
fix #372
|
||||
serial now no longer resonds to empty commands
|
||||
add caching headers to static content
|
||||
upgraded IRremoteESP8266 from v1.0.2 to v1.2.0. fixes #188
|
||||
fix HTTP chunked transfer encoding, since WebServer class doesnt support it. this fixes the 2 second delay in some browsers. (we where out of spec.)
|
||||
more details AP mode serial output
|
||||
made mdns a feature. consitent use of hostname for both mdns and dhcp client. hostname now is name_unitnumber, with spaces replaced by -
|
||||
gave some html logging debug-level
|
||||
imlemented setting name, unit and password via serial. implements #317
|
||||
added note to inverse logic to fix #318
|
||||
automaticly updated release notes for v2.0.0-dev11
|
||||
|
||||
Gustavo Spadari (1):
|
||||
Adding comments on RAW code (#386) (#393)
|
||||
|
||||
JK (7):
|
||||
First draft
|
||||
Send web page as junked data
|
||||
Accept CR and LF at serial commands
|
||||
First draft
|
||||
Added Plugin for Touch KeyPad Chip TTP229
|
||||
Fine tuning of CSS and menu
|
||||
Reenabled javascript for device-selector
|
||||
|
||||
Jochen Krapf (25):
|
||||
Added _P054_DMX512 (#322)
|
||||
Added _P055_Chiming (#323)
|
||||
Added _P056_SDS011-Dust (#324)
|
||||
Added Plugin for Quadrature Encoder Interface (Rotary Encoder) (#335)
|
||||
Added Plugin _P061_KeyPad (#340)
|
||||
Added Plugin _P060_MCP3221 (#342)
|
||||
Formula option for _P013_HCSR04 plugin issue #343 #313 (#344)
|
||||
Fixed issues #308 #305 (#345)
|
||||
Added Plugin _P062_MPR121_KeyPad (#346)
|
||||
Fixed issue #348 (#349)
|
||||
Added plugins for HT16K33 LED matrix driver and key pad scanner (#328)
|
||||
Increase DEVICES_MAX for more testing and dev plugins (#353)
|
||||
Write default CSS to SPIFFS on boot (#357)
|
||||
Fixed DEVICES_MAX for testing and dev (#374)
|
||||
Step back to style-based-css for speed up + pimp menu (#376)
|
||||
Check plugin-array size on init - issue #119 (#389)
|
||||
Added Plugin for MP3 module (#402)
|
||||
Minor corrections and documentation (#404)
|
||||
Added Plugin for Gesture Sensor APDS9960 (#409)
|
||||
Added Plugin for Color Sensor VEML6040 (#412)
|
||||
Added Plugin for HX711 Load Cell - Request #408 (#415)
|
||||
Fixed multiline define bug on CRLF (#416)
|
||||
Added Value Logger on SD Card (#429)
|
||||
Plugin65 MP3 - volume updated in device menu - issue #424 (#438)
|
||||
Plugin HX711 - Added Tare function (#419)
|
||||
|
||||
PieVo (1):
|
||||
Update P053 (PMSx003) to support software serial and minor cleanup (#390)
|
||||
|
||||
SloMusti (3):
|
||||
fixed deep sleep, such that it can be enabled from Rules (#375)
|
||||
Implemented a better WiFI AP naming strategy. ESP_Easy has replaced the newdevice text as the default name and now the name is used as and AP SSID (#410)
|
||||
added mDNS implementation (#418)
|
||||
|
||||
elucas2uy (1):
|
||||
FIX Pass and Index on handle_controllers() (#331)
|
||||
|
||||
imthemichi (1):
|
||||
Plugin_008-RFID extended with wiegand 34-bits and key-pad (#387)
|
||||
|
||||
krikk (5):
|
||||
changed the ina219 plugin so that is always sends 3 values, voltage, current, power... like a normal plugin should do... (#325)
|
||||
delay option should be displayed even if the SendDataOption is false, because the delay option also controls the refresh rate of the oled display... fixes issue #336 (#339)
|
||||
seconds were displayed without leading zero issue #337 (#338)
|
||||
added local ip to sysinfo plugin, due to limitation of return type float, i had to split up the ip in its octets... fixes issue #228 (#341)
|
||||
implemented a measurement type selection to retain backward compability to Domoticz... hope this works... (#351)
|
||||
|
||||
mvdbro (8):
|
||||
Fix Domoticz helper plugin #330
|
||||
Enlarge MQTT buffer for Domoticz MQTT controller
|
||||
MQTT Controller enable/disable fix (#287)
|
||||
Fix incorrect ADC GPIO display
|
||||
Fix default controller settings (#360)
|
||||
Added pin state buffer table page (mainly for debugging)
|
||||
Update checkRAM function
|
||||
Revert to default ESP Easy colorscheme
|
||||
|
||||
papperone (5):
|
||||
Fixed Broken P038
|
||||
p038
|
||||
reverted some changes due to bug fixed in the "webserver.ino #348"
|
||||
P038 - optimization
|
||||
P010 plugin optimization (#403)
|
||||
|
||||
tedenda (2):
|
||||
Renamed Prefix from P011 to C011
|
||||
Missed one...
|
||||
|
||||
|
||||
-----------------------------
|
||||
Changes in release v2.0.0-dev10
|
||||
-----------------------------
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/***************************************************
|
||||
This is a library for the MPR121 I2C 12-chan Capacitive Sensor
|
||||
|
||||
Designed specifically to work with the MPR121 sensor from Adafruit
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C to communicate, 2+ pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#include "Adafruit_MPR121.h"
|
||||
|
||||
Adafruit_MPR121::Adafruit_MPR121() {
|
||||
}
|
||||
|
||||
boolean Adafruit_MPR121::begin(uint8_t i2caddr) {
|
||||
Wire.begin();
|
||||
|
||||
_i2caddr = i2caddr;
|
||||
|
||||
// soft reset
|
||||
writeRegister(MPR121_SOFTRESET, 0x63);
|
||||
delay(1);
|
||||
for (uint8_t i=0; i<0x7F; i++) {
|
||||
// Serial.print("$"); Serial.print(i, HEX);
|
||||
// Serial.print(": 0x"); Serial.println(readRegister8(i));
|
||||
}
|
||||
|
||||
|
||||
writeRegister(MPR121_ECR, 0x0);
|
||||
|
||||
uint8_t c = readRegister8(MPR121_CONFIG2);
|
||||
|
||||
if (c != 0x24) return false;
|
||||
|
||||
|
||||
setThreshholds(12, 6);
|
||||
writeRegister(MPR121_MHDR, 0x01);
|
||||
writeRegister(MPR121_NHDR, 0x01);
|
||||
writeRegister(MPR121_NCLR, 0x0E);
|
||||
writeRegister(MPR121_FDLR, 0x00);
|
||||
|
||||
writeRegister(MPR121_MHDF, 0x01);
|
||||
writeRegister(MPR121_NHDF, 0x05);
|
||||
writeRegister(MPR121_NCLF, 0x01);
|
||||
writeRegister(MPR121_FDLF, 0x00);
|
||||
|
||||
writeRegister(MPR121_NHDT, 0x00);
|
||||
writeRegister(MPR121_NCLT, 0x00);
|
||||
writeRegister(MPR121_FDLT, 0x00);
|
||||
|
||||
writeRegister(MPR121_DEBOUNCE, 0);
|
||||
writeRegister(MPR121_CONFIG1, 0x10); // default, 16uA charge current
|
||||
writeRegister(MPR121_CONFIG2, 0x20); // 0.5uS encoding, 1ms period
|
||||
|
||||
// writeRegister(MPR121_AUTOCONFIG0, 0x8F);
|
||||
|
||||
// writeRegister(MPR121_UPLIMIT, 150);
|
||||
// writeRegister(MPR121_TARGETLIMIT, 100); // should be ~400 (100 shifted)
|
||||
// writeRegister(MPR121_LOWLIMIT, 50);
|
||||
// enable all electrodes
|
||||
writeRegister(MPR121_ECR, 0x8F); // start with first 5 bits of baseline tracking
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Adafruit_MPR121::setThreshholds(uint8_t touch, uint8_t release) {
|
||||
|
||||
setThresholds(touch, release);
|
||||
}
|
||||
|
||||
void Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release) {
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
writeRegister(MPR121_TOUCHTH_0 + 2*i, touch);
|
||||
writeRegister(MPR121_RELEASETH_0 + 2*i, release);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Adafruit_MPR121::filteredData(uint8_t t) {
|
||||
if (t > 12) return 0;
|
||||
return readRegister16(MPR121_FILTDATA_0L + t*2);
|
||||
}
|
||||
|
||||
uint16_t Adafruit_MPR121::baselineData(uint8_t t) {
|
||||
if (t > 12) return 0;
|
||||
uint16_t bl = readRegister8(MPR121_BASELINE_0 + t);
|
||||
return (bl << 2);
|
||||
}
|
||||
|
||||
uint16_t Adafruit_MPR121::touched(void) {
|
||||
uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L);
|
||||
return t & 0x0FFF;
|
||||
}
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
|
||||
uint8_t Adafruit_MPR121::readRegister8(uint8_t reg) {
|
||||
Wire.beginTransmission(_i2caddr);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission(false);
|
||||
while (Wire.requestFrom(_i2caddr, 1) != 1);
|
||||
return ( Wire.read());
|
||||
}
|
||||
|
||||
uint16_t Adafruit_MPR121::readRegister16(uint8_t reg) {
|
||||
Wire.beginTransmission(_i2caddr);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission(false);
|
||||
while (Wire.requestFrom(_i2caddr, 2) != 2);
|
||||
uint16_t v = Wire.read();
|
||||
v |= ((uint16_t) Wire.read()) << 8;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes 8-bits to the specified destination register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_MPR121::writeRegister(uint8_t reg, uint8_t value) {
|
||||
Wire.beginTransmission(_i2caddr);
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)(value));
|
||||
Wire.endTransmission();
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/***************************************************
|
||||
This is a library for the MPR121 12-Channel Capacitive Sensor
|
||||
|
||||
Designed specifically to work with the MPR121 breakout from Adafruit
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C to communicate, 2+ pins are required to
|
||||
interface
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#ifndef ADAFRUIT_MPR121_H
|
||||
#define ADAFRUIT_MPR121_H
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include <Wire.h>
|
||||
|
||||
// The default I2C address
|
||||
#define MPR121_I2CADDR_DEFAULT 0x5A
|
||||
|
||||
#define MPR121_TOUCHSTATUS_L 0x00
|
||||
#define MPR121_TOUCHSTATUS_H 0x01
|
||||
#define MPR121_FILTDATA_0L 0x04
|
||||
#define MPR121_FILTDATA_0H 0x05
|
||||
#define MPR121_BASELINE_0 0x1E
|
||||
#define MPR121_MHDR 0x2B
|
||||
#define MPR121_NHDR 0x2C
|
||||
#define MPR121_NCLR 0x2D
|
||||
#define MPR121_FDLR 0x2E
|
||||
#define MPR121_MHDF 0x2F
|
||||
#define MPR121_NHDF 0x30
|
||||
#define MPR121_NCLF 0x31
|
||||
#define MPR121_FDLF 0x32
|
||||
#define MPR121_NHDT 0x33
|
||||
#define MPR121_NCLT 0x34
|
||||
#define MPR121_FDLT 0x35
|
||||
|
||||
#define MPR121_TOUCHTH_0 0x41
|
||||
#define MPR121_RELEASETH_0 0x42
|
||||
#define MPR121_DEBOUNCE 0x5B
|
||||
#define MPR121_CONFIG1 0x5C
|
||||
#define MPR121_CONFIG2 0x5D
|
||||
#define MPR121_CHARGECURR_0 0x5F
|
||||
#define MPR121_CHARGETIME_1 0x6C
|
||||
#define MPR121_ECR 0x5E
|
||||
#define MPR121_AUTOCONFIG0 0x7B
|
||||
#define MPR121_AUTOCONFIG1 0x7C
|
||||
#define MPR121_UPLIMIT 0x7D
|
||||
#define MPR121_LOWLIMIT 0x7E
|
||||
#define MPR121_TARGETLIMIT 0x7F
|
||||
|
||||
#define MPR121_GPIODIR 0x76
|
||||
#define MPR121_GPIOEN 0x77
|
||||
#define MPR121_GPIOSET 0x78
|
||||
#define MPR121_GPIOCLR 0x79
|
||||
#define MPR121_GPIOTOGGLE 0x7A
|
||||
|
||||
|
||||
|
||||
#define MPR121_SOFTRESET 0x80
|
||||
|
||||
//.. thru to 0x1C/0x1D
|
||||
class Adafruit_MPR121 {
|
||||
public:
|
||||
// Hardware I2C
|
||||
Adafruit_MPR121(void);
|
||||
|
||||
boolean begin(uint8_t i2caddr = MPR121_I2CADDR_DEFAULT);
|
||||
|
||||
uint16_t filteredData(uint8_t t);
|
||||
uint16_t baselineData(uint8_t t);
|
||||
|
||||
uint8_t readRegister8(uint8_t reg);
|
||||
uint16_t readRegister16(uint8_t reg);
|
||||
void writeRegister(uint8_t reg, uint8_t value);
|
||||
uint16_t touched(void);
|
||||
// Add deprecated attribute so that the compiler shows a warning
|
||||
__attribute__((deprecated)) void setThreshholds(uint8_t touch, uint8_t release);
|
||||
void setThresholds(uint8_t touch, uint8_t release);
|
||||
|
||||
private:
|
||||
int8_t _i2caddr;
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_MPR121_H
|
||||
@@ -0,0 +1,32 @@
|
||||
# Adafruit_MPR121_Library
|
||||
<!-- START COMPATIBILITY TABLE -->
|
||||
|
||||
## Compatibility
|
||||
|
||||
MCU | Tested Works | Doesn't Work | Not Tested | Notes
|
||||
------------------ | :----------: | :----------: | :---------: | -----
|
||||
Atmega328 @ 16MHz | X | | |
|
||||
Atmega328 @ 12MHz | X | | |
|
||||
Atmega32u4 @ 16MHz | X | | |
|
||||
Atmega32u4 @ 8MHz | X | | |
|
||||
ESP8266 | | X | |
|
||||
Atmega2560 @ 16MHz | X | | |
|
||||
ATSAM3X8E | | X | |
|
||||
ATSAM21D | X | | |
|
||||
ATtiny85 @ 16MHz | | | X |
|
||||
ATtiny85 @ 8MHz | | | X |
|
||||
Intel Curie @ 32MHz | | | X |
|
||||
STM32F2 | | | X |
|
||||
|
||||
* ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
|
||||
* ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
|
||||
* ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
|
||||
* ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
|
||||
* ESP8266 : Adafruit Huzzah
|
||||
* ATmega2560 @ 16MHz : Arduino Mega
|
||||
* ATSAM3X8E : Arduino Due
|
||||
* ATSAM21D : Arduino Zero, M0 Pro
|
||||
* ATtiny85 @ 16MHz : Adafruit Trinket 5V
|
||||
* ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
|
||||
|
||||
<!-- END COMPATIBILITY TABLE -->
|
||||
@@ -0,0 +1,25 @@
|
||||
This is a library for the MPR121 12-channel Capacitive touch sensor
|
||||
|
||||
Designed specifically to work with the MPR121 Breakout in the Adafruit shop
|
||||
----> https://www.adafruit.com/products/1982
|
||||
|
||||
These sensors use I2C communicate, at least 2 pins are required
|
||||
to interface
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
|
||||
Check out the links above for our tutorials and wiring diagrams
|
||||
|
||||
To download. click the ZIP button, and rename the uncompressed folder Adafruit_MPR121
|
||||
Check that the Adafruit_MPR121 folder contains Adafruit_MPR121.cpp and Adafruit_MPR121.h
|
||||
|
||||
Place the Adafruit_MPR121 library folder your arduinosketchfolder/libraries/ folder.
|
||||
You may need to create the libraries subfolder if its your first library. Restart the IDE.
|
||||
|
||||
We also have a great tutorial on Arduino library installation at:
|
||||
http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use
|
||||
@@ -0,0 +1,83 @@
|
||||
/*********************************************************
|
||||
This is a library for the MPR121 12-channel Capacitive touch sensor
|
||||
|
||||
Designed specifically to work with the MPR121 Breakout in the Adafruit shop
|
||||
----> https://www.adafruit.com/products/
|
||||
|
||||
These sensors use I2C communicate, at least 2 pins are required
|
||||
to interface
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
BSD license, all text above must be included in any redistribution
|
||||
**********************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include "Adafruit_MPR121.h"
|
||||
|
||||
// You can have up to 4 on one i2c bus but one is enough for testing!
|
||||
Adafruit_MPR121 cap = Adafruit_MPR121();
|
||||
|
||||
// Keeps track of the last pins touched
|
||||
// so we know when buttons are 'released'
|
||||
uint16_t lasttouched = 0;
|
||||
uint16_t currtouched = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial) { // needed to keep leonardo/micro from starting too fast!
|
||||
delay(10);
|
||||
}
|
||||
|
||||
Serial.println("Adafruit MPR121 Capacitive Touch sensor test");
|
||||
|
||||
// Default address is 0x5A, if tied to 3.3V its 0x5B
|
||||
// If tied to SDA its 0x5C and if SCL then 0x5D
|
||||
if (!cap.begin(0x5A)) {
|
||||
Serial.println("MPR121 not found, check wiring?");
|
||||
while (1);
|
||||
}
|
||||
Serial.println("MPR121 found!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Get the currently touched pads
|
||||
currtouched = cap.touched();
|
||||
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
// it if *is* touched and *wasnt* touched before, alert!
|
||||
if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
|
||||
Serial.print(i); Serial.println(" touched");
|
||||
}
|
||||
// if it *was* touched and now *isnt*, alert!
|
||||
if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
|
||||
Serial.print(i); Serial.println(" released");
|
||||
}
|
||||
}
|
||||
|
||||
// reset our state
|
||||
lasttouched = currtouched;
|
||||
|
||||
// comment out this line for detailed data from the sensor!
|
||||
return;
|
||||
|
||||
// debugging info, what
|
||||
Serial.print("\t\t\t\t\t\t\t\t\t\t\t\t\t 0x"); Serial.println(cap.touched(), HEX);
|
||||
Serial.print("Filt: ");
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
Serial.print(cap.filteredData(i)); Serial.print("\t");
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("Base: ");
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
Serial.print(cap.baselineData(i)); Serial.print("\t");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// put a delay so it isn't overwhelming
|
||||
delay(100);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Adafruit_MPR121 KEYWORD1
|
||||
begin KEYWORD2
|
||||
filteredData KEYWORD2
|
||||
baselineData KEYWORD2
|
||||
touched KEYWORD2
|
||||
setThresholds KEYWORD2
|
||||
@@ -0,0 +1,9 @@
|
||||
name=Adafruit MPR121
|
||||
version=1.0.0
|
||||
author=Adafruit <info@adafruit.com>
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Arduino library for the MPR121-based capacitive sensors in the Adafruit shop.
|
||||
paragraph=Designed specifically to work with the MPR121 Breakout in the Adafruit shop.
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_MPR121
|
||||
architectures=*
|
||||
@@ -0,0 +1,174 @@
|
||||
#include "HT16K33.h"
|
||||
#include <Wire.h>
|
||||
|
||||
CHT16K33::CHT16K33(void)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
void CHT16K33::Init(uint8_t addr)
|
||||
{
|
||||
_addr = addr;
|
||||
|
||||
// System Setup Register
|
||||
Wire.beginTransmission(_addr);
|
||||
Wire.write(0x21); // oscillator on
|
||||
Wire.endTransmission();
|
||||
|
||||
// Display Setup Register
|
||||
Wire.beginTransmission(_addr);
|
||||
Wire.write(0x81); // blink off; display on
|
||||
Wire.endTransmission();
|
||||
|
||||
SetBrightness(15);
|
||||
ClearRowBuffer();
|
||||
TransmitRowBuffer();
|
||||
};
|
||||
|
||||
void CHT16K33::SetBrightness(uint8_t b)
|
||||
{
|
||||
if (b > 15)
|
||||
b = 15;
|
||||
// Digital Dimming Data Input
|
||||
Wire.beginTransmission(_addr);
|
||||
Wire.write(0xE0 | b); // brightness
|
||||
Wire.endTransmission();
|
||||
};
|
||||
|
||||
void CHT16K33::TransmitRowBuffer(void)
|
||||
{
|
||||
// Display Memory
|
||||
Wire.beginTransmission(_addr);
|
||||
Wire.write(0); // start data at address 0
|
||||
for (byte i=0; i<8; i++)
|
||||
{
|
||||
Wire.write(_rowBuffer[i] & 0xFF);
|
||||
Wire.write(_rowBuffer[i] >> 8);
|
||||
}
|
||||
Wire.endTransmission();
|
||||
};
|
||||
|
||||
void CHT16K33::ClearRowBuffer(void)
|
||||
{
|
||||
for (byte i=0; i<8; i++)
|
||||
_rowBuffer[i] = 0;
|
||||
};
|
||||
|
||||
void CHT16K33::SetRow(uint8_t com, uint16_t data)
|
||||
{
|
||||
if (com < 8)
|
||||
_rowBuffer[com] = data;
|
||||
};
|
||||
|
||||
uint16_t CHT16K33::GetRow(uint8_t com)
|
||||
{
|
||||
if (com < 8)
|
||||
return _rowBuffer[com];
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
|
||||
void CHT16K33::SetDigit(uint8_t com, uint8_t c)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
|
||||
if (c <= 0xF)
|
||||
value = _digits[c];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
value = c + 10 - 'A';
|
||||
value = _digits[value & 0xF];
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
value = c - '0';
|
||||
value = _digits[value & 0xF];
|
||||
break;
|
||||
case ' ':
|
||||
value = 0;
|
||||
break;
|
||||
case ':':
|
||||
value = 0x02; //special for China 4 x 7-seg big display
|
||||
break;
|
||||
case '-':
|
||||
value = 0x40;
|
||||
break;
|
||||
}
|
||||
|
||||
SetRow(com, value);
|
||||
}
|
||||
|
||||
uint8_t CHT16K33::ReadKeys(void)
|
||||
{
|
||||
// Display Memory
|
||||
Wire.beginTransmission(_addr);
|
||||
Wire.write(0x40); // start data at address 0x40
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(_addr, (uint8_t)6);
|
||||
if (Wire.available() == 6)
|
||||
{
|
||||
for (byte i=0; i<3; i++)
|
||||
{
|
||||
_keyBuffer[i] = Wire.read() | (Wire.read() << 8);
|
||||
}
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
for (byte i=0; i<3; i++)
|
||||
{
|
||||
byte mask = 1;
|
||||
for (byte k=0; k<12; k++)
|
||||
{
|
||||
if (_keyBuffer[i] & mask)
|
||||
{
|
||||
_keydown = 16*(i+1) + (k+1);
|
||||
return _keydown;
|
||||
}
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
_keydown = 0;
|
||||
return _keydown;
|
||||
};
|
||||
|
||||
const uint8_t CHT16K33::_digits[16] =
|
||||
{
|
||||
0x3F, // 0
|
||||
0x06, // 1
|
||||
0x5B, // 2
|
||||
0x4F, // 3
|
||||
0x66, // 4
|
||||
0x6D, // 5
|
||||
0x7D, // 6
|
||||
0x07, // 7
|
||||
0x7F, // 8
|
||||
0x6F, // 9
|
||||
0x77, // A
|
||||
0x7C, // B
|
||||
0x39, // C
|
||||
0x5E, // D
|
||||
0x79, // E
|
||||
0x71, // F
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef CHT16K33_h
|
||||
#define CHT16K33_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class CHT16K33 {
|
||||
public:
|
||||
CHT16K33(void);
|
||||
|
||||
void Init(uint8_t addr);
|
||||
|
||||
// LED buffer
|
||||
void ClearRowBuffer(void);
|
||||
void SetRow(uint8_t com, uint16_t data);
|
||||
uint16_t GetRow(uint8_t com);
|
||||
void SetDigit(uint8_t com, uint8_t c);
|
||||
|
||||
// LED output and control
|
||||
void SetBrightness(uint8_t b);
|
||||
void TransmitRowBuffer(void);
|
||||
|
||||
//KeyPad Scan
|
||||
uint8_t ReadKeys(void);
|
||||
|
||||
protected:
|
||||
uint8_t _addr;
|
||||
uint16_t _rowBuffer[8];
|
||||
uint16_t _keyBuffer[3];
|
||||
byte _keydown;
|
||||
|
||||
static const uint8_t _digits[16];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
name=CHT16K33 LED Matrix Library
|
||||
version=0.0.1
|
||||
author=Jochen Krapf
|
||||
maintainer=Jochen Krapf <jk@nerd2nerd.org>
|
||||
sentence=CHT16K33 16x8 LED and 13x3 KeyPad Matrix Library
|
||||
paragraph=CHT16K33 16x8 LED and 13x3 KeyPad Matrix Library
|
||||
category=LED
|
||||
url=https://github.com/???
|
||||
architectures=esp8266,avr
|
||||
@@ -1,13 +1,14 @@
|
||||
language: c
|
||||
env:
|
||||
- BD=esp8266:esp8266:nodemcuv2:CpuFrequency=80,FlashSize=4M3M
|
||||
- BD=esp8266:esp8266:d1_mini:CpuFrequency=80,FlashSize=4M3M
|
||||
before_install:
|
||||
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
|
||||
- sleep 3
|
||||
- export DISPLAY=:1.0
|
||||
- wget http://downloads.arduino.cc/arduino-1.8.1-linux64.tar.xz
|
||||
- tar xf arduino-1.8.1-linux64.tar.xz
|
||||
- sudo mv arduino-1.8.1 /usr/local/share/arduino
|
||||
- wget http://downloads.arduino.cc/arduino-1.8.2-linux64.tar.xz
|
||||
- tar xf arduino-1.8.2-linux64.tar.xz
|
||||
- sudo mv arduino-1.8.2 /usr/local/share/arduino
|
||||
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
|
||||
install:
|
||||
- ln -s $PWD /usr/local/share/arduino/libraries/
|
||||
@@ -25,7 +26,7 @@ script:
|
||||
- arduino --verify --board $BD $PWD/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
|
||||
- arduino --verify --board $BD $PWD/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
|
||||
- arduino --verify --board $BD $PWD/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
|
||||
- arduino --verify --board $BD $PWD/examples/TurnOnKelvinatorAC/TurnOnMitsubishiAC.ino
|
||||
- arduino --verify --board $BD $PWD/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
@@ -9,17 +9,17 @@ IRDaikinESP::IRDaikinESP(int pin) : _irsend(pin)
|
||||
{
|
||||
}
|
||||
|
||||
void IRDaikinESP::begin()
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::begin()
|
||||
{
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
void IRDaikinESP::send()
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::send()
|
||||
{
|
||||
_irsend.sendDaikin(daikin);
|
||||
}
|
||||
|
||||
void IRDaikinESP::checksum()
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::checksum()
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
uint8_t i;
|
||||
@@ -36,39 +36,39 @@ void IRDaikinESP::checksum()
|
||||
daikin[26] = sum &0xFF;
|
||||
}
|
||||
|
||||
void IRDaikinESP::on()
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::on()
|
||||
{
|
||||
//state = ON;
|
||||
daikin[13] |= 0x01;
|
||||
checksum();
|
||||
}
|
||||
|
||||
void IRDaikinESP::off()
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::off()
|
||||
{
|
||||
//state = OFF;
|
||||
daikin[13] &= 0xFE;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getPower()
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getPower()
|
||||
{
|
||||
return (daikin[13])&0x01;
|
||||
}
|
||||
|
||||
// DAIKIN_SILENT or DAIKIN_POWERFUL
|
||||
void IRDaikinESP::setAux(uint8_t aux)
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setAux(uint8_t aux)
|
||||
{
|
||||
daikin[21] = aux;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getAux(){
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getAux(){
|
||||
return daikin[21];
|
||||
}
|
||||
|
||||
|
||||
// Set the temp in deg C
|
||||
void IRDaikinESP::setTemp(uint8_t temp)
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setTemp(uint8_t temp)
|
||||
{
|
||||
if (temp < 18)
|
||||
temp = 18;
|
||||
@@ -78,13 +78,13 @@ void IRDaikinESP::setTemp(uint8_t temp)
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getTemp()
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getTemp()
|
||||
{
|
||||
return (daikin[14])/2;
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
|
||||
void IRDaikinESP::setFan(uint8_t fan)
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setFan(uint8_t fan)
|
||||
{
|
||||
// Set the fan speed bits, leave low 4 bits alone
|
||||
uint8_t fanset;
|
||||
@@ -97,7 +97,7 @@ void IRDaikinESP::setFan(uint8_t fan)
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getFan()
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getFan()
|
||||
{
|
||||
uint8_t fan = daikin[16] >> 4;
|
||||
fan = fan - 2;
|
||||
@@ -106,7 +106,7 @@ uint8_t IRDaikinESP::getFan()
|
||||
return fan;
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getMode()
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getMode()
|
||||
{/*
|
||||
DAIKIN_COOL
|
||||
DAIKIN_HEAT
|
||||
@@ -117,13 +117,13 @@ uint8_t IRDaikinESP::getMode()
|
||||
return (daikin[13])>>4;
|
||||
}
|
||||
|
||||
void IRDaikinESP::setMode(uint8_t mode)
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setMode(uint8_t mode)
|
||||
{
|
||||
daikin[13]=mode<<4 | getPower();
|
||||
checksum();
|
||||
}
|
||||
|
||||
void IRDaikinESP::setSwingVertical(uint8_t swing)
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setSwingVertical(uint8_t swing)
|
||||
{
|
||||
if (swing)
|
||||
daikin[16] = daikin[16] | 0x0F;
|
||||
@@ -132,12 +132,12 @@ void IRDaikinESP::setSwingVertical(uint8_t swing)
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getSwingVertical()
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getSwingVertical()
|
||||
{
|
||||
return (daikin[16])&0x01;
|
||||
}
|
||||
|
||||
void IRDaikinESP::setSwingHorizontal(uint8_t swing)
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setSwingHorizontal(uint8_t swing)
|
||||
{
|
||||
if (swing)
|
||||
daikin[17] = daikin[17] | 0x0F;
|
||||
@@ -146,7 +146,7 @@ void IRDaikinESP::setSwingHorizontal(uint8_t swing)
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getSwingHorizontal()
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getSwingHorizontal()
|
||||
{
|
||||
return (daikin[17])&0x01;
|
||||
}
|
||||
|
||||
@@ -20,36 +20,36 @@ IRKelvinatorAC::IRKelvinatorAC(int pin) : _irsend(pin) {
|
||||
stateReset();
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::stateReset() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::stateReset() {
|
||||
for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++)
|
||||
remote_state[i] = 0x0;
|
||||
remote_state[3] = 0x50;
|
||||
remote_state[11] = 0x70;
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::begin() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::fixup() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::fixup() {
|
||||
// X-Fan mode is only valid in COOL or DRY modes.
|
||||
if (getMode() != KELVINATOR_COOL && getMode() != KELVINATOR_DRY)
|
||||
setXFan(false);
|
||||
checksum(); // Calculate the checksums
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::send() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::send() {
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
_irsend.sendKelvinator(remote_state);
|
||||
}
|
||||
|
||||
uint8_t* IRKelvinatorAC::getRaw() {
|
||||
uint8_t* ICACHE_FLASH_ATTR IRKelvinatorAC::getRaw() {
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
return remote_state;
|
||||
}
|
||||
|
||||
// Many Bothans died to bring us this information.
|
||||
void IRKelvinatorAC::checksum() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::checksum() {
|
||||
// For each command + options block.
|
||||
for (uint8_t offset = 0; offset < KELVINATOR_STATE_LENGTH; offset += 8) {
|
||||
uint8_t sum = KELVINATOR_CHECKSUM_START;
|
||||
@@ -68,31 +68,31 @@ void IRKelvinatorAC::checksum() {
|
||||
}
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::on() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::on() {
|
||||
//state = ON;
|
||||
remote_state[0] |= KELVINATOR_POWER;
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::off() {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::off() {
|
||||
//state = OFF;
|
||||
remote_state[0] &= ~KELVINATOR_POWER;
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setPower(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setPower(bool state) {
|
||||
if (state)
|
||||
on();
|
||||
else
|
||||
off();
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getPower() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getPower() {
|
||||
return ((remote_state[0] & KELVINATOR_POWER) != 0);
|
||||
}
|
||||
|
||||
// Set the temp. in deg C
|
||||
void IRKelvinatorAC::setTemp(uint8_t temp) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setTemp(uint8_t temp) {
|
||||
temp = max(KELVINATOR_MIN_TEMP, temp);
|
||||
temp = min(KELVINATOR_MAX_TEMP, temp);
|
||||
remote_state[1] = (remote_state[1] & 0xF0U) | (temp - KELVINATOR_MIN_TEMP);
|
||||
@@ -100,12 +100,12 @@ void IRKelvinatorAC::setTemp(uint8_t temp) {
|
||||
}
|
||||
|
||||
// Return the set temp. in deg C
|
||||
uint8_t IRKelvinatorAC::getTemp() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getTemp() {
|
||||
return ((remote_state[1] & 0xFU) + KELVINATOR_MIN_TEMP);
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
|
||||
void IRKelvinatorAC::setFan(uint8_t fan) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setFan(uint8_t fan) {
|
||||
fan = min(KELVINATOR_FAN_MAX, fan); // Bounds check
|
||||
|
||||
// Only change things if we need to.
|
||||
@@ -122,11 +122,11 @@ void IRKelvinatorAC::setFan(uint8_t fan) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t IRKelvinatorAC::getFan() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getFan() {
|
||||
return ((remote_state[14] & ~KELVINATOR_FAN_MASK) >> KELVINATOR_FAN_OFFSET);
|
||||
}
|
||||
|
||||
uint8_t IRKelvinatorAC::getMode() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getMode() {
|
||||
/*
|
||||
KELVINATOR_AUTO
|
||||
KELVINATOR_COOL
|
||||
@@ -137,7 +137,7 @@ uint8_t IRKelvinatorAC::getMode() {
|
||||
return (remote_state[0] & ~KELVINATOR_MODE_MASK);
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setMode(uint8_t mode) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setMode(uint8_t mode) {
|
||||
// If we get an unexpected mode, default to AUTO.
|
||||
if (mode > KELVINATOR_HEAT) mode = KELVINATOR_AUTO;
|
||||
remote_state[0] = (remote_state[0] & KELVINATOR_MODE_MASK) | mode;
|
||||
@@ -147,7 +147,7 @@ void IRKelvinatorAC::setMode(uint8_t mode) {
|
||||
setTemp(KELVINATOR_AUTO_TEMP);
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setSwingVertical(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setSwingVertical(bool state) {
|
||||
if (state) {
|
||||
remote_state[0] |= KELVINATOR_VENT_SWING;
|
||||
remote_state[4] |= KELVINATOR_VENT_SWING_V;
|
||||
@@ -160,11 +160,11 @@ void IRKelvinatorAC::setSwingVertical(bool state) {
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getSwingVertical() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getSwingVertical() {
|
||||
return ((remote_state[4] & KELVINATOR_VENT_SWING_V) != 0);
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setSwingHorizontal(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setSwingHorizontal(bool state) {
|
||||
if (state) {
|
||||
remote_state[0] |= KELVINATOR_VENT_SWING;
|
||||
remote_state[4] |= KELVINATOR_VENT_SWING_H;
|
||||
@@ -177,57 +177,57 @@ void IRKelvinatorAC::setSwingHorizontal(bool state) {
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getSwingHorizontal() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getSwingHorizontal() {
|
||||
return ((remote_state[4] & KELVINATOR_VENT_SWING_H) != 0);
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setQuiet(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setQuiet(bool state) {
|
||||
remote_state[12] &= ~KELVINATOR_QUIET;
|
||||
remote_state[12] |= (state << KELVINATOR_QUIET_OFFSET);
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getQuiet() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getQuiet() {
|
||||
return ((remote_state[12] & KELVINATOR_QUIET) != 0);
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setIonFilter(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setIonFilter(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_ION_FILTER;
|
||||
remote_state[2] |= (state << KELVINATOR_ION_FILTER_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getIonFilter() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getIonFilter() {
|
||||
return ((remote_state[2] & KELVINATOR_ION_FILTER) != 0);
|
||||
}
|
||||
|
||||
void IRKelvinatorAC::setLight(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setLight(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_LIGHT;
|
||||
remote_state[2] |= (state << KELVINATOR_LIGHT_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getLight() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getLight() {
|
||||
return ((remote_state[2] & KELVINATOR_LIGHT) != 0);
|
||||
}
|
||||
|
||||
// Note: XFan mode is only valid in Cool or Dry mode.
|
||||
void IRKelvinatorAC::setXFan(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setXFan(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_XFAN;
|
||||
remote_state[2] |= (state << KELVINATOR_XFAN_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getXFan() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getXFan() {
|
||||
return ((remote_state[2] & KELVINATOR_XFAN) != 0);
|
||||
}
|
||||
|
||||
// Note: Turbo mode is turned off if the fan speed is changed.
|
||||
void IRKelvinatorAC::setTurbo(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setTurbo(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_TURBO;
|
||||
remote_state[2] |= (state << KELVINATOR_TURBO_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool IRKelvinatorAC::getTurbo() {
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getTurbo() {
|
||||
return ((remote_state[2] & KELVINATOR_TURBO) != 0);
|
||||
}
|
||||
|
||||
@@ -17,31 +17,31 @@ IRMitsubishiAC::IRMitsubishiAC(int pin) : _irsend(pin) {
|
||||
}
|
||||
|
||||
// Reset the state of the remote to a known good state/sequence.
|
||||
void IRMitsubishiAC::stateReset() {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::stateReset() {
|
||||
for (uint8_t i = 0; i < MITSUBISHI_AC_STATE_LENGTH; i++)
|
||||
remote_state[i] = known_good_state[i];
|
||||
checksum(); // Calculate the checksum
|
||||
}
|
||||
|
||||
// Configure the pin for output.
|
||||
void IRMitsubishiAC::begin() {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
// Send the current desired state to the IR LED.
|
||||
void IRMitsubishiAC::send() {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::send() {
|
||||
checksum(); // Ensure correct checksum before sending.
|
||||
_irsend.sendMitsubishiAC(remote_state);
|
||||
}
|
||||
|
||||
// Return a pointer to the internal state date of the remote.
|
||||
uint8_t* IRMitsubishiAC::getRaw() {
|
||||
uint8_t* ICACHE_FLASH_ATTR IRMitsubishiAC::getRaw() {
|
||||
checksum();
|
||||
return remote_state;
|
||||
}
|
||||
|
||||
// Calculate the checksum for the current internal state of the remote.
|
||||
void IRMitsubishiAC::checksum() {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::checksum() {
|
||||
uint8_t sum = 0;
|
||||
// Checksum is simple addition of all previous bytes stored
|
||||
// as a 8 bit value.
|
||||
@@ -51,19 +51,19 @@ void IRMitsubishiAC::checksum() {
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C to off.
|
||||
void IRMitsubishiAC::on() {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::on() {
|
||||
//state = ON;
|
||||
remote_state[5] |= MITSUBISHI_AC_POWER;
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C to off.
|
||||
void IRMitsubishiAC::off() {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::off() {
|
||||
//state = OFF;
|
||||
remote_state[5] &= ~MITSUBISHI_AC_POWER;
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C.
|
||||
void IRMitsubishiAC::setPower(bool state) {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setPower(bool state) {
|
||||
if (state)
|
||||
on();
|
||||
else
|
||||
@@ -71,25 +71,25 @@ void IRMitsubishiAC::setPower(bool state) {
|
||||
}
|
||||
|
||||
// Return the requested power state of the A/C.
|
||||
bool IRMitsubishiAC::getPower() {
|
||||
bool ICACHE_FLASH_ATTR IRMitsubishiAC::getPower() {
|
||||
return((remote_state[5] & MITSUBISHI_AC_POWER) != 0);
|
||||
}
|
||||
|
||||
// Set the temp. in deg C
|
||||
void IRMitsubishiAC::setTemp(uint8_t temp) {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setTemp(uint8_t temp) {
|
||||
temp = max(MITSUBISHI_AC_MIN_TEMP, temp);
|
||||
temp = min(MITSUBISHI_AC_MAX_TEMP, temp);
|
||||
remote_state[7] = temp - MITSUBISHI_AC_MIN_TEMP;
|
||||
}
|
||||
|
||||
// Return the set temp. in deg C
|
||||
uint8_t IRMitsubishiAC::getTemp() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getTemp() {
|
||||
return(remote_state[7] + MITSUBISHI_AC_MIN_TEMP);
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-6.
|
||||
// 0 is auto, 1-5 is the speed, 6 is silent.
|
||||
void IRMitsubishiAC::setFan(uint8_t fan) {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setFan(uint8_t fan) {
|
||||
// Bounds check
|
||||
if (fan > MITSUBISHI_AC_FAN_SILENT)
|
||||
fan = MITSUBISHI_AC_FAN_MAX; // Set the fan to maximum if out of range.
|
||||
@@ -103,7 +103,7 @@ void IRMitsubishiAC::setFan(uint8_t fan) {
|
||||
}
|
||||
|
||||
// Return the requested state of the unit's fan.
|
||||
uint8_t IRMitsubishiAC::getFan() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getFan() {
|
||||
uint8_t fan = remote_state[9] & B111;
|
||||
if (fan == MITSUBISHI_AC_FAN_MAX)
|
||||
return MITSUBISHI_AC_FAN_SILENT;
|
||||
@@ -111,7 +111,7 @@ uint8_t IRMitsubishiAC::getFan() {
|
||||
}
|
||||
|
||||
// Return the requested climate operation mode of the a/c unit.
|
||||
uint8_t IRMitsubishiAC::getMode() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getMode() {
|
||||
/*
|
||||
MITSUBISHI_AC_AUTO
|
||||
MITSUBISHI_AC_COOL
|
||||
@@ -122,7 +122,7 @@ uint8_t IRMitsubishiAC::getMode() {
|
||||
}
|
||||
|
||||
// Set the requested climate operation mode of the a/c unit.
|
||||
void IRMitsubishiAC::setMode(uint8_t mode) {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setMode(uint8_t mode) {
|
||||
// If we get an unexpected mode, default to AUTO.
|
||||
switch (mode) {
|
||||
case MITSUBISHI_AC_AUTO: break;
|
||||
@@ -135,7 +135,7 @@ void IRMitsubishiAC::setMode(uint8_t mode) {
|
||||
}
|
||||
|
||||
// Set the requested vane operation mode of the a/c unit.
|
||||
void IRMitsubishiAC::setVane(uint8_t mode) {
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setVane(uint8_t mode) {
|
||||
mode = max(mode, B111); // bounds check
|
||||
mode |= B1000;
|
||||
mode <<= 3;
|
||||
@@ -143,6 +143,6 @@ void IRMitsubishiAC::setVane(uint8_t mode) {
|
||||
}
|
||||
|
||||
// Return the requested vane operation mode of the a/c unit.
|
||||
uint8_t IRMitsubishiAC::getVane() {
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getVane() {
|
||||
return ((remote_state[9] & B00111000) >> 3);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,7 @@
|
||||
#define IRremote_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "IRremoteInt.h"
|
||||
|
||||
// The following are compile-time library options.
|
||||
// If you change them, recompile the library.
|
||||
@@ -68,7 +69,8 @@ enum decode_type_t {
|
||||
DENON,
|
||||
KELVINATOR,
|
||||
SHERWOOD,
|
||||
MITSUBISHI_AC
|
||||
MITSUBISHI_AC,
|
||||
RCMM
|
||||
};
|
||||
|
||||
// Results returned from the decoder
|
||||
@@ -89,30 +91,33 @@ public:
|
||||
// Decoded value for NEC when a repeat code is received
|
||||
#define REPEAT 0xffffffff
|
||||
|
||||
#define SEND_PROTOCOL_NEC case NEC: sendNEC(data, nbits); break;
|
||||
#define SEND_PROTOCOL_SONY case SONY: sendSony(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC5 case RC5: sendRC5(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC6 case RC6: sendRC6(data, nbits); break;
|
||||
#define SEND_PROTOCOL_DISH case DISH: sendDISH(data, nbits); break;
|
||||
#define SEND_PROTOCOL_JVC case JVC: sendJVC(data, nbits, 0); break;
|
||||
#define SEND_PROTOCOL_SAMSUNG case SAMSUNG: sendSAMSUNG(data, nbits); break;
|
||||
#define SEND_PROTOCOL_LG case LG: sendLG(data, nbits); break;
|
||||
#define SEND_PROTOCOL_WHYNTER case WHYNTER: sendWhynter(data, nbits); break;
|
||||
#define SEND_PROTOCOL_COOLIX case COOLIX: sendCOOLIX(data, nbits); break;
|
||||
#define SEND_PROTOCOL_DENON case DENON: sendDenon(data, nbits); break;
|
||||
#define SEND_PROTOCOL_NEC case NEC: sendNEC(data, nbits); break;
|
||||
#define SEND_PROTOCOL_SONY case SONY: sendSony(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC5 case RC5: sendRC5(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC6 case RC6: sendRC6(data, nbits); break;
|
||||
#define SEND_PROTOCOL_DISH case DISH: sendDISH(data, nbits); break;
|
||||
#define SEND_PROTOCOL_JVC case JVC: sendJVC(data, nbits, 0); break;
|
||||
#define SEND_PROTOCOL_SAMSUNG case SAMSUNG: sendSAMSUNG(data, nbits); break;
|
||||
#define SEND_PROTOCOL_LG case LG: sendLG(data, nbits); break;
|
||||
#define SEND_PROTOCOL_WHYNTER case WHYNTER: sendWhynter(data, nbits); break;
|
||||
#define SEND_PROTOCOL_COOLIX case COOLIX: sendCOOLIX(data, nbits); break;
|
||||
#define SEND_PROTOCOL_DENON case DENON: sendDenon(data, nbits); break;
|
||||
#define SEND_PROTOCOL_SHERWOOD case SHERWOOD: sendSherwood(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RCMM case RCMM: sendRCMM(data, nbits); break;
|
||||
|
||||
|
||||
// main class for receiving IR
|
||||
class IRrecv
|
||||
{
|
||||
public:
|
||||
IRrecv(int recvpin);
|
||||
bool decode(decode_results *results);
|
||||
bool decode(decode_results *results, irparams_t *save=NULL);
|
||||
void enableIRIn();
|
||||
void disableIRIn();
|
||||
void resume();
|
||||
private:
|
||||
// These are called by decode
|
||||
void copyIrParams(irparams_t *dest);
|
||||
int getRClevel(decode_results *results, int *offset, int *used, int t1);
|
||||
bool decodeNEC(decode_results *results);
|
||||
bool decodeSony(decode_results *results);
|
||||
@@ -120,6 +125,7 @@ public:
|
||||
bool decodeMitsubishi(decode_results *results);
|
||||
bool decodeRC5(decode_results *results);
|
||||
bool decodeRC6(decode_results *results);
|
||||
bool decodeRCMM(decode_results *results);
|
||||
bool decodePanasonic(decode_results *results);
|
||||
bool decodeLG(decode_results *results);
|
||||
bool decodeJVC(decode_results *results);
|
||||
@@ -131,6 +137,14 @@ public:
|
||||
bool decodeDaikin(decode_results *results);
|
||||
bool decodeDenon(decode_results *results);
|
||||
int compare(unsigned int oldval, unsigned int newval);
|
||||
uint32_t ticksLow(uint32_t usecs, uint8_t tolerance=TOLERANCE);
|
||||
uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance=TOLERANCE);
|
||||
bool match(uint32_t measured_ticks, uint32_t desired_us,
|
||||
uint8_t tolerance=TOLERANCE);
|
||||
bool matchMark(uint32_t measured_ticks, uint32_t desired_us,
|
||||
uint8_t tolerance=TOLERANCE, int excess=MARK_EXCESS);
|
||||
bool matchSpace(uint32_t measured_ticks, uint32_t desired_us,
|
||||
uint8_t tolerance=TOLERANCE, int excess=MARK_EXCESS);
|
||||
};
|
||||
|
||||
// Only used for testing; can remove virtual for shorter code
|
||||
@@ -139,6 +153,7 @@ public:
|
||||
#else
|
||||
#define VIRTUAL
|
||||
#endif
|
||||
|
||||
class IRsend
|
||||
{
|
||||
public:
|
||||
@@ -158,12 +173,13 @@ public:
|
||||
SEND_PROTOCOL_COOLIX
|
||||
SEND_PROTOCOL_DENON
|
||||
SEND_PROTOCOL_SHERWOOD
|
||||
SEND_PROTOCOL_RCMM
|
||||
}
|
||||
};
|
||||
void sendCOOLIX(unsigned long data, int nbits);
|
||||
void sendWhynter(unsigned long data, int nbits);
|
||||
void sendNEC(unsigned long data, int nbits=32, unsigned int repeat=0);
|
||||
void sendLG(unsigned long data, int nbits);
|
||||
void sendLG(unsigned long data, int nbits=28, unsigned int repeat=0);
|
||||
// sendSony() should typically be called with repeat=2 as Sony devices
|
||||
// expect the code to be sent at least 3 times. (code + 2 repeats = 3 codes)
|
||||
// As the legacy use of this procedure was only to send a single code
|
||||
@@ -176,15 +192,19 @@ public:
|
||||
void sendGC(unsigned int buf[], int len);
|
||||
void sendRC5(unsigned long data, int nbits);
|
||||
void sendRC6(unsigned long data, int nbits);
|
||||
void sendDISH(unsigned long data, int nbits);
|
||||
void sendRCMM(uint32_t data, uint8_t nbits=24);
|
||||
// sendDISH() should typically be called with repeat=3 as DISH devices
|
||||
// expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes)
|
||||
// As the legacy use of this procedure was only to send a single code
|
||||
// it defaults to repeat=0 for backward compatiblity.
|
||||
void sendDISH(unsigned long data, int nbits, unsigned int repeat=0);
|
||||
void sendSharp(unsigned int address, unsigned int command);
|
||||
void sendSharpRaw(unsigned long data, int nbits);
|
||||
void sendPanasonic(unsigned int address, unsigned long data);
|
||||
void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does.
|
||||
void sendSAMSUNG(unsigned long data, int nbits);
|
||||
void sendDaikin(unsigned char daikin[]);
|
||||
void sendDaikinChunk(unsigned char buf[], int len, int start);
|
||||
void sendDenon(unsigned long data, int nbits);
|
||||
void sendJVC(unsigned long data, int nbits, unsigned int repeat=0);
|
||||
void sendSAMSUNG(unsigned long data, int nbits=32);
|
||||
void sendDaikin(unsigned char data[]);
|
||||
void sendDenon(unsigned long data, int nbits=14);
|
||||
void sendKelvinator(unsigned char data[]);
|
||||
void sendSherwood(unsigned long data, int nbits=32, unsigned int repeat=1);
|
||||
void sendMitsubishiAC(unsigned char data[]);
|
||||
@@ -210,12 +230,4 @@ private:
|
||||
uint32_t start;
|
||||
};
|
||||
|
||||
// Some useful constants
|
||||
#define USECPERTICK 50 // microseconds per clock interrupt tick
|
||||
#define RAWBUF 100 // Length of raw duration buffer
|
||||
|
||||
// Marks tend to be 100us too long, and spaces 100us too short
|
||||
// when received due to sensor lag.
|
||||
#define MARK_EXCESS 100
|
||||
|
||||
#endif
|
||||
|
||||
@@ -60,10 +60,11 @@
|
||||
#define NEC_RPT_SPACE 2250
|
||||
#define NEC_MIN_COMMAND_LENGTH 108000UL
|
||||
|
||||
// Timings based on http://www.sbprojects.com/knowledge/ir/sirc.php
|
||||
#define SONY_HDR_MARK 2400
|
||||
#define SONY_HDR_SPACE 600
|
||||
#define SONY_ONE_MARK 1200
|
||||
#define SONY_ZERO_MARK 600
|
||||
#define SONY_ONE_MARK 1250 // Experiments suggest +50 to spec is better.
|
||||
#define SONY_ZERO_MARK 650 // Experiments suggest +50 to spec is better.
|
||||
#define SONY_RPT_LENGTH 45000
|
||||
#define SONY_DOUBLE_SPACE_USECS 500 // usually see 713 - not using ticks as get number wrapround
|
||||
|
||||
@@ -105,6 +106,20 @@
|
||||
#define RC6_T1 444
|
||||
#define RC6_RPT_LENGTH 46000
|
||||
|
||||
// http://www.sbprojects.com/knowledge/ir/rcmm.php
|
||||
#define RCMM_HDR_MARK 416
|
||||
#define RCMM_HDR_SPACE 277
|
||||
#define RCMM_BIT_MARK 166
|
||||
#define RCMM_BIT_SPACE_0 277
|
||||
#define RCMM_BIT_SPACE_1 444
|
||||
#define RCMM_BIT_SPACE_2 611
|
||||
#define RCMM_BIT_SPACE_3 777
|
||||
#define RCMM_RPT_LENGTH 27778
|
||||
#define RCMM_MIN_GAP 3360
|
||||
// Use a tolerance of +/-10% when matching some data spaces.
|
||||
#define RCMM_TOLERANCE 10
|
||||
#define RCMM_EXCESS 50
|
||||
|
||||
#define SHARP_BIT_MARK 245
|
||||
#define SHARP_ONE_SPACE 1805
|
||||
#define SHARP_ZERO_SPACE 795
|
||||
@@ -118,13 +133,13 @@
|
||||
#define DISH_ONE_SPACE 1700
|
||||
#define DISH_ZERO_SPACE 2800
|
||||
#define DISH_RPT_SPACE 6200
|
||||
#define DISH_TOP_BIT 0x8000
|
||||
|
||||
#define PANASONIC_HDR_MARK 3502
|
||||
#define PANASONIC_HDR_SPACE 1750
|
||||
#define PANASONIC_BIT_MARK 502
|
||||
#define PANASONIC_ONE_SPACE 1244
|
||||
#define PANASONIC_ZERO_SPACE 400
|
||||
// Ref: http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152
|
||||
#define PANASONIC_HDR_MARK 3456
|
||||
#define PANASONIC_HDR_SPACE 1728
|
||||
#define PANASONIC_BIT_MARK 432
|
||||
#define PANASONIC_ONE_SPACE 1296
|
||||
#define PANASONIC_ZERO_SPACE 432
|
||||
|
||||
#define JVC_HDR_MARK 8000
|
||||
#define JVC_HDR_SPACE 4000
|
||||
@@ -184,15 +199,18 @@
|
||||
#define KELVINATOR_GAP_SPACE 19950U
|
||||
#define KELVINATOR_CMD_FOOTER 2U
|
||||
|
||||
#define TOLERANCE 25 // percent tolerance in measurements
|
||||
#define LTOL (1.0 - TOLERANCE/100.)
|
||||
#define UTOL (1.0 + TOLERANCE/100.)
|
||||
// Some useful constants
|
||||
#define USECPERTICK 50 // microseconds per clock interrupt tick
|
||||
#define RAWBUF 100 // Length of raw duration buffer
|
||||
|
||||
// Marks tend to be 100us too long, and spaces 100us too short
|
||||
// when received due to sensor lag.
|
||||
#define MARK_EXCESS 100
|
||||
|
||||
#define _GAP 5000 // Minimum map between transmissions
|
||||
#define GAP_TICKS (_GAP/USECPERTICK)
|
||||
|
||||
#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
|
||||
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
|
||||
#define TOLERANCE 25 // default percent tolerance in measurements
|
||||
|
||||
// receiver states
|
||||
#define STATE_IDLE 2
|
||||
@@ -200,14 +218,18 @@
|
||||
#define STATE_SPACE 4
|
||||
#define STATE_STOP 5
|
||||
|
||||
#define RAWBUF 100 // Length of raw duration buffer
|
||||
|
||||
// information for the interrupt handler
|
||||
typedef struct {
|
||||
uint8_t recvpin; // pin for IR data from detector
|
||||
uint8_t rcvstate; // state machine
|
||||
unsigned int timer; // state timer, counts 50uS ticks.
|
||||
unsigned int rawbuf[RAWBUF]; // raw data
|
||||
uint8_t rawlen; // counter of entries in rawbuf
|
||||
uint8_t overflow;
|
||||
uint8_t recvpin; // pin for IR data from detector
|
||||
uint8_t rcvstate; // state machine
|
||||
unsigned int timer; // state timer, counts 50uS ticks.
|
||||
unsigned int rawbuf[RAWBUF]; // raw data
|
||||
// uint16_t is used for rawlen as it saves 3 bytes of iram in the interrupt
|
||||
// handler. Don't ask why, I don't know. It just does.
|
||||
uint16_t rawlen; // counter of entries in rawbuf.
|
||||
uint8_t overflow; // Buffer overflow indicator.
|
||||
}
|
||||
irparams_t;
|
||||
|
||||
|
||||
@@ -18,6 +18,15 @@ Seb's notes : I also changed the pulse parameters for Samsung, update the Panaso
|
||||
5. Restart your Arduino ide
|
||||
6. Check out the examples
|
||||
|
||||
###### Using Git to install library ( Linux )
|
||||
```
|
||||
cd ~/Arduino/libraries
|
||||
git clone https://github.com/markszabo/IRremoteESP8266.git
|
||||
```
|
||||
###### To Update to the latest version of the library
|
||||
`
|
||||
cd ~/Arduino/libraries/IRremoteESP8266 && git pull
|
||||
`
|
||||
## Contributing
|
||||
If you want to contribute to this project:
|
||||
- Report bugs and errors
|
||||
|
||||
@@ -26,7 +26,7 @@ void handleIr(){
|
||||
for (uint8_t i=0; i<server.args(); i++){
|
||||
if(server.argName(i) == "code")
|
||||
{
|
||||
unsigned long code = server.arg(i).toInt();
|
||||
unsigned long code = strtoul(server.arg(i).c_str(), NULL, 10);
|
||||
irsend.sendNEC(code, 32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,39 @@
|
||||
/*
|
||||
* IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv
|
||||
* An IR detector/demodulator must be connected to the input RECV_PIN.
|
||||
* Version 0.1 Sept, 2015
|
||||
* Example circuit diagram:
|
||||
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving
|
||||
* Changes:
|
||||
* Version 0.2 April, 2017
|
||||
* - Decode from a copy of the data so we can start capturing faster thus
|
||||
* reduce the likelihood of miscaptures.
|
||||
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com
|
||||
*/
|
||||
|
||||
#include <IRremoteESP8266.h>
|
||||
|
||||
int RECV_PIN = 2; //an IR detector/demodulator is connected to GPIO pin 2
|
||||
// An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU board).
|
||||
int RECV_PIN = 14;
|
||||
|
||||
IRrecv irrecv(RECV_PIN);
|
||||
|
||||
void setup ( )
|
||||
{
|
||||
Serial.begin(9600); // Status message will be sent to PC at 9600 baud
|
||||
decode_results results; // Somewhere to store the results
|
||||
irparams_t save; // A place to copy the interrupt state while decoding.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY); // Status message will be sent to the PC at 115200 baud
|
||||
irrecv.enableIRIn(); // Start the receiver
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Display IR code
|
||||
//
|
||||
void ircode (decode_results *results)
|
||||
{
|
||||
void ircode(decode_results *results) {
|
||||
// Panasonic has an Address
|
||||
if (results->decode_type == PANASONIC) {
|
||||
Serial.print(results->panasonicAddress, HEX);
|
||||
Serial.print(":");
|
||||
}
|
||||
|
||||
// Print Code
|
||||
Serial.print(results->value, HEX);
|
||||
}
|
||||
@@ -35,8 +41,7 @@ void ircode (decode_results *results)
|
||||
//+=============================================================================
|
||||
// Display encoding type
|
||||
//
|
||||
void encoding (decode_results *results)
|
||||
{
|
||||
void encoding(decode_results *results) {
|
||||
switch (results->decode_type) {
|
||||
default:
|
||||
case UNKNOWN: Serial.print("UNKNOWN"); break ;
|
||||
@@ -54,14 +59,14 @@ void encoding (decode_results *results)
|
||||
case WHYNTER: Serial.print("WHYNTER"); break ;
|
||||
case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break ;
|
||||
case PANASONIC: Serial.print("PANASONIC"); break ;
|
||||
case DENON: Serial.print("DENON"); break ;
|
||||
}
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Dump out the decode_results structure.
|
||||
//
|
||||
void dumpInfo (decode_results *results)
|
||||
{
|
||||
void dumpInfo (decode_results *results) {
|
||||
if (results->overflow) {
|
||||
Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWBUF");
|
||||
return;
|
||||
@@ -83,8 +88,7 @@ void dumpInfo (decode_results *results)
|
||||
//+=============================================================================
|
||||
// Dump out the decode_results structure.
|
||||
//
|
||||
void dumpRaw (decode_results *results)
|
||||
{
|
||||
void dumpRaw(decode_results *results) {
|
||||
// Print Raw data
|
||||
Serial.print("Timing[");
|
||||
Serial.print(results->rawlen-1, DEC);
|
||||
@@ -113,8 +117,7 @@ void dumpRaw (decode_results *results)
|
||||
//+=============================================================================
|
||||
// Dump out the decode_results structure.
|
||||
//
|
||||
void dumpCode (decode_results *results)
|
||||
{
|
||||
void dumpCode (decode_results *results) {
|
||||
// Start declaration
|
||||
Serial.print("unsigned int "); // variable type
|
||||
Serial.print("rawData["); // array name
|
||||
@@ -129,7 +132,7 @@ void dumpCode (decode_results *results)
|
||||
}
|
||||
|
||||
// End declaration
|
||||
Serial.print("};"); //
|
||||
Serial.print("};"); //
|
||||
|
||||
// Comment
|
||||
Serial.print(" // ");
|
||||
@@ -142,7 +145,6 @@ void dumpCode (decode_results *results)
|
||||
|
||||
// Now dump "known" codes
|
||||
if (results->decode_type != UNKNOWN) {
|
||||
|
||||
// Some protocols have an address
|
||||
if (results->decode_type == PANASONIC) {
|
||||
Serial.print("unsigned int addr = 0x");
|
||||
@@ -160,15 +162,12 @@ void dumpCode (decode_results *results)
|
||||
//+=============================================================================
|
||||
// The repeating section of the code
|
||||
//
|
||||
void loop ( )
|
||||
{
|
||||
decode_results results; // Somewhere to store the results
|
||||
|
||||
if (irrecv.decode(&results)) { // Grab an IR code
|
||||
void loop() {
|
||||
// Check if the IR code has been received.
|
||||
if (irrecv.decode(&results, &save)) {
|
||||
dumpInfo(&results); // Output the results
|
||||
dumpRaw(&results); // Output the results in RAW format
|
||||
dumpCode(&results); // Output the results as source code
|
||||
Serial.println(""); // Blank line between entries
|
||||
irrecv.resume(); // Prepare for the next value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,40 @@
|
||||
/*
|
||||
* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend
|
||||
* An IR LED must be connected to ESP8266 pin 0.
|
||||
* Version 0.1 June, 2015
|
||||
* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend.
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
* Suggested circuit:
|
||||
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
|
||||
*
|
||||
* Common mistakes & tips:
|
||||
* * Don't just connect the IR LED directly to the pin, it won't
|
||||
* have enough current to drive the IR LED effectively.
|
||||
* * Make sure you have the IR LED polarity correct.
|
||||
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
|
||||
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
|
||||
* Replace the IR LED with a normal LED if you don't have a digital camera
|
||||
* when debugging.
|
||||
* * Avoid using the following pins unless you really know what you are doing:
|
||||
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
|
||||
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
|
||||
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
|
||||
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
|
||||
* for your first time. e.g. ESP-12 etc.
|
||||
*
|
||||
* Version 1.0 April, 2017
|
||||
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com
|
||||
*/
|
||||
|
||||
#include <IRremoteESP8266.h>
|
||||
|
||||
IRsend irsend(0); //an IR led is connected to GPIO pin 0
|
||||
IRsend irsend(4); //an IR led is connected to GPIO pin 4 (D2)
|
||||
|
||||
void setup()
|
||||
{
|
||||
irsend.begin();
|
||||
Serial.begin(9600);
|
||||
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
@@ -20,6 +42,6 @@ void loop() {
|
||||
irsend.sendNEC(0x00FFE01FUL, 32);
|
||||
delay(2000);
|
||||
Serial.println("Sony");
|
||||
irsend.sendSony(0xa90, 12);
|
||||
irsend.sendSony(0xa90, 12, 2);
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "IRremoteESP8266",
|
||||
"version": "1.0.2",
|
||||
"version": "1.2.0",
|
||||
"keywords": "infrared, ir, remote, esp8266",
|
||||
"description": "Send and receive infrared signals with multiple protocols (ESP8266)",
|
||||
"repository":
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name=IRremoteESP8266
|
||||
version=1.0.2
|
||||
version=1.2.0
|
||||
author=Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran
|
||||
maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto
|
||||
sentence=Send and receive infrared signals with multiple protocols (ESP8266)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,241 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "QEIx4.h"
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// bit masks for state machine - don't change!!!
|
||||
#define QEIx4_STATE 0xC
|
||||
#define QEIx4_MASK 0x1C
|
||||
#define QEIx4_1x_INC 0x0100
|
||||
#define QEIx4_2x_INC 0x0200
|
||||
#define QEIx4_4x_INC 0x0400
|
||||
#define QEIx4_1x_DEC 0x1000
|
||||
#define QEIx4_2x_DEC 0x2000
|
||||
#define QEIx4_4x_DEC 0x4000
|
||||
#define QEIx4_1x_MASK 0x11FF
|
||||
#define QEIx4_2x_MASK 0x33FF
|
||||
#define QEIx4_4x_MASK 0x77FF
|
||||
#define QEIx4_DIR 0x20
|
||||
#define QEIx4_A 1
|
||||
#define QEIx4_B 2
|
||||
#define QEIx4_AB 3
|
||||
#define QEIx4_S0 0x0
|
||||
#define QEIx4_S1 0x4
|
||||
#define QEIx4_S2 0x8
|
||||
#define QEIx4_S3 0xC
|
||||
#define QEIx4_CCW 0
|
||||
#define QEIx4_CW 0x10
|
||||
#define QEIx4_IS_CHG 0x7700
|
||||
#define QEIx4_IS_INC 0x0700
|
||||
#define QEIx4_IS_DEC 0x7000
|
||||
#define QEIx4_IS_DIR 0x20
|
||||
|
||||
// state machine for decoting - don't change!!!
|
||||
uint16_t QEIx4::__stateLUT[32] = {
|
||||
// act state S0 in CCW direction
|
||||
QEIx4_CCW | QEIx4_S0,
|
||||
QEIx4_CW | QEIx4_S1 | QEIx4_A | QEIx4_4x_INC | QEIx4_DIR,
|
||||
QEIx4_CCW | QEIx4_S0 | QEIx4_B,
|
||||
QEIx4_CCW | QEIx4_S3 | QEIx4_AB | QEIx4_1x_DEC,
|
||||
// act state S1 in CCW direction
|
||||
QEIx4_CCW | QEIx4_S1,
|
||||
QEIx4_CCW | QEIx4_S1 | QEIx4_A,
|
||||
QEIx4_CCW | QEIx4_S0 | QEIx4_B | QEIx4_4x_DEC,
|
||||
QEIx4_CW | QEIx4_S2 | QEIx4_AB | QEIx4_1x_INC | QEIx4_DIR,
|
||||
// act state S2 in CCW direction
|
||||
QEIx4_CCW | QEIx4_S1 | QEIx4_2x_DEC,
|
||||
QEIx4_CCW | QEIx4_S2 | QEIx4_A,
|
||||
QEIx4_CW | QEIx4_S3 | QEIx4_B | QEIx4_4x_INC | QEIx4_DIR,
|
||||
QEIx4_CCW | QEIx4_S2 | QEIx4_AB,
|
||||
// act state S3 in CCW direction
|
||||
QEIx4_CW | QEIx4_S0 | QEIx4_2x_INC | QEIx4_DIR,
|
||||
QEIx4_CCW | QEIx4_S2 | QEIx4_A | QEIx4_4x_DEC,
|
||||
QEIx4_CCW | QEIx4_S3 | QEIx4_B,
|
||||
QEIx4_CCW | QEIx4_S3 | QEIx4_AB,
|
||||
|
||||
// act state S0 in CW direction
|
||||
QEIx4_CW | QEIx4_S0,
|
||||
QEIx4_CW | QEIx4_S1 | QEIx4_A | QEIx4_4x_INC,
|
||||
QEIx4_CW | QEIx4_S0 | QEIx4_B,
|
||||
QEIx4_CCW | QEIx4_S3 | QEIx4_AB | QEIx4_1x_DEC | QEIx4_DIR,
|
||||
// act state S1 in CW direction
|
||||
QEIx4_CW | QEIx4_S1,
|
||||
QEIx4_CW | QEIx4_S1 | QEIx4_A,
|
||||
QEIx4_CCW | QEIx4_S0 | QEIx4_B | QEIx4_4x_DEC | QEIx4_DIR,
|
||||
QEIx4_CW | QEIx4_S2 | QEIx4_AB | QEIx4_1x_INC,
|
||||
// act state S2 in CW direction
|
||||
QEIx4_CCW | QEIx4_S1 | QEIx4_2x_DEC | QEIx4_DIR,
|
||||
QEIx4_CW | QEIx4_S2 | QEIx4_A,
|
||||
QEIx4_CW | QEIx4_S3 | QEIx4_B | QEIx4_4x_INC,
|
||||
QEIx4_CW | QEIx4_S2 | QEIx4_AB,
|
||||
// act state S3 in CW direction
|
||||
QEIx4_CW | QEIx4_S0 | QEIx4_2x_INC,
|
||||
QEIx4_CCW | QEIx4_S2 | QEIx4_A | QEIx4_4x_DEC | QEIx4_DIR,
|
||||
QEIx4_CW | QEIx4_S3 | QEIx4_B,
|
||||
QEIx4_CW | QEIx4_S3 | QEIx4_AB
|
||||
};
|
||||
|
||||
// Helper for ISR call
|
||||
QEIx4* QEIx4::__instance[4] = { 0 };
|
||||
|
||||
|
||||
//#define DEB(x) printf (x)
|
||||
#define DEB(x)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QEIx4::QEIx4()
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
if (__instance[i] == 0)
|
||||
{
|
||||
__instance[i] = this;
|
||||
DEB("::");
|
||||
break;
|
||||
}
|
||||
|
||||
_pinA = -1;
|
||||
_pinB = -1;
|
||||
_pinI = -1;
|
||||
_state = 0;
|
||||
_limitMin = LONG_MIN;
|
||||
_limitMax = LONG_MAX;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QEIx4::~QEIx4()
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
if (__instance[i] == this)
|
||||
{
|
||||
__instance[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QEIx4::begin(int16_t pinA, int16_t pinB, int16_t pinI, uint8_t mode)
|
||||
{
|
||||
if (_pinA >= 0)
|
||||
detachInterrupt(digitalPinToInterrupt(_pinA));
|
||||
if (_pinB >= 0)
|
||||
detachInterrupt(digitalPinToInterrupt(_pinB));
|
||||
|
||||
_pinA = pinA;
|
||||
_pinB = pinB;
|
||||
_pinI = pinI;
|
||||
|
||||
_counter = 0;
|
||||
_bHasChanged = true;
|
||||
|
||||
if (mode == 1)
|
||||
_eventMask = QEIx4_1x_MASK;
|
||||
else if (mode == 2)
|
||||
_eventMask = QEIx4_2x_MASK;
|
||||
else
|
||||
_eventMask = QEIx4_4x_MASK;
|
||||
|
||||
pinMode(_pinA, INPUT_PULLUP);
|
||||
pinMode(_pinB, INPUT_PULLUP);
|
||||
pinMode(_pinI, INPUT_PULLUP);
|
||||
|
||||
if (_pinA >= 0)
|
||||
attachInterrupt(digitalPinToInterrupt(_pinA), ISR, CHANGE);
|
||||
if (_pinB >= 0)
|
||||
attachInterrupt(digitalPinToInterrupt(_pinB), ISR, CHANGE);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
long QEIx4::read()
|
||||
{
|
||||
noInterrupts();
|
||||
_bHasChanged = false;
|
||||
long ret = _counter;
|
||||
interrupts();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void QEIx4::loop()
|
||||
{
|
||||
noInterrupts();
|
||||
processStateMachine();
|
||||
interrupts();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QEIx4::processStateMachine()
|
||||
{
|
||||
DEB(".");
|
||||
|
||||
_state &= QEIx4_MASK;
|
||||
if (digitalRead(_pinA)) _state |= QEIx4_A;
|
||||
if (digitalRead(_pinB)) _state |= QEIx4_B;
|
||||
|
||||
_state = __stateLUT[_state]; // magic is done by lookup-table
|
||||
_state &= _eventMask;
|
||||
|
||||
if (_state & QEIx4_IS_CHG) { // is any change?
|
||||
bool bCounterChange = false;
|
||||
|
||||
if ((_state & QEIx4_IS_INC) && (_counter < _limitMax)) { // has moved foreward?
|
||||
_counter++;
|
||||
bCounterChange = true;
|
||||
DEB("+");
|
||||
}
|
||||
if ((_state & QEIx4_IS_DEC) && (_counter > _limitMin)) { // has moved backward?
|
||||
_counter--;
|
||||
bCounterChange = true;
|
||||
DEB("-");
|
||||
}
|
||||
|
||||
if (_pinI >= 0 && _bIndexTrigger && bCounterChange && digitalRead(_pinI)) { // is index pin triggered?
|
||||
_bIndexTrigger = false;
|
||||
_counter = 0;
|
||||
DEB("I");
|
||||
}
|
||||
|
||||
if (bCounterChange) { // has counter changed?
|
||||
_bHasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QEIx4::ISR()
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
if (__instance[i])
|
||||
{
|
||||
__instance[i]->processStateMachine();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,133 @@
|
||||
/*--------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
#ifndef QEIX4_H
|
||||
#define QEIX4_H
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
class QEIx4
|
||||
{
|
||||
public:
|
||||
|
||||
/** constructor of QEIx4 object
|
||||
*/
|
||||
QEIx4();
|
||||
|
||||
/** destructor of QEIx4 object
|
||||
*/
|
||||
~QEIx4();
|
||||
|
||||
void begin(int16_t pinA, int16_t pinB, int16_t pinI=-1, uint8_t mode=4);
|
||||
|
||||
/** Gets the actual counter value.
|
||||
*
|
||||
* @return Actual counter value
|
||||
*/
|
||||
long read();
|
||||
|
||||
/** Gets the actual counter value as long operator.
|
||||
*
|
||||
* @return Actual counter value as long operator
|
||||
*/
|
||||
operator long() { // int-Operator
|
||||
return read();
|
||||
}
|
||||
|
||||
/** Sets the counter value at actual encoder position to given value.
|
||||
*
|
||||
* @param Counter value
|
||||
*/
|
||||
void write(long counter) {
|
||||
_counter = counter;
|
||||
}
|
||||
|
||||
/** Sets the counter value at actual encoder position to given value as assign operator.
|
||||
*
|
||||
* @param Counter value
|
||||
*/
|
||||
int operator= (long counter) { // Assign-Operator
|
||||
write(counter);
|
||||
return counter;
|
||||
}
|
||||
|
||||
void setLimit(long limitMin, long limitMax)
|
||||
{
|
||||
_limitMin = limitMin;
|
||||
_limitMax = limitMax;
|
||||
}
|
||||
|
||||
/** Sets the flag for zeroing on next high on index pin while AB lines triggers next counting. The trigger calls tha callback function in which the counter can be set to zero or the actual counter can be latched in for later offset calculation
|
||||
*
|
||||
* @param Flag for triggering. Set to 1 for call the attached callback. It is reseted after this call
|
||||
*/
|
||||
void setIndexTrigger(bool bIndexTrigger=true) {
|
||||
if (_pinI < 0)
|
||||
bIndexTrigger = false;
|
||||
_bIndexTrigger = bIndexTrigger;
|
||||
}
|
||||
|
||||
bool hasChanged(){
|
||||
return _bHasChanged;
|
||||
}
|
||||
|
||||
void loop();
|
||||
|
||||
protected:
|
||||
|
||||
/** Polls the state machine and updates the counter value.
|
||||
*/
|
||||
void processStateMachine();
|
||||
|
||||
/** Entry point for arduino interrupts - route to class instances
|
||||
*/
|
||||
static void ISR();
|
||||
|
||||
protected:
|
||||
|
||||
volatile long _counter;
|
||||
volatile bool _bHasChanged;
|
||||
volatile bool _bIndexTrigger;
|
||||
|
||||
int16_t _pinA;
|
||||
int16_t _pinB;
|
||||
int16_t _pinI;
|
||||
long _limitMin;
|
||||
long _limitMax;
|
||||
uint16_t _state;
|
||||
uint16_t _eMode;
|
||||
|
||||
private:
|
||||
static uint16_t __stateLUT[32];
|
||||
static QEIx4* __instance[4];
|
||||
uint16_t _eventMask;
|
||||
};
|
||||
|
||||
#endif // QEIX4_H
|
||||
@@ -0,0 +1,28 @@
|
||||
# MechInputs Library (https://github.com/jkDesignDE/MechInputs)
|
||||
|
||||
Arduino library for reading and debouncing mechanical inputs Like buttons, switches and encoders.
|
||||
|
||||
After downloading, rename folder to 'MechInputs' and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->MechInputs->* sketches.
|
||||
|
||||
# QEI (quadrature encoder interface) library, for decoding AB signals from a rotary encoder
|
||||
|
||||
Use cases:
|
||||
- Rotary encoder in closed loop motor regulation
|
||||
- Hand wheel
|
||||
- Input device for motion control (MoCo)
|
||||
|
||||
|
||||
A class to decode pulses on a rotary encoder with AB signals (quadrature encoder).
|
||||
It uses all 4 edges of the AB signals to increase the counter resolution 4 times of cycles per rotation/revolution (CPR) (e.g. an encoder with 500 CPR get 2000 counts per rotation)
|
||||
|
||||
In opposite to most common QEI implementation this is resistant to jitter and chatter on AB signals and motor vibrations.
|
||||
Whes reaching the next position the edge that triggerd this position (state) is ignored to aboid oscillating up/down counts.
|
||||
|
||||
It can also be used in polling mode i.g. in idle routines if interrupts are not desired.
|
||||
At this mode be sure that the sampling frequency is heigher than the maximum rotation speed (expeced counts per second)
|
||||
|
||||
The internal state machine is based on a look up table (LUT) to minimize interrupt retention time and get all necessary flags at once.
|
||||
|
||||
The library is designed to support closed loop speed- and motion-controller for also slow and smooth motions like movie camera motion control.
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
name=MechInputs
|
||||
version=0.0.1
|
||||
author=Jochen Krapf
|
||||
maintainer=Jochen Krapf <jk@nerd2nerd.org>
|
||||
sentence=Library for Reading and Debouncing Mechanical Inputs Like Buttons, Switches and Encoders with Arduino-Based Controllers.
|
||||
paragraph=Library for Reading and Debouncing Mechanical Inputs Like Buttons, Switches and Encoders with Arduino-Based Controllers.
|
||||
category=Input
|
||||
url=https://github.com/jkDesignDE/MechInputs
|
||||
architectures=esp8266,avr
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,81 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include <SensorSerial.h>
|
||||
|
||||
|
||||
SensorSerial::SensorSerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize) : SoftwareSerial(receivePin, transmitPin, inverse_logic, buffSize)
|
||||
{
|
||||
//boolean sws = isValidGPIOpin(receivePin);
|
||||
_hw = receivePin < 0;
|
||||
}
|
||||
|
||||
void SensorSerial::begin(long speed)
|
||||
{
|
||||
if (_hw)
|
||||
Serial.begin(speed);
|
||||
else
|
||||
SoftwareSerial::begin(speed);
|
||||
}
|
||||
|
||||
int SensorSerial::peek()
|
||||
{
|
||||
if (_hw)
|
||||
return Serial.peek();
|
||||
else
|
||||
return SoftwareSerial::peek();
|
||||
}
|
||||
|
||||
size_t SensorSerial::write(uint8_t byte)
|
||||
{
|
||||
if (_hw)
|
||||
return Serial.write(byte);
|
||||
else
|
||||
return SoftwareSerial::write(byte);
|
||||
}
|
||||
|
||||
int SensorSerial::read()
|
||||
{
|
||||
if (_hw)
|
||||
return Serial.read();
|
||||
else
|
||||
return SoftwareSerial::read();
|
||||
}
|
||||
|
||||
int SensorSerial::available()
|
||||
{
|
||||
if (_hw)
|
||||
return Serial.available();
|
||||
else
|
||||
return SoftwareSerial::available();
|
||||
}
|
||||
|
||||
void SensorSerial::flush()
|
||||
{
|
||||
if (_hw)
|
||||
Serial.flush();
|
||||
else
|
||||
SoftwareSerial::flush();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _SENSORSERIAL_H_
|
||||
#define _SENSORSERIAL_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
class SensorSerial : public SoftwareSerial
|
||||
{
|
||||
public:
|
||||
SensorSerial(int receivePin, int transmitPin = -1, bool inverse_logic = false, unsigned int buffSize = 64);
|
||||
|
||||
void begin(long speed);
|
||||
|
||||
int peek();
|
||||
|
||||
virtual size_t write(uint8_t byte);
|
||||
|
||||
virtual int read();
|
||||
|
||||
virtual int available();
|
||||
|
||||
virtual void flush();
|
||||
|
||||
protected:
|
||||
boolean _hw;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "SensorSerialBuffer.h"
|
||||
|
||||
CSensorSerialBuffer::CSensorSerialBuffer()
|
||||
{
|
||||
_writeIndex = 0;
|
||||
_packetLength = 0;
|
||||
Clear();
|
||||
}
|
||||
|
||||
void CSensorSerialBuffer::Clear ()
|
||||
{
|
||||
for (byte i=0; i<SERIALBUFFER_SIZE; i++)
|
||||
_buffer[i] = 0;
|
||||
}
|
||||
|
||||
void CSensorSerialBuffer::AddData (byte b)
|
||||
{
|
||||
_buffer[_writeIndex] = b;
|
||||
_writeIndex++;
|
||||
_writeIndex &= SERIALBUFFER_MASK;
|
||||
}
|
||||
|
||||
void CSensorSerialBuffer::SetPacketLength (byte len)
|
||||
{
|
||||
_packetLength = len;
|
||||
}
|
||||
|
||||
byte& CSensorSerialBuffer::operator[] (byte x)
|
||||
{
|
||||
x += _writeIndex;
|
||||
x -= _packetLength;
|
||||
x &= SERIALBUFFER_MASK;
|
||||
return _buffer[x];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _SENSORSERIALBUFFER_H_
|
||||
#define _SENSORSERIALBUFFER_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define SERIALBUFFER_SIZE 32
|
||||
#define SERIALBUFFER_MASK 31
|
||||
|
||||
class CSensorSerialBuffer
|
||||
{
|
||||
public:
|
||||
CSensorSerialBuffer();
|
||||
|
||||
void Clear ();
|
||||
|
||||
void AddData (byte b);
|
||||
|
||||
void SetPacketLength (byte len);
|
||||
|
||||
byte& operator[] (byte x);
|
||||
|
||||
private:
|
||||
byte _buffer[SERIALBUFFER_SIZE];
|
||||
byte _writeIndex;
|
||||
byte _packetLength;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "jkSDS011.h"
|
||||
|
||||
CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX) : _serial(pinRX, pinTX)
|
||||
{
|
||||
_sws = ! ( pinRX < 0 || pinRX == 3 );
|
||||
_pm2_5 = NAN;
|
||||
_pm10_ = NAN;
|
||||
_available = false;
|
||||
_pm2_5avr = 0;
|
||||
_pm10_avr = 0;
|
||||
_avr = 0;
|
||||
_data.SetPacketLength(10);
|
||||
|
||||
_serial.begin(9600);
|
||||
}
|
||||
|
||||
void CjkSDS011::Process()
|
||||
{
|
||||
while (_serial.available())
|
||||
{
|
||||
_data.AddData(_serial.read());
|
||||
|
||||
if (_data[0] == 0xAA && _data[9] == 0xAB && (_data[1] == 0xC0 || _data[1] == 0xCF)) // correct packet frame?
|
||||
{
|
||||
byte checksum = 0;
|
||||
for (byte i=2; i<= 7; i++)
|
||||
checksum += _data[i];
|
||||
if (checksum != _data[8])
|
||||
continue;
|
||||
|
||||
if (_data[1] == 0xC0) // SDS011 or SDS018?
|
||||
{
|
||||
_pm2_5 = (float)((_data[3] << 8) | _data[2]) * 0.1;
|
||||
_pm10_ = (float)((_data[5] << 8) | _data[4]) * 0.1;
|
||||
_available = true;
|
||||
}
|
||||
else if (_data[1] == 0xCF) // SDS198?
|
||||
{
|
||||
_pm2_5 = (float)((_data[5] << 8) | _data[4]);
|
||||
_pm10_ = (float)((_data[3] << 8) | _data[2]);
|
||||
_available = true;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
_pm2_5avr += _pm2_5;
|
||||
_pm10_avr += _pm10_;
|
||||
_avr++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean CjkSDS011::available()
|
||||
{
|
||||
boolean ret = _available;
|
||||
_available = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CjkSDS011::ReadAverage(float &pm25, float &pm10)
|
||||
{
|
||||
if (_avr)
|
||||
{
|
||||
pm25 = _pm2_5avr / _avr;
|
||||
pm10 = _pm10_avr / _avr;
|
||||
_pm2_5avr = 0;
|
||||
_pm10_avr = 0;
|
||||
_avr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pm25 = NAN;
|
||||
pm10 = NAN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to ...
|
||||
|
||||
Written by Jochen Krapf,
|
||||
contributions by ... and other members of the open
|
||||
source community.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the MechInputs library.
|
||||
|
||||
MechInputs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
MechInputs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with MechInputs. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _jkSDS011_H_
|
||||
#define _jkSDS011_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SensorSerial.h"
|
||||
#include "SensorSerialBuffer.h"
|
||||
|
||||
class CjkSDS011
|
||||
{
|
||||
public:
|
||||
CjkSDS011(int16_t pinRX, int16_t pinTX);
|
||||
|
||||
void Process();
|
||||
|
||||
boolean available();
|
||||
|
||||
float GetPM2_5() { return _pm2_5; };
|
||||
float GetPM10_() { return _pm10_; };
|
||||
|
||||
void ReadAverage(float &pm25, float &pm10);
|
||||
|
||||
private:
|
||||
SensorSerial _serial;
|
||||
CSensorSerialBuffer _data;
|
||||
float _pm2_5;
|
||||
float _pm10_;
|
||||
float _pm2_5avr;
|
||||
float _pm10_avr;
|
||||
uint16_t _avr;
|
||||
boolean _available;
|
||||
boolean _sws;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
name=SerialSensors
|
||||
version=0.0.1
|
||||
author=Jochen Krapf
|
||||
maintainer=Jochen Krapf <jk@nerd2nerd.org>
|
||||
sentence=Library for Reading and Serial Data from Sensor Devices.
|
||||
paragraph=Library for Reading and Serial Data from Sensor Devices.
|
||||
category=Input
|
||||
url=https://github.com/jkDesignDE/SerialSensors
|
||||
architectures=esp8266,avr
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
License Information
|
||||
-------------------
|
||||
|
||||
The hardware is released under [Creative Commons Share-alike 3.0](http://creativecommons.org/licenses/by-sa/3.0/).
|
||||
|
||||
All other code is open source so please feel free to do anything you want with it; you buy me a beer if you use this and we meet someday ([Beerware license](http://en.wikipedia.org/wiki/Beerware)).
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
SparkFun APDS9960 RGB and Gesture Sensor Arduino Library
|
||||
=========================================================
|
||||
|
||||

|
||||
|
||||
[*Avago APDS-9960 Breakout Board (SEN-12787)*](https://www.sparkfun.com/products/12787)
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
* Download the Git repository as a ZIP ("Download ZIP" button)
|
||||
* Unzip
|
||||
* Copy the entire library directory (APDS-9960_RGB_and_Gesture_Sensor_Arduino_Library
|
||||
) to \<Arduino installation directory\>/libraries
|
||||
* Open the Arduino program
|
||||
* Select File -> Examples -> SparkFun_APDS9960 -> GestureTest
|
||||
* Plug in your Arduino and APDS-9960 with the following connections
|
||||
|
||||
*-OR-*
|
||||
|
||||
* Use the library manager
|
||||
|
||||
| Arduino Pin | APDS-9960 Board | Function |
|
||||
|---|---|---|
|
||||
| 3.3V | VCC | Power |
|
||||
| GND | GND | Ground |
|
||||
| A4 | SDA | I2C Data |
|
||||
| A5 | SCL | I2C Clock |
|
||||
| 2 | INT | Interrupt |
|
||||
|
||||
* Go to Tools -> Board and select your Arduino board
|
||||
* Go to Tools -> Serial Port and select the COM port of your Arduino board
|
||||
* Click "Upload"
|
||||
* Go to Tools -> Serial Monitor
|
||||
* Ensure the baud rate is set at 9600 baud
|
||||
* Swipe your hand over the sensor in various directions!
|
||||
|
||||
Repository Contents
|
||||
-------------------
|
||||
|
||||
* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE.
|
||||
* **/src** - Source files for the library (.cpp, .h).
|
||||
* **library.properties** - General library properties for the Arduino package manager.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
|
||||
* **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library.
|
||||
* **[Product Repository](https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor)** - Main repository (including hardware files) for the SparkFun_APDS9960 RGB and Gesture Sensor.
|
||||
* **[Hookup Guide](https://learn.sparkfun.com/tutorials/apds-9960-rgb-and-gesture-sensor-hookup-guide)** - Basic hookup guide for the sensor.
|
||||
|
||||
Products that use this Library
|
||||
---------------------------------
|
||||
|
||||
* [SEN-12787](https://www.sparkfun.com/products/12787)- Avago APDS-9960
|
||||
|
||||
Version History
|
||||
---------------
|
||||
* [V_1.4.1](https://github.com/sparkfun/SparkFun_APDS-9960_Sensor_Arduino_Library/tree/V_1.4.1) - Removing blank files, updating library.properties file.
|
||||
* [V_1.4.0](https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor_Arduino_Library/tree/V_1.4.0) - Updated to new library structure
|
||||
* V_1.3.0 - Implemented disableProximitySensor(). Thanks to jmg5150 for catching that!
|
||||
* V_1.2.0 - Added pinMode line to GestureTest demo to fix interrupt bug with some Arduinos
|
||||
* V_1.1.0 - Updated GestureTest demo to not freeze with fast swipes
|
||||
* V_1.0.0: Initial release
|
||||
* Ambient and RGB light sensing implemented
|
||||
* Ambient light interrupts working
|
||||
* Proximity sensing implemented
|
||||
* Proximity interrupts working
|
||||
* Gesture (UP, DOWN, LEFT, RIGHT, NEAR, FAR) sensing implemented
|
||||
|
||||
License Information
|
||||
-------------------
|
||||
|
||||
This product is _**open source**_!
|
||||
|
||||
The **code** is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round!
|
||||
|
||||
Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license.
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
|
||||
- Your friends at SparkFun.
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/****************************************************************
|
||||
AmbientLightInterrupt.ino
|
||||
APDS-9960 RGB and Gesture Sensor
|
||||
Shawn Hymel @ SparkFun Electronics
|
||||
October 24, 2014
|
||||
https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor
|
||||
|
||||
Tests the ambient light interrupt abilities of the APDS-9960.
|
||||
Configures the APDS-9960 over I2C and waits for an external
|
||||
interrupt based on high or low light conditions. Try covering
|
||||
the sensor with your hand or bringing the sensor close to a
|
||||
bright light source. You might need to adjust the LIGHT_INT_HIGH
|
||||
and LIGHT_INT_LOW values to get the interrupt to work correctly.
|
||||
|
||||
Hardware Connections:
|
||||
|
||||
IMPORTANT: The APDS-9960 can only accept 3.3V!
|
||||
|
||||
Arduino Pin APDS-9960 Board Function
|
||||
|
||||
3.3V VCC Power
|
||||
GND GND Ground
|
||||
A4 SDA I2C Data
|
||||
A5 SCL I2C Clock
|
||||
2 INT Interrupt
|
||||
13 - LED
|
||||
|
||||
Resources:
|
||||
Include Wire.h and SparkFun_APDS-9960.h
|
||||
|
||||
Development environment specifics:
|
||||
Written in Arduino 1.0.5
|
||||
Tested with SparkFun Arduino Pro Mini 3.3V
|
||||
|
||||
This code is beerware; if you see me (or any other SparkFun
|
||||
employee) at the local, and you've found our code helpful, please
|
||||
buy us a round!
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
****************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
|
||||
// Pins
|
||||
#define APDS9960_INT 2 // Needs to be an interrupt pin
|
||||
#define LED_PIN 13 // LED for showing interrupt
|
||||
|
||||
// Constants
|
||||
#define LIGHT_INT_HIGH 1000 // High light level for interrupt
|
||||
#define LIGHT_INT_LOW 10 // Low light level for interrupt
|
||||
|
||||
// Global variables
|
||||
SparkFun_APDS9960 apds = SparkFun_APDS9960();
|
||||
uint16_t ambient_light = 0;
|
||||
uint16_t red_light = 0;
|
||||
uint16_t green_light = 0;
|
||||
uint16_t blue_light = 0;
|
||||
int isr_flag = 0;
|
||||
uint16_t threshold = 0;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Set LED as output
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
pinMode(APDS9960_INT, INPUT);
|
||||
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("-------------------------------------"));
|
||||
Serial.println(F("SparkFun APDS-9960 - Light Interrupts"));
|
||||
Serial.println(F("-------------------------------------"));
|
||||
|
||||
// Initialize interrupt service routine
|
||||
attachInterrupt(0, interruptRoutine, FALLING);
|
||||
|
||||
// Initialize APDS-9960 (configure I2C and initial values)
|
||||
if ( apds.init() ) {
|
||||
Serial.println(F("APDS-9960 initialization complete"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during APDS-9960 init!"));
|
||||
}
|
||||
|
||||
// Set high and low interrupt thresholds
|
||||
if ( !apds.setLightIntLowThreshold(LIGHT_INT_LOW) ) {
|
||||
Serial.println(F("Error writing low threshold"));
|
||||
}
|
||||
if ( !apds.setLightIntHighThreshold(LIGHT_INT_HIGH) ) {
|
||||
Serial.println(F("Error writing high threshold"));
|
||||
}
|
||||
|
||||
// Start running the APDS-9960 light sensor (no interrupts)
|
||||
if ( apds.enableLightSensor(false) ) {
|
||||
Serial.println(F("Light sensor is now running"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during light sensor init!"));
|
||||
}
|
||||
|
||||
// Read high and low interrupt thresholds
|
||||
if ( !apds.getLightIntLowThreshold(threshold) ) {
|
||||
Serial.println(F("Error reading low threshold"));
|
||||
} else {
|
||||
Serial.print(F("Low Threshold: "));
|
||||
Serial.println(threshold);
|
||||
}
|
||||
if ( !apds.getLightIntHighThreshold(threshold) ) {
|
||||
Serial.println(F("Error reading high threshold"));
|
||||
} else {
|
||||
Serial.print(F("High Threshold: "));
|
||||
Serial.println(threshold);
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
if ( !apds.setAmbientLightIntEnable(1) ) {
|
||||
Serial.println(F("Error enabling interrupts"));
|
||||
}
|
||||
|
||||
// Wait for initialization and calibration to finish
|
||||
delay(500);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// If interrupt occurs, print out the light levels
|
||||
if ( isr_flag == 1 ) {
|
||||
|
||||
// Read the light levels (ambient, red, green, blue) and print
|
||||
if ( !apds.readAmbientLight(ambient_light) ||
|
||||
!apds.readRedLight(red_light) ||
|
||||
!apds.readGreenLight(green_light) ||
|
||||
!apds.readBlueLight(blue_light) ) {
|
||||
Serial.println("Error reading light values");
|
||||
} else {
|
||||
Serial.print("Interrupt! Ambient: ");
|
||||
Serial.print(ambient_light);
|
||||
Serial.print(" R: ");
|
||||
Serial.print(red_light);
|
||||
Serial.print(" G: ");
|
||||
Serial.print(green_light);
|
||||
Serial.print(" B: ");
|
||||
Serial.println(blue_light);
|
||||
}
|
||||
|
||||
// Turn on LED for a half a second
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
// Reset flag and clear APDS-9960 interrupt (IMPORTANT!)
|
||||
isr_flag = 0;
|
||||
if ( !apds.clearAmbientLightInt() ) {
|
||||
Serial.println("Error clearing interrupt");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void interruptRoutine() {
|
||||
isr_flag = 1;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/****************************************************************
|
||||
ColorSensor.ino
|
||||
APDS-9960 RGB and Gesture Sensor
|
||||
Shawn Hymel @ SparkFun Electronics
|
||||
October 15, 2014
|
||||
https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor
|
||||
|
||||
Tests the color and ambient light sensing abilities of the
|
||||
APDS-9960. Configures APDS-9960 over I2C and polls the sensor for
|
||||
ambient light and color levels, which are displayed over the
|
||||
serial console.
|
||||
|
||||
Hardware Connections:
|
||||
|
||||
IMPORTANT: The APDS-9960 can only accept 3.3V!
|
||||
|
||||
Arduino Pin APDS-9960 Board Function
|
||||
|
||||
3.3V VCC Power
|
||||
GND GND Ground
|
||||
A4 SDA I2C Data
|
||||
A5 SCL I2C Clock
|
||||
|
||||
Resources:
|
||||
Include Wire.h and SparkFun_APDS-9960.h
|
||||
|
||||
Development environment specifics:
|
||||
Written in Arduino 1.0.5
|
||||
Tested with SparkFun Arduino Pro Mini 3.3V
|
||||
|
||||
This code is beerware; if you see me (or any other SparkFun
|
||||
employee) at the local, and you've found our code helpful, please
|
||||
buy us a round!
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
****************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
|
||||
// Global Variables
|
||||
SparkFun_APDS9960 apds = SparkFun_APDS9960();
|
||||
uint16_t ambient_light = 0;
|
||||
uint16_t red_light = 0;
|
||||
uint16_t green_light = 0;
|
||||
uint16_t blue_light = 0;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("--------------------------------"));
|
||||
Serial.println(F("SparkFun APDS-9960 - ColorSensor"));
|
||||
Serial.println(F("--------------------------------"));
|
||||
|
||||
// Initialize APDS-9960 (configure I2C and initial values)
|
||||
if ( apds.init() ) {
|
||||
Serial.println(F("APDS-9960 initialization complete"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during APDS-9960 init!"));
|
||||
}
|
||||
|
||||
// Start running the APDS-9960 light sensor (no interrupts)
|
||||
if ( apds.enableLightSensor(false) ) {
|
||||
Serial.println(F("Light sensor is now running"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during light sensor init!"));
|
||||
}
|
||||
|
||||
// Wait for initialization and calibration to finish
|
||||
delay(500);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Read the light levels (ambient, red, green, blue)
|
||||
if ( !apds.readAmbientLight(ambient_light) ||
|
||||
!apds.readRedLight(red_light) ||
|
||||
!apds.readGreenLight(green_light) ||
|
||||
!apds.readBlueLight(blue_light) ) {
|
||||
Serial.println("Error reading light values");
|
||||
} else {
|
||||
Serial.print("Ambient: ");
|
||||
Serial.print(ambient_light);
|
||||
Serial.print(" Red: ");
|
||||
Serial.print(red_light);
|
||||
Serial.print(" Green: ");
|
||||
Serial.print(green_light);
|
||||
Serial.print(" Blue: ");
|
||||
Serial.println(blue_light);
|
||||
}
|
||||
|
||||
// Wait 1 second before next reading
|
||||
delay(1000);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/****************************************************************
|
||||
GestureTest.ino
|
||||
APDS-9960 RGB and Gesture Sensor
|
||||
Shawn Hymel @ SparkFun Electronics
|
||||
May 30, 2014
|
||||
https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor
|
||||
|
||||
Tests the gesture sensing abilities of the APDS-9960. Configures
|
||||
APDS-9960 over I2C and waits for gesture events. Calculates the
|
||||
direction of the swipe (up, down, left, right) and displays it
|
||||
on a serial console.
|
||||
|
||||
To perform a NEAR gesture, hold your hand
|
||||
far above the sensor and move it close to the sensor (within 2
|
||||
inches). Hold your hand there for at least 1 second and move it
|
||||
away.
|
||||
|
||||
To perform a FAR gesture, hold your hand within 2 inches of the
|
||||
sensor for at least 1 second and then move it above (out of
|
||||
range) of the sensor.
|
||||
|
||||
Hardware Connections:
|
||||
|
||||
IMPORTANT: The APDS-9960 can only accept 3.3V!
|
||||
|
||||
Arduino Pin APDS-9960 Board Function
|
||||
|
||||
3.3V VCC Power
|
||||
GND GND Ground
|
||||
A4 SDA I2C Data
|
||||
A5 SCL I2C Clock
|
||||
2 INT Interrupt
|
||||
|
||||
Resources:
|
||||
Include Wire.h and SparkFun_APDS-9960.h
|
||||
|
||||
Development environment specifics:
|
||||
Written in Arduino 1.0.5
|
||||
Tested with SparkFun Arduino Pro Mini 3.3V
|
||||
|
||||
This code is beerware; if you see me (or any other SparkFun
|
||||
employee) at the local, and you've found our code helpful, please
|
||||
buy us a round!
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
****************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
|
||||
// Pins
|
||||
#define APDS9960_INT 2 // Needs to be an interrupt pin
|
||||
|
||||
// Constants
|
||||
|
||||
// Global Variables
|
||||
SparkFun_APDS9960 apds = SparkFun_APDS9960();
|
||||
int isr_flag = 0;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Set interrupt pin as input
|
||||
pinMode(APDS9960_INT, INPUT);
|
||||
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("--------------------------------"));
|
||||
Serial.println(F("SparkFun APDS-9960 - GestureTest"));
|
||||
Serial.println(F("--------------------------------"));
|
||||
|
||||
// Initialize interrupt service routine
|
||||
attachInterrupt(0, interruptRoutine, FALLING);
|
||||
|
||||
// Initialize APDS-9960 (configure I2C and initial values)
|
||||
if ( apds.init() ) {
|
||||
Serial.println(F("APDS-9960 initialization complete"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during APDS-9960 init!"));
|
||||
}
|
||||
|
||||
// Start running the APDS-9960 gesture sensor engine
|
||||
if ( apds.enableGestureSensor(true) ) {
|
||||
Serial.println(F("Gesture sensor is now running"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during gesture sensor init!"));
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if( isr_flag == 1 ) {
|
||||
detachInterrupt(0);
|
||||
handleGesture();
|
||||
isr_flag = 0;
|
||||
attachInterrupt(0, interruptRoutine, FALLING);
|
||||
}
|
||||
}
|
||||
|
||||
void interruptRoutine() {
|
||||
isr_flag = 1;
|
||||
}
|
||||
|
||||
void handleGesture() {
|
||||
if ( apds.isGestureAvailable() ) {
|
||||
switch ( apds.readGesture() ) {
|
||||
case DIR_UP:
|
||||
Serial.println("UP");
|
||||
break;
|
||||
case DIR_DOWN:
|
||||
Serial.println("DOWN");
|
||||
break;
|
||||
case DIR_LEFT:
|
||||
Serial.println("LEFT");
|
||||
break;
|
||||
case DIR_RIGHT:
|
||||
Serial.println("RIGHT");
|
||||
break;
|
||||
case DIR_NEAR:
|
||||
Serial.println("NEAR");
|
||||
break;
|
||||
case DIR_FAR:
|
||||
Serial.println("FAR");
|
||||
break;
|
||||
default:
|
||||
Serial.println("NONE");
|
||||
}
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/****************************************************************
|
||||
ProximityInterrupt.ino
|
||||
APDS-9960 RGB and Gesture Sensor
|
||||
Shawn Hymel @ SparkFun Electronics
|
||||
October 24, 2014
|
||||
https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor
|
||||
|
||||
Tests the proximity interrupt abilities of the APDS-9960.
|
||||
Configures the APDS-9960 over I2C and waits for an external
|
||||
interrupt based on high or low proximity conditions. Move your
|
||||
hand near the sensor and watch the LED on pin 13.
|
||||
|
||||
Hardware Connections:
|
||||
|
||||
IMPORTANT: The APDS-9960 can only accept 3.3V!
|
||||
|
||||
Arduino Pin APDS-9960 Board Function
|
||||
|
||||
3.3V VCC Power
|
||||
GND GND Ground
|
||||
A4 SDA I2C Data
|
||||
A5 SCL I2C Clock
|
||||
2 INT Interrupt
|
||||
13 - LED
|
||||
|
||||
Resources:
|
||||
Include Wire.h and SparkFun_APDS-9960.h
|
||||
|
||||
Development environment specifics:
|
||||
Written in Arduino 1.0.5
|
||||
Tested with SparkFun Arduino Pro Mini 3.3V
|
||||
|
||||
This code is beerware; if you see me (or any other SparkFun
|
||||
employee) at the local, and you've found our code helpful, please
|
||||
buy us a round!
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
****************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
|
||||
// Pins
|
||||
#define APDS9960_INT 2 // Needs to be an interrupt pin
|
||||
#define LED_PIN 13 // LED for showing interrupt
|
||||
|
||||
// Constants
|
||||
#define PROX_INT_HIGH 50 // Proximity level for interrupt
|
||||
#define PROX_INT_LOW 0 // No far interrupt
|
||||
|
||||
// Global variables
|
||||
SparkFun_APDS9960 apds = SparkFun_APDS9960();
|
||||
uint8_t proximity_data = 0;
|
||||
int isr_flag = 0;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Set LED as output
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
pinMode(APDS9960_INT, INPUT);
|
||||
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("---------------------------------------"));
|
||||
Serial.println(F("SparkFun APDS-9960 - ProximityInterrupt"));
|
||||
Serial.println(F("---------------------------------------"));
|
||||
|
||||
// Initialize interrupt service routine
|
||||
attachInterrupt(0, interruptRoutine, FALLING);
|
||||
|
||||
// Initialize APDS-9960 (configure I2C and initial values)
|
||||
if ( apds.init() ) {
|
||||
Serial.println(F("APDS-9960 initialization complete"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during APDS-9960 init!"));
|
||||
}
|
||||
|
||||
// Adjust the Proximity sensor gain
|
||||
if ( !apds.setProximityGain(PGAIN_2X) ) {
|
||||
Serial.println(F("Something went wrong trying to set PGAIN"));
|
||||
}
|
||||
|
||||
// Set proximity interrupt thresholds
|
||||
if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
|
||||
Serial.println(F("Error writing low threshold"));
|
||||
}
|
||||
if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
|
||||
Serial.println(F("Error writing high threshold"));
|
||||
}
|
||||
|
||||
// Start running the APDS-9960 proximity sensor (interrupts)
|
||||
if ( apds.enableProximitySensor(true) ) {
|
||||
Serial.println(F("Proximity sensor is now running"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during sensor init!"));
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// If interrupt occurs, print out the proximity level
|
||||
if ( isr_flag == 1 ) {
|
||||
|
||||
// Read proximity level and print it out
|
||||
if ( !apds.readProximity(proximity_data) ) {
|
||||
Serial.println("Error reading proximity value");
|
||||
} else {
|
||||
Serial.print("Proximity detected! Level: ");
|
||||
Serial.println(proximity_data);
|
||||
}
|
||||
|
||||
// Turn on LED for a half a second
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
// Reset flag and clear APDS-9960 interrupt (IMPORTANT!)
|
||||
isr_flag = 0;
|
||||
if ( !apds.clearProximityInt() ) {
|
||||
Serial.println("Error clearing interrupt");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void interruptRoutine() {
|
||||
isr_flag = 1;
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/****************************************************************
|
||||
ProximityTest.ino
|
||||
APDS-9960 RGB and Gesture Sensor
|
||||
Shawn Hymel @ SparkFun Electronics
|
||||
October 28, 2014
|
||||
https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor
|
||||
|
||||
Tests the proximity sensing abilities of the APDS-9960.
|
||||
Configures the APDS-9960 over I2C and polls for the distance to
|
||||
the object nearest the sensor.
|
||||
|
||||
Hardware Connections:
|
||||
|
||||
IMPORTANT: The APDS-9960 can only accept 3.3V!
|
||||
|
||||
Arduino Pin APDS-9960 Board Function
|
||||
|
||||
3.3V VCC Power
|
||||
GND GND Ground
|
||||
A4 SDA I2C Data
|
||||
A5 SCL I2C Clock
|
||||
|
||||
Resources:
|
||||
Include Wire.h and SparkFun_APDS-9960.h
|
||||
|
||||
Development environment specifics:
|
||||
Written in Arduino 1.0.5
|
||||
Tested with SparkFun Arduino Pro Mini 3.3V
|
||||
|
||||
This code is beerware; if you see me (or any other SparkFun
|
||||
employee) at the local, and you've found our code helpful, please
|
||||
buy us a round!
|
||||
|
||||
Distributed as-is; no warranty is given.
|
||||
****************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SparkFun_APDS9960.h>
|
||||
|
||||
// Global Variables
|
||||
SparkFun_APDS9960 apds = SparkFun_APDS9960();
|
||||
uint8_t proximity_data = 0;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.println(F("SparkFun APDS-9960 - ProximitySensor"));
|
||||
Serial.println(F("------------------------------------"));
|
||||
|
||||
// Initialize APDS-9960 (configure I2C and initial values)
|
||||
if ( apds.init() ) {
|
||||
Serial.println(F("APDS-9960 initialization complete"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during APDS-9960 init!"));
|
||||
}
|
||||
|
||||
// Adjust the Proximity sensor gain
|
||||
if ( !apds.setProximityGain(PGAIN_2X) ) {
|
||||
Serial.println(F("Something went wrong trying to set PGAIN"));
|
||||
}
|
||||
|
||||
// Start running the APDS-9960 proximity sensor (no interrupts)
|
||||
if ( apds.enableProximitySensor(false) ) {
|
||||
Serial.println(F("Proximity sensor is now running"));
|
||||
} else {
|
||||
Serial.println(F("Something went wrong during sensor init!"));
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Read the proximity value
|
||||
if ( !apds.readProximity(proximity_data) ) {
|
||||
Serial.println("Error reading proximity value");
|
||||
} else {
|
||||
Serial.print("Proximity: ");
|
||||
Serial.println(proximity_data);
|
||||
}
|
||||
|
||||
// Wait 250 ms before next reading
|
||||
delay(250);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
name=SparkFun APDS9960 RGB and Gesture Sensor
|
||||
version=1.4.2
|
||||
author=SparkFun Electronics <techsupport@sparkfun.com>
|
||||
maintainer=SparkFun Electronics <sparkfun.com>
|
||||
sentence=Library for the Avago APDS-9960 sensor
|
||||
paragraph=This library works with the SparkFun Breakout board for the Avago APDS-9960 proximity, light, RGB, and gesture sensor, made by SparkFun Electronics.
|
||||
category=Sensors
|
||||
url=https://github.com/sparkfun/SparkFun_APDS-9960_Sensor_Arduino_Library
|
||||
architectures=*
|
||||
@@ -0,0 +1,5 @@
|
||||
This folder should contain the .cpp and .h files for the library.
|
||||
|
||||
If backward compatibility is needed, source code should be placed in the library root folder and in a "utilyt" folder.
|
||||
|
||||
Check out the [library specification](https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification) for more details.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* @file SparkFun_APDS-9960.h
|
||||
* @brief Library for the SparkFun APDS-9960 breakout board
|
||||
* @author Shawn Hymel (SparkFun Electronics)
|
||||
*
|
||||
* @copyright This code is public domain but you buy me a beer if you use
|
||||
* this and we meet someday (Beerware license).
|
||||
*
|
||||
* This library interfaces the Avago APDS-9960 to Arduino over I2C. The library
|
||||
* relies on the Arduino Wire (I2C) library. to use the library, instantiate an
|
||||
* APDS9960 object, call init(), and call the appropriate functions.
|
||||
*/
|
||||
|
||||
#ifndef SparkFun_APDS9960_H
|
||||
#define SparkFun_APDS9960_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/* Debug */
|
||||
#define DEBUG 0
|
||||
|
||||
/* APDS-9960 I2C address */
|
||||
#define APDS9960_I2C_ADDR 0x39
|
||||
|
||||
/* Gesture parameters */
|
||||
#define GESTURE_THRESHOLD_OUT 10
|
||||
#define GESTURE_SENSITIVITY_1 50
|
||||
#define GESTURE_SENSITIVITY_2 20
|
||||
|
||||
/* Error code for returned values */
|
||||
#define ERROR 0xFF
|
||||
|
||||
/* Acceptable device IDs */
|
||||
#define APDS9960_ID_1 0xAB
|
||||
#define APDS9960_ID_2 0x9C
|
||||
|
||||
/* Misc parameters */
|
||||
#define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads
|
||||
|
||||
/* APDS-9960 register addresses */
|
||||
#define APDS9960_ENABLE 0x80
|
||||
#define APDS9960_ATIME 0x81
|
||||
#define APDS9960_WTIME 0x83
|
||||
#define APDS9960_AILTL 0x84
|
||||
#define APDS9960_AILTH 0x85
|
||||
#define APDS9960_AIHTL 0x86
|
||||
#define APDS9960_AIHTH 0x87
|
||||
#define APDS9960_PILT 0x89
|
||||
#define APDS9960_PIHT 0x8B
|
||||
#define APDS9960_PERS 0x8C
|
||||
#define APDS9960_CONFIG1 0x8D
|
||||
#define APDS9960_PPULSE 0x8E
|
||||
#define APDS9960_CONTROL 0x8F
|
||||
#define APDS9960_CONFIG2 0x90
|
||||
#define APDS9960_ID 0x92
|
||||
#define APDS9960_STATUS 0x93
|
||||
#define APDS9960_CDATAL 0x94
|
||||
#define APDS9960_CDATAH 0x95
|
||||
#define APDS9960_RDATAL 0x96
|
||||
#define APDS9960_RDATAH 0x97
|
||||
#define APDS9960_GDATAL 0x98
|
||||
#define APDS9960_GDATAH 0x99
|
||||
#define APDS9960_BDATAL 0x9A
|
||||
#define APDS9960_BDATAH 0x9B
|
||||
#define APDS9960_PDATA 0x9C
|
||||
#define APDS9960_POFFSET_UR 0x9D
|
||||
#define APDS9960_POFFSET_DL 0x9E
|
||||
#define APDS9960_CONFIG3 0x9F
|
||||
#define APDS9960_GPENTH 0xA0
|
||||
#define APDS9960_GEXTH 0xA1
|
||||
#define APDS9960_GCONF1 0xA2
|
||||
#define APDS9960_GCONF2 0xA3
|
||||
#define APDS9960_GOFFSET_U 0xA4
|
||||
#define APDS9960_GOFFSET_D 0xA5
|
||||
#define APDS9960_GOFFSET_L 0xA7
|
||||
#define APDS9960_GOFFSET_R 0xA9
|
||||
#define APDS9960_GPULSE 0xA6
|
||||
#define APDS9960_GCONF3 0xAA
|
||||
#define APDS9960_GCONF4 0xAB
|
||||
#define APDS9960_GFLVL 0xAE
|
||||
#define APDS9960_GSTATUS 0xAF
|
||||
#define APDS9960_IFORCE 0xE4
|
||||
#define APDS9960_PICLEAR 0xE5
|
||||
#define APDS9960_CICLEAR 0xE6
|
||||
#define APDS9960_AICLEAR 0xE7
|
||||
#define APDS9960_GFIFO_U 0xFC
|
||||
#define APDS9960_GFIFO_D 0xFD
|
||||
#define APDS9960_GFIFO_L 0xFE
|
||||
#define APDS9960_GFIFO_R 0xFF
|
||||
|
||||
/* Bit fields */
|
||||
#define APDS9960_PON 0b00000001
|
||||
#define APDS9960_AEN 0b00000010
|
||||
#define APDS9960_PEN 0b00000100
|
||||
#define APDS9960_WEN 0b00001000
|
||||
#define APSD9960_AIEN 0b00010000
|
||||
#define APDS9960_PIEN 0b00100000
|
||||
#define APDS9960_GEN 0b01000000
|
||||
#define APDS9960_GVALID 0b00000001
|
||||
|
||||
/* On/Off definitions */
|
||||
#define OFF 0
|
||||
#define ON 1
|
||||
|
||||
/* Acceptable parameters for setMode */
|
||||
#define POWER 0
|
||||
#define AMBIENT_LIGHT 1
|
||||
#define PROXIMITY 2
|
||||
#define WAIT 3
|
||||
#define AMBIENT_LIGHT_INT 4
|
||||
#define PROXIMITY_INT 5
|
||||
#define GESTURE 6
|
||||
#define ALL 7
|
||||
|
||||
/* LED Drive values */
|
||||
#define LED_DRIVE_100MA 0
|
||||
#define LED_DRIVE_50MA 1
|
||||
#define LED_DRIVE_25MA 2
|
||||
#define LED_DRIVE_12_5MA 3
|
||||
|
||||
/* Proximity Gain (PGAIN) values */
|
||||
#define PGAIN_1X 0
|
||||
#define PGAIN_2X 1
|
||||
#define PGAIN_4X 2
|
||||
#define PGAIN_8X 3
|
||||
|
||||
/* ALS Gain (AGAIN) values */
|
||||
#define AGAIN_1X 0
|
||||
#define AGAIN_4X 1
|
||||
#define AGAIN_16X 2
|
||||
#define AGAIN_64X 3
|
||||
|
||||
/* Gesture Gain (GGAIN) values */
|
||||
#define GGAIN_1X 0
|
||||
#define GGAIN_2X 1
|
||||
#define GGAIN_4X 2
|
||||
#define GGAIN_8X 3
|
||||
|
||||
/* LED Boost values */
|
||||
#define LED_BOOST_100 0
|
||||
#define LED_BOOST_150 1
|
||||
#define LED_BOOST_200 2
|
||||
#define LED_BOOST_300 3
|
||||
|
||||
/* Gesture wait time values */
|
||||
#define GWTIME_0MS 0
|
||||
#define GWTIME_2_8MS 1
|
||||
#define GWTIME_5_6MS 2
|
||||
#define GWTIME_8_4MS 3
|
||||
#define GWTIME_14_0MS 4
|
||||
#define GWTIME_22_4MS 5
|
||||
#define GWTIME_30_8MS 6
|
||||
#define GWTIME_39_2MS 7
|
||||
|
||||
/* Default values */
|
||||
#define DEFAULT_ATIME 219 // 103ms
|
||||
#define DEFAULT_WTIME 246 // 27ms
|
||||
#define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses
|
||||
#define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses
|
||||
#define DEFAULT_POFFSET_UR 0 // 0 offset
|
||||
#define DEFAULT_POFFSET_DL 0 // 0 offset
|
||||
#define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor
|
||||
#define DEFAULT_LDRIVE LED_DRIVE_100MA
|
||||
#define DEFAULT_PGAIN PGAIN_4X
|
||||
#define DEFAULT_AGAIN AGAIN_4X
|
||||
#define DEFAULT_PILT 0 // Low proximity threshold
|
||||
#define DEFAULT_PIHT 50 // High proximity threshold
|
||||
#define DEFAULT_AILT 0xFFFF // Force interrupt for calibration
|
||||
#define DEFAULT_AIHT 0
|
||||
#define DEFAULT_PERS 0x11 // 2 consecutive prox or ALS for int.
|
||||
#define DEFAULT_CONFIG2 0x01 // No saturation interrupts or LED boost
|
||||
#define DEFAULT_CONFIG3 0 // Enable all photodiodes, no SAI
|
||||
#define DEFAULT_GPENTH 40 // Threshold for entering gesture mode
|
||||
#define DEFAULT_GEXTH 30 // Threshold for exiting gesture mode
|
||||
#define DEFAULT_GCONF1 0x40 // 4 gesture events for int., 1 for exit
|
||||
#define DEFAULT_GGAIN GGAIN_4X
|
||||
#define DEFAULT_GLDRIVE LED_DRIVE_100MA
|
||||
#define DEFAULT_GWTIME GWTIME_2_8MS
|
||||
#define DEFAULT_GOFFSET 0 // No offset scaling for gesture mode
|
||||
#define DEFAULT_GPULSE 0xC9 // 32us, 10 pulses
|
||||
#define DEFAULT_GCONF3 0 // All photodiodes active during gesture
|
||||
#define DEFAULT_GIEN 0 // Disable gesture interrupts
|
||||
|
||||
/* Direction definitions */
|
||||
enum {
|
||||
DIR_NONE,
|
||||
DIR_LEFT,
|
||||
DIR_RIGHT,
|
||||
DIR_UP,
|
||||
DIR_DOWN,
|
||||
DIR_NEAR,
|
||||
DIR_FAR,
|
||||
DIR_ALL
|
||||
};
|
||||
|
||||
/* State definitions */
|
||||
|
||||
enum {
|
||||
N_A_STATE, // NA_STATE - collision with ESP8266WiFi.h
|
||||
NEAR_STATE,
|
||||
FAR_STATE,
|
||||
ALL_STATE
|
||||
};
|
||||
|
||||
|
||||
/* Container for gesture data */
|
||||
typedef struct gesture_data_type {
|
||||
uint8_t u_data[32];
|
||||
uint8_t d_data[32];
|
||||
uint8_t l_data[32];
|
||||
uint8_t r_data[32];
|
||||
uint8_t index;
|
||||
uint8_t total_gestures;
|
||||
uint8_t in_threshold;
|
||||
uint8_t out_threshold;
|
||||
} gesture_data_type;
|
||||
|
||||
/* APDS9960 Class */
|
||||
class SparkFun_APDS9960 {
|
||||
public:
|
||||
|
||||
/* Initialization methods */
|
||||
SparkFun_APDS9960();
|
||||
~SparkFun_APDS9960();
|
||||
bool init();
|
||||
uint8_t getMode();
|
||||
bool setMode(uint8_t mode, uint8_t enable);
|
||||
|
||||
/* Turn the APDS-9960 on and off */
|
||||
bool enablePower();
|
||||
bool disablePower();
|
||||
|
||||
/* Enable or disable specific sensors */
|
||||
bool enableLightSensor(bool interrupts = false);
|
||||
bool disableLightSensor();
|
||||
bool enableProximitySensor(bool interrupts = false);
|
||||
bool disableProximitySensor();
|
||||
bool enableGestureSensor(bool interrupts = true);
|
||||
bool disableGestureSensor();
|
||||
|
||||
/* LED drive strength control */
|
||||
uint8_t getLEDDrive();
|
||||
bool setLEDDrive(uint8_t drive);
|
||||
uint8_t getGestureLEDDrive();
|
||||
bool setGestureLEDDrive(uint8_t drive);
|
||||
|
||||
/* Gain control */
|
||||
uint8_t getAmbientLightGain();
|
||||
bool setAmbientLightGain(uint8_t gain);
|
||||
uint8_t getProximityGain();
|
||||
bool setProximityGain(uint8_t gain);
|
||||
uint8_t getGestureGain();
|
||||
bool setGestureGain(uint8_t gain);
|
||||
|
||||
/* Get and set light interrupt thresholds */
|
||||
bool getLightIntLowThreshold(uint16_t &threshold);
|
||||
bool setLightIntLowThreshold(uint16_t threshold);
|
||||
bool getLightIntHighThreshold(uint16_t &threshold);
|
||||
bool setLightIntHighThreshold(uint16_t threshold);
|
||||
|
||||
/* Get and set proximity interrupt thresholds */
|
||||
bool getProximityIntLowThreshold(uint8_t &threshold);
|
||||
bool setProximityIntLowThreshold(uint8_t threshold);
|
||||
bool getProximityIntHighThreshold(uint8_t &threshold);
|
||||
bool setProximityIntHighThreshold(uint8_t threshold);
|
||||
|
||||
/* Get and set interrupt enables */
|
||||
uint8_t getAmbientLightIntEnable();
|
||||
bool setAmbientLightIntEnable(uint8_t enable);
|
||||
uint8_t getProximityIntEnable();
|
||||
bool setProximityIntEnable(uint8_t enable);
|
||||
uint8_t getGestureIntEnable();
|
||||
bool setGestureIntEnable(uint8_t enable);
|
||||
|
||||
/* Clear interrupts */
|
||||
bool clearAmbientLightInt();
|
||||
bool clearProximityInt();
|
||||
|
||||
/* Ambient light methods */
|
||||
bool readAmbientLight(uint16_t &val);
|
||||
bool readRedLight(uint16_t &val);
|
||||
bool readGreenLight(uint16_t &val);
|
||||
bool readBlueLight(uint16_t &val);
|
||||
|
||||
/* Proximity methods */
|
||||
bool readProximity(uint8_t &val);
|
||||
|
||||
/* Gesture methods */
|
||||
bool isGestureAvailable();
|
||||
int readGesture();
|
||||
int readGestureNonBlocking();
|
||||
|
||||
private:
|
||||
|
||||
/* Gesture processing */
|
||||
void resetGestureParameters();
|
||||
bool processGestureData();
|
||||
bool decodeGesture();
|
||||
|
||||
/* Proximity Interrupt Threshold */
|
||||
uint8_t getProxIntLowThresh();
|
||||
bool setProxIntLowThresh(uint8_t threshold);
|
||||
uint8_t getProxIntHighThresh();
|
||||
bool setProxIntHighThresh(uint8_t threshold);
|
||||
|
||||
/* LED Boost Control */
|
||||
uint8_t getLEDBoost();
|
||||
bool setLEDBoost(uint8_t boost);
|
||||
|
||||
/* Proximity photodiode select */
|
||||
uint8_t getProxGainCompEnable();
|
||||
bool setProxGainCompEnable(uint8_t enable);
|
||||
uint8_t getProxPhotoMask();
|
||||
bool setProxPhotoMask(uint8_t mask);
|
||||
|
||||
/* Gesture threshold control */
|
||||
uint8_t getGestureEnterThresh();
|
||||
bool setGestureEnterThresh(uint8_t threshold);
|
||||
uint8_t getGestureExitThresh();
|
||||
bool setGestureExitThresh(uint8_t threshold);
|
||||
|
||||
/* Gesture LED, gain, and time control */
|
||||
uint8_t getGestureWaitTime();
|
||||
bool setGestureWaitTime(uint8_t time);
|
||||
|
||||
/* Gesture mode */
|
||||
uint8_t getGestureMode();
|
||||
bool setGestureMode(uint8_t mode);
|
||||
|
||||
/* Raw I2C Commands */
|
||||
bool wireWriteByte(uint8_t val);
|
||||
bool wireWriteDataByte(uint8_t reg, uint8_t val);
|
||||
bool wireWriteDataBlock(uint8_t reg, uint8_t *val, unsigned int len);
|
||||
bool wireReadDataByte(uint8_t reg, uint8_t &val);
|
||||
int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len);
|
||||
|
||||
/* Members */
|
||||
gesture_data_type gesture_data_;
|
||||
int gesture_ud_delta_;
|
||||
int gesture_lr_delta_;
|
||||
int gesture_ud_count_;
|
||||
int gesture_lr_count_;
|
||||
int gesture_near_count_;
|
||||
int gesture_far_count_;
|
||||
int gesture_state_;
|
||||
int gesture_motion_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
// MQTT_MAX_PACKET_SIZE : Maximum packet size
|
||||
#ifndef MQTT_MAX_PACKET_SIZE
|
||||
#define MQTT_MAX_PACKET_SIZE 256 // need to fix this here, because this define cannot be overruled within the Arduino sketch...
|
||||
#define MQTT_MAX_PACKET_SIZE 384 // need to fix this here, because this define cannot be overruled within the Arduino sketch...
|
||||
#endif
|
||||
|
||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||
|
||||
@@ -4,13 +4,13 @@ NEW="$1"
|
||||
|
||||
[ "$NEW" != "" ] || exit 1
|
||||
|
||||
PREV=`git tag|tail -1`
|
||||
PREV=`git tag --sort=creatordate|tail -1`
|
||||
|
||||
############## update Release_notes.txt
|
||||
NOTES="dist/Release_notes.txt"
|
||||
echo "-----------------------------" > "$NOTES.new"
|
||||
echo "Changes in release $NEW" >> "$NOTES.new"
|
||||
echo "-----------------------------" >> "$NOTES.new"
|
||||
echo "-------------------------------------------------" > "$NOTES.new"
|
||||
echo "Changes in release $NEW (since $PREV)" >> "$NOTES.new"
|
||||
echo "-------------------------------------------------" >> "$NOTES.new"
|
||||
echo -e "\nRelease date: `date`\n" >> "$NOTES.new"
|
||||
|
||||
git shortlog --no-merges $PREV..HEAD >> "$NOTES.new"
|
||||
|
||||
+38
-9
@@ -86,12 +86,7 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
if (strcasecmp_P(Command, PSTR("clearRTCRAM")) == 0)
|
||||
{
|
||||
success = true;
|
||||
RTC.factoryResetCounter = 0;
|
||||
RTC.deepSleepState = 0;
|
||||
RTC.rebootCounter = 0;
|
||||
RTC.flashDayCounter = 0;
|
||||
RTC.flashCounter = 0;
|
||||
saveToRTC();
|
||||
initRTC();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("notify")) == 0)
|
||||
@@ -154,7 +149,7 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
{
|
||||
Serial.print(lowestRAM);
|
||||
Serial.print(F(" : "));
|
||||
Serial.println(lowestRAMid);
|
||||
Serial.println(lowestRAMfunction);
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -264,11 +259,19 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
// commands for rules
|
||||
// ****************************************
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("config")) == 0)
|
||||
{
|
||||
success = true;
|
||||
struct EventStruct TempEvent;
|
||||
String request = Line;
|
||||
remoteConfig(&TempEvent, request);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("deepSleep")) == 0)
|
||||
{
|
||||
success = true;
|
||||
if (Par1 > 0)
|
||||
deepSleep(Par1);
|
||||
deepSleepStart(Par1); // call the second part of the function to avoid check and enable one-shot operation
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskValueSet")) == 0)
|
||||
@@ -445,7 +448,7 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
if (strcasecmp_P(Command, PSTR("WifiConnect")) == 0)
|
||||
{
|
||||
success = true;
|
||||
WifiConnect(true, 1);
|
||||
WifiConnect(1);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiDisconnect")) == 0)
|
||||
@@ -454,6 +457,31 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
WifiDisconnect();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiAPMode")) == 0)
|
||||
{
|
||||
WifiAPMode(true);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Unit")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Settings.Unit=Par1;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Name")) == 0)
|
||||
{
|
||||
success = true;
|
||||
strcpy(Settings.Name, Line + 5);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Password")) == 0)
|
||||
{
|
||||
success = true;
|
||||
strcpy(SecuritySettings.Password, Line + 9);
|
||||
}
|
||||
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Reboot")) == 0)
|
||||
{
|
||||
success = true;
|
||||
@@ -519,6 +547,7 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
Serial.print(F(" IP Address : ")); Serial.println(str);
|
||||
Serial.print(F(" Build : ")); Serial.println((int)BUILD);
|
||||
Serial.print(F(" Name : ")); Serial.println(Settings.Name);
|
||||
Serial.print(F(" Unit : ")); Serial.println((int)Settings.Unit);
|
||||
Serial.print(F(" WifiSSID : ")); Serial.println(SecuritySettings.WifiSSID);
|
||||
Serial.print(F(" WifiKey : ")); Serial.println(SecuritySettings.WifiKey);
|
||||
|
||||
+4
-1
@@ -10,6 +10,9 @@ boolean sendData(struct EventStruct *event)
|
||||
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
|
||||
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
|
||||
if (Settings.UseValueLogger && Settings.InitSPI && Settings.Pin_sd_cs >= 0)
|
||||
SendValueLogger(event->TaskIndex);
|
||||
|
||||
// if (!Settings.TaskDeviceSendData[event->TaskIndex])
|
||||
// return false;
|
||||
|
||||
@@ -54,7 +57,7 @@ boolean sendData(struct EventStruct *event)
|
||||
// handle MQTT messages
|
||||
void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
// char log[256];
|
||||
char c_payload[256];
|
||||
char c_payload[384];
|
||||
|
||||
statusLED(true);
|
||||
|
||||
|
||||
+130
-65
@@ -73,11 +73,9 @@
|
||||
// You can always change these during runtime and save to eeprom
|
||||
// After loading firmware, issue a 'reset' command to load the defaults.
|
||||
|
||||
#define DEFAULT_NAME "newdevice" // Enter your device friendly name
|
||||
#define DEFAULT_NAME "ESP_Easy" // Enter your device friendly name
|
||||
#define DEFAULT_SSID "ssid" // Enter your network SSID
|
||||
#define DEFAULT_KEY "wpakey" // Enter your network WPA key
|
||||
#define DEFAULT_SERVER "192.168.0.8" // Enter your Domoticz Server IP address
|
||||
#define DEFAULT_PORT 8080 // Enter your Domoticz Server port value
|
||||
#define DEFAULT_DELAY 60 // Enter your Send delay in seconds
|
||||
#define DEFAULT_AP_KEY "configesp" // Enter network WPA key for AP (config) mode
|
||||
|
||||
@@ -87,9 +85,12 @@
|
||||
#define DEFAULT_GW "192.168.0.1" // Enter your gateway
|
||||
#define DEFAULT_SUBNET "255.255.255.0" // Enter your subnet
|
||||
|
||||
#define DEFAULT_MQTT_TEMPLATE false // true or false enabled or disabled set mqqt sub and pub
|
||||
#define DEFAULT_MQTT_PUB "sensors/espeasy/%sysname%/%tskname%/%valname%" // Enter your pub
|
||||
#define DEFAULT_MQTT_SUB "sensors/espeasy/%sysname%/#" // Enter your sub
|
||||
#define DEFAULT_CONTROLLER false // true or false enabled or disabled, set 1st controller defaults
|
||||
// using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol !
|
||||
#define DEFAULT_PUB "sensors/espeasy/%sysname%/%tskname%/%valname%" // Enter your pub
|
||||
#define DEFAULT_SUB "sensors/espeasy/%sysname%/#" // Enter your sub
|
||||
#define DEFAULT_SERVER "192.168.0.8" // Enter your Server IP address
|
||||
#define DEFAULT_PORT 8080 // Enter your Server port value
|
||||
|
||||
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
|
||||
// 1 = Domoticz HTTP
|
||||
@@ -114,6 +115,9 @@
|
||||
//Note: This adds around 10kb to the firmware size, and 1kb extra ram.
|
||||
// #define FEATURE_ARDUINO_OTA
|
||||
|
||||
//enable mDNS mode (adds about 6kb ram and some bytes IRAM)
|
||||
// #define FEATURE_MDNS
|
||||
|
||||
|
||||
//enable reporting status to ESPEasy developers.
|
||||
//this informs us of crashes and stability issues.
|
||||
@@ -176,7 +180,10 @@
|
||||
#define PLUGIN_CLOCK_IN 18
|
||||
#define PLUGIN_TIMER_IN 19
|
||||
#define PLUGIN_FIFTY_PER_SECOND 20
|
||||
#define PLUGIN_REMOTE_CONFIG 21
|
||||
#define PLUGIN_SET_CONFIG 21
|
||||
#define PLUGIN_GET_DEVICEGPIONAMES 22
|
||||
#define PLUGIN_EXIT 23
|
||||
#define PLUGIN_GET_CONFIG 24
|
||||
|
||||
#define CPLUGIN_PROTOCOL_ADD 1
|
||||
#define CPLUGIN_PROTOCOL_TEMPLATE 2
|
||||
@@ -197,16 +204,21 @@
|
||||
#define LOG_LEVEL_INFO 2
|
||||
#define LOG_LEVEL_DEBUG 3
|
||||
#define LOG_LEVEL_DEBUG_MORE 4
|
||||
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
|
||||
|
||||
#define CMD_REBOOT 89
|
||||
#define CMD_WIFI_DISCONNECT 135
|
||||
|
||||
#define DEVICES_MAX 64
|
||||
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
|
||||
#define DEVICES_MAX 72
|
||||
#else
|
||||
#define DEVICES_MAX 64
|
||||
#endif
|
||||
#define TASKS_MAX 12 // max 12!
|
||||
#define CONTROLLER_MAX 3 // max 4!
|
||||
#define NOTIFICATION_MAX 3 // max 4!
|
||||
#define VARS_PER_TASK 4
|
||||
#define PLUGIN_MAX 64
|
||||
#define PLUGIN_MAX DEVICES_MAX
|
||||
#define PLUGIN_CONFIGVAR_MAX 8
|
||||
#define PLUGIN_CONFIGFLOATVAR_MAX 4
|
||||
#define PLUGIN_CONFIGLONGVAR_MAX 4
|
||||
@@ -276,6 +288,10 @@
|
||||
#include <DNSServer.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#ifdef FEATURE_MDNS
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <PubSubClient.h>
|
||||
@@ -316,7 +332,9 @@ bool ArduinoOTAtriggered=false;
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIP(192, 168, 4, 1);
|
||||
DNSServer dnsServer;
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
MDNSResponder mdns;
|
||||
#endif
|
||||
|
||||
// MQTT client
|
||||
WiFiClient mqtt;
|
||||
@@ -348,6 +366,7 @@ struct SecurityStruct
|
||||
char ControllerUser[CONTROLLER_MAX][26];
|
||||
char ControllerPassword[CONTROLLER_MAX][64];
|
||||
char Password[26];
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
} SecuritySettings;
|
||||
|
||||
struct SettingsStruct
|
||||
@@ -419,6 +438,11 @@ struct SettingsStruct
|
||||
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
|
||||
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
|
||||
boolean Pin_status_led_Inversed;
|
||||
boolean deepSleepOnFail;
|
||||
boolean UseValueLogger;
|
||||
//its safe to extend this struct, up to several bytes, default values in config are 0
|
||||
//look in misc.ino how config.dat is used because also other stuff is stored in it at different offsets.
|
||||
//TODO: document config.dat somewhere here
|
||||
} Settings;
|
||||
|
||||
struct ControllerSettingsStruct
|
||||
@@ -442,6 +466,7 @@ struct NotificationSettingsStruct
|
||||
char Body[513];
|
||||
byte Pin1;
|
||||
byte Pin2;
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
};
|
||||
|
||||
struct ExtraTaskSettingsStruct
|
||||
@@ -474,6 +499,7 @@ struct EventStruct
|
||||
byte OriginTaskIndex;
|
||||
String String1;
|
||||
String String2;
|
||||
String String3;
|
||||
byte *Data;
|
||||
};
|
||||
|
||||
@@ -552,18 +578,26 @@ struct pinStatesStruct
|
||||
uint16_t value;
|
||||
} pinStates[PINSTATE_TABLE_MAX];
|
||||
|
||||
|
||||
// this offsets are in blocks, bytes = blocks * 4
|
||||
#define RTC_BASE_STRUCT 64
|
||||
#define RTC_BASE_USERVAR 74
|
||||
|
||||
//max 40 bytes: ( 74 - 64 ) * 4
|
||||
struct RTCStruct
|
||||
{
|
||||
byte ID1;
|
||||
byte ID2;
|
||||
boolean valid; // not used?
|
||||
boolean unused1;
|
||||
byte factoryResetCounter;
|
||||
byte deepSleepState;
|
||||
byte rebootCounter; //not used yet?
|
||||
byte unused2;
|
||||
byte flashDayCounter;
|
||||
unsigned long flashCounter;
|
||||
unsigned long bootCounter;
|
||||
} RTC;
|
||||
|
||||
|
||||
int deviceCount = -1;
|
||||
int protocolCount = -1;
|
||||
int notificationCount = -1;
|
||||
@@ -583,10 +617,10 @@ unsigned long timerwd;
|
||||
unsigned long lastSend;
|
||||
unsigned int NC_Count = 0;
|
||||
unsigned int C_Count = 0;
|
||||
boolean AP_Mode = false;
|
||||
byte cmd_within_mainloop = 0;
|
||||
unsigned long connectionFailures;
|
||||
unsigned long wdcounter = 0;
|
||||
unsigned long timerAPoff = 0;
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
float vcc = -1.0;
|
||||
@@ -622,24 +656,14 @@ unsigned long dailyResetCounter = 0;
|
||||
String eventBuffer = "";
|
||||
|
||||
uint16_t lowestRAM = 0;
|
||||
byte lowestRAMid=0;
|
||||
/*
|
||||
1 savetoflash - obsolete
|
||||
2 loadfrom flash - obsolete
|
||||
3 zerofillflash - obsolete
|
||||
4 rulesprocessing
|
||||
5 handle_download
|
||||
6 handle_css
|
||||
7 handlefileupload
|
||||
8 handle_rules
|
||||
9 handle_devices
|
||||
*/
|
||||
String lowestRAMfunction = "";
|
||||
|
||||
/*********************************************************************************************\
|
||||
* SETUP
|
||||
\*********************************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
|
||||
lowestRAM = FreeMem();
|
||||
|
||||
Serial.begin(115200);
|
||||
@@ -661,6 +685,43 @@ void setup()
|
||||
log += BUILD_GIT;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
//warm boot
|
||||
if (readFromRTC())
|
||||
{
|
||||
RTC.bootCounter++;
|
||||
readUserVarFromRTC();
|
||||
|
||||
if (RTC.deepSleepState == 1)
|
||||
{
|
||||
log = F("INIT : Rebooted from deepsleep #");
|
||||
lastBootCause=BOOT_CAUSE_DEEP_SLEEP;
|
||||
}
|
||||
else
|
||||
log = F("INIT : Warm boot #");
|
||||
|
||||
log += RTC.bootCounter;
|
||||
|
||||
}
|
||||
//cold boot (RTC memory empty)
|
||||
else
|
||||
{
|
||||
initRTC();
|
||||
|
||||
// cold boot situation
|
||||
if (lastBootCause == BOOT_CAUSE_MANUAL_REBOOT) // only set this if not set earlier during boot stage.
|
||||
lastBootCause = BOOT_CAUSE_COLD_BOOT;
|
||||
log = F("INIT : Cold Boot");
|
||||
}
|
||||
|
||||
RTC.deepSleepState=0;
|
||||
saveToRTC();
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
|
||||
|
||||
fileSystemCheck();
|
||||
LoadSettings();
|
||||
|
||||
@@ -684,7 +745,11 @@ void setup()
|
||||
}
|
||||
|
||||
if (Settings.UseSerial)
|
||||
{
|
||||
//make sure previous serial buffers are flushed before resetting baudrate
|
||||
Serial.flush();
|
||||
Serial.begin(Settings.BaudRate);
|
||||
}
|
||||
|
||||
if (Settings.Build != BUILD)
|
||||
BuildFixes();
|
||||
@@ -701,8 +766,22 @@ void setup()
|
||||
|
||||
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
|
||||
WifiAPconfig();
|
||||
if (!WifiConnect(true,3))
|
||||
WifiConnect(false,3);
|
||||
|
||||
if (Settings.deepSleep)
|
||||
{
|
||||
//only one attempt in deepsleep, to conserve battery
|
||||
if (!WifiConnect(1))
|
||||
{
|
||||
if (Settings.deepSleepOnFail)
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("SLEEP: Connection failed, going back to sleep."));
|
||||
deepSleep(Settings.Delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// 3 connect attempts
|
||||
WifiConnect(3);
|
||||
|
||||
#ifdef FEATURE_REPORTING
|
||||
ReportStatus();
|
||||
@@ -735,42 +814,11 @@ void setup()
|
||||
|
||||
// Setup MQTT Client
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
|
||||
if (Protocol[ProtocolIndex].usesMQTT)
|
||||
if (Protocol[ProtocolIndex].usesMQTT && Settings.ControllerEnabled[0])
|
||||
MQTTConnect();
|
||||
|
||||
sendSysInfoUDP(3);
|
||||
|
||||
//warm boot
|
||||
if (readFromRTC())
|
||||
{
|
||||
readUserVarFromRTC();
|
||||
if (RTC.deepSleepState == 1)
|
||||
{
|
||||
log = F("INIT : Rebooted from deepsleep");
|
||||
lastBootCause=BOOT_CAUSE_DEEP_SLEEP;
|
||||
}
|
||||
else
|
||||
log = F("INIT : Normal boot");
|
||||
}
|
||||
//cold boot (RTC memory empty)
|
||||
else
|
||||
{
|
||||
RTC.factoryResetCounter=0;
|
||||
RTC.deepSleepState=0;
|
||||
RTC.rebootCounter=0;
|
||||
RTC.flashDayCounter=0;
|
||||
RTC.flashCounter=0;
|
||||
saveToRTC();
|
||||
|
||||
// cold boot situation
|
||||
if (lastBootCause == BOOT_CAUSE_MANUAL_REBOOT) // only set this if not set earlier during boot stage.
|
||||
lastBootCause = BOOT_CAUSE_COLD_BOOT;
|
||||
log = F("INIT : Cold Boot");
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
if (Settings.UseNTP)
|
||||
initTime();
|
||||
|
||||
@@ -790,9 +838,7 @@ void setup()
|
||||
rulesProcessing(event);
|
||||
}
|
||||
|
||||
RTC.deepSleepState=0;
|
||||
saveToRTC();
|
||||
|
||||
writeDefaultCSS();
|
||||
|
||||
}
|
||||
|
||||
@@ -807,7 +853,7 @@ void loop()
|
||||
if (wifiSetupConnect)
|
||||
{
|
||||
// try to connect for setup wizard
|
||||
WifiConnect(true,1);
|
||||
WifiConnect(1);
|
||||
wifiSetupConnect = false;
|
||||
}
|
||||
|
||||
@@ -950,6 +996,12 @@ void runOncePerSecond()
|
||||
Serial.print(F(" uS 1 ps:"));
|
||||
Serial.println(timer);
|
||||
}
|
||||
|
||||
if (timerAPoff != 0 && millis() > timerAPoff)
|
||||
{
|
||||
timerAPoff = 0;
|
||||
WifiAPMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
@@ -967,7 +1019,8 @@ void runEach30Seconds()
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendSysInfoUDP(1);
|
||||
refreshNodeList();
|
||||
MQTTCheck();
|
||||
if(Settings.ControllerEnabled[0])
|
||||
MQTTCheck();
|
||||
if (Settings.UseSSDP)
|
||||
SSDP_update();
|
||||
#if FEATURE_ADC_VCC
|
||||
@@ -1164,8 +1217,17 @@ boolean checkSystemTimers()
|
||||
/*********************************************************************************************\
|
||||
* run background tasks
|
||||
\*********************************************************************************************/
|
||||
bool runningBackgroundTasks=false;
|
||||
void backgroundtasks()
|
||||
{
|
||||
//prevent recursion!
|
||||
if (runningBackgroundTasks)
|
||||
{
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
runningBackgroundTasks=true;
|
||||
|
||||
tcpCleanup();
|
||||
|
||||
if (Settings.UseSerial)
|
||||
@@ -1178,7 +1240,8 @@ void backgroundtasks()
|
||||
dnsServer.processNextRequest();
|
||||
|
||||
WebServer.handleClient();
|
||||
MQTTclient.loop();
|
||||
if(Settings.ControllerEnabled[0])
|
||||
MQTTclient.loop();
|
||||
checkUDP();
|
||||
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
@@ -1196,4 +1259,6 @@ void backgroundtasks()
|
||||
yield();
|
||||
|
||||
statusLED(false);
|
||||
|
||||
runningBackgroundTasks=false;
|
||||
}
|
||||
|
||||
+324
-180
@@ -51,15 +51,23 @@ void deepSleep(int delay)
|
||||
}
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, F("SLEEP: Entering deep sleep..."));
|
||||
deepSleepStart(delay); // Call deepSleepStart function after these checks
|
||||
}
|
||||
|
||||
void deepSleepStart(int delay)
|
||||
{
|
||||
// separate function that is called from above function or directly from rules, usign deepSleep as a one-shot
|
||||
String event = F("System#Sleep");
|
||||
rulesProcessing(event);
|
||||
|
||||
|
||||
RTC.deepSleepState = 1;
|
||||
saveToRTC();
|
||||
|
||||
String event = F("System#Sleep");
|
||||
rulesProcessing(event);
|
||||
if (delay > 4294 || delay < 0)
|
||||
delay = 4294; //max sleep time ~1.2h
|
||||
|
||||
addLog(LOG_LEVEL_INFO, F("SLEEP: Powering down to deepsleep..."));
|
||||
ESP.deepSleep((uint32_t)delay * 1000000, WAKE_RF_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -68,8 +76,6 @@ boolean remoteConfig(struct EventStruct *event, String& string)
|
||||
boolean success = false;
|
||||
String command = parseString(string, 1);
|
||||
|
||||
Serial.print("config call:");
|
||||
Serial.println(string);
|
||||
if (command == F("config"))
|
||||
{
|
||||
success = true;
|
||||
@@ -80,15 +86,12 @@ boolean remoteConfig(struct EventStruct *event, String& string)
|
||||
|
||||
String configTaskName = string.substring(configCommandPos1, configCommandPos2 - 1);
|
||||
String configCommand = string.substring(configCommandPos2);
|
||||
Serial.println(configTaskName);
|
||||
Serial.println(configCommand);
|
||||
|
||||
int8_t index = getTaskIndexByName(configTaskName);
|
||||
Serial.println(index);
|
||||
if (index != -1)
|
||||
{
|
||||
event->TaskIndex = index;
|
||||
success = PluginCall(PLUGIN_REMOTE_CONFIG, event, configCommand);
|
||||
success = PluginCall(PLUGIN_SET_CONFIG, event, configCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,6 +122,21 @@ void flashCount()
|
||||
saveToRTC();
|
||||
}
|
||||
|
||||
String flashGuard()
|
||||
{
|
||||
if (RTC.flashDayCounter > MAX_FLASHWRITES_PER_DAY)
|
||||
{
|
||||
String log = F("FS : Daily flash write rate exceeded! (powercycle to reset this)");
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return log;
|
||||
}
|
||||
flashCount();
|
||||
return(String());
|
||||
}
|
||||
|
||||
//use this in function that can return an error string. it automaticly returns with an error string if there where too many flash writes.
|
||||
#define FLASH_GUARD() { String flashErr=flashGuard(); if (flashErr.length()) return(flashErr); }
|
||||
|
||||
/*********************************************************************************************\
|
||||
Get value count from sensor type
|
||||
\*********************************************************************************************/
|
||||
@@ -354,63 +372,66 @@ boolean timeOut(unsigned long timer)
|
||||
|
||||
/********************************************************************************************\
|
||||
Status LED
|
||||
\*********************************************************************************************/
|
||||
#define STATUS_PWM_NORMALVALUE (PWMRANGE>>2)
|
||||
#define STATUS_PWM_NORMALFADE (PWMRANGE>>8)
|
||||
#define STATUS_PWM_TRAFFICRISE (PWMRANGE>>1)
|
||||
|
||||
\*********************************************************************************************/
|
||||
#define STATUS_PWM_NORMALVALUE (PWMRANGE>>2)
|
||||
#define STATUS_PWM_NORMALFADE (PWMRANGE>>8)
|
||||
#define STATUS_PWM_TRAFFICRISE (PWMRANGE>>1)
|
||||
|
||||
void statusLED(boolean traffic)
|
||||
{
|
||||
static int gnStatusValueCurrent = -1;
|
||||
static long int gnLastUpdate = millis();
|
||||
|
||||
if (Settings.Pin_status_led == -1)
|
||||
static int gnStatusValueCurrent = -1;
|
||||
static long int gnLastUpdate = millis();
|
||||
|
||||
if (Settings.Pin_status_led == -1)
|
||||
return;
|
||||
|
||||
if (gnStatusValueCurrent<0)
|
||||
pinMode(Settings.Pin_status_led, OUTPUT);
|
||||
|
||||
int nStatusValue = gnStatusValueCurrent;
|
||||
|
||||
if (traffic)
|
||||
|
||||
if (gnStatusValueCurrent<0)
|
||||
pinMode(Settings.Pin_status_led, OUTPUT);
|
||||
|
||||
int nStatusValue = gnStatusValueCurrent;
|
||||
|
||||
if (traffic)
|
||||
{
|
||||
nStatusValue += STATUS_PWM_TRAFFICRISE; //ramp up fast
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AP_Mode) //apmode is active
|
||||
{
|
||||
nStatusValue = ((millis()>>1) & PWMRANGE) - (PWMRANGE>>2); //ramp up for 2 sec, 3/4 luminosity
|
||||
}
|
||||
else if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
nStatusValue = (millis()>>1) & (PWMRANGE>>2); //ramp up for 1/2 sec, 1/4 luminosity
|
||||
}
|
||||
else //connected
|
||||
{
|
||||
long int delta=millis()-gnLastUpdate;
|
||||
if (delta>0 || delta<0 )
|
||||
{
|
||||
nStatusValue -= STATUS_PWM_NORMALFADE; //ramp down slowly
|
||||
nStatusValue = std::max(nStatusValue, STATUS_PWM_NORMALVALUE);
|
||||
gnLastUpdate=millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nStatusValue = constrain(nStatusValue, 0, PWMRANGE);
|
||||
|
||||
if (gnStatusValueCurrent != nStatusValue)
|
||||
{
|
||||
gnStatusValueCurrent = nStatusValue;
|
||||
|
||||
long pwm = nStatusValue * nStatusValue; //simple gamma correction
|
||||
pwm >>= 10;
|
||||
if (Settings.Pin_status_led_Inversed)
|
||||
pwm = PWMRANGE-pwm;
|
||||
|
||||
analogWrite(Settings.Pin_status_led, pwm);
|
||||
}
|
||||
nStatusValue += STATUS_PWM_TRAFFICRISE; //ramp up fast
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
long int delta=millis()-gnLastUpdate;
|
||||
if (delta>0 || delta<0 )
|
||||
{
|
||||
nStatusValue -= STATUS_PWM_NORMALFADE; //ramp down slowly
|
||||
nStatusValue = std::max(nStatusValue, STATUS_PWM_NORMALVALUE);
|
||||
gnLastUpdate=millis();
|
||||
}
|
||||
}
|
||||
//AP mode is active
|
||||
else if (WifiIsAP())
|
||||
{
|
||||
nStatusValue = ((millis()>>1) & PWMRANGE) - (PWMRANGE>>2); //ramp up for 2 sec, 3/4 luminosity
|
||||
}
|
||||
//Disconnected
|
||||
else
|
||||
{
|
||||
nStatusValue = (millis()>>1) & (PWMRANGE>>2); //ramp up for 1/2 sec, 1/4 luminosity
|
||||
}
|
||||
}
|
||||
|
||||
nStatusValue = constrain(nStatusValue, 0, PWMRANGE);
|
||||
|
||||
if (gnStatusValueCurrent != nStatusValue)
|
||||
{
|
||||
gnStatusValueCurrent = nStatusValue;
|
||||
|
||||
long pwm = nStatusValue * nStatusValue; //simple gamma correction
|
||||
pwm >>= 10;
|
||||
if (Settings.Pin_status_led_Inversed)
|
||||
pwm = PWMRANGE-pwm;
|
||||
|
||||
analogWrite(Settings.Pin_status_led, pwm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -522,21 +543,31 @@ void BuildFixes()
|
||||
\*********************************************************************************************/
|
||||
void fileSystemCheck()
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("FS : Mounting..."));
|
||||
if (SPIFFS.begin())
|
||||
{
|
||||
String log = F("FS : Mount successful");
|
||||
fs::FSInfo fs_info;
|
||||
SPIFFS.info(fs_info);
|
||||
|
||||
String log = F("FS : Mount successful, used ");
|
||||
log=log+fs_info.usedBytes;
|
||||
log=log+F(" bytes of ");
|
||||
log=log+fs_info.totalBytes;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
fs::File f = SPIFFS.open("config.dat", "r");
|
||||
if (!f)
|
||||
{
|
||||
ResetFactory();
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
String log = F("FS : Mount failed");
|
||||
Serial.println(log);
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
ResetFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,74 +709,85 @@ boolean str2ip(char *string, byte* IP)
|
||||
/********************************************************************************************\
|
||||
Save settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveSettings(void)
|
||||
String SaveSettings(void)
|
||||
{
|
||||
SaveToFile((char*)"config.dat", 0, (byte*)&Settings, sizeof(struct SettingsStruct));
|
||||
return SaveToFile((char*)"security.dat", 0, (byte*)&SecuritySettings, sizeof(struct SecurityStruct));
|
||||
String err;
|
||||
err=SaveToFile((char*)"config.dat", 0, (byte*)&Settings, sizeof(struct SettingsStruct));
|
||||
if (err.length())
|
||||
return(err);
|
||||
|
||||
return(SaveToFile((char*)"security.dat", 0, (byte*)&SecuritySettings, sizeof(struct SecurityStruct)));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Load settings from SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean LoadSettings()
|
||||
String LoadSettings()
|
||||
{
|
||||
LoadFromFile((char*)"config.dat", 0, (byte*)&Settings, sizeof(struct SettingsStruct));
|
||||
LoadFromFile((char*)"security.dat", 0, (byte*)&SecuritySettings, sizeof(struct SecurityStruct));
|
||||
String err;
|
||||
err=LoadFromFile((char*)"config.dat", 0, (byte*)&Settings, sizeof(struct SettingsStruct));
|
||||
if (err.length())
|
||||
return(err);
|
||||
|
||||
return(LoadFromFile((char*)"security.dat", 0, (byte*)&SecuritySettings, sizeof(struct SecurityStruct)));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Save Task settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveTaskSettings(byte TaskIndex)
|
||||
String SaveTaskSettings(byte TaskIndex)
|
||||
{
|
||||
ExtraTaskSettings.TaskIndex = TaskIndex;
|
||||
return SaveToFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
|
||||
return(SaveToFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct)));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Load Task settings from SPIFFS
|
||||
\*********************************************************************************************/
|
||||
void LoadTaskSettings(byte TaskIndex)
|
||||
String LoadTaskSettings(byte TaskIndex)
|
||||
{
|
||||
//already loaded
|
||||
if (ExtraTaskSettings.TaskIndex == TaskIndex)
|
||||
return;
|
||||
return(String());
|
||||
|
||||
LoadFromFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
|
||||
String result = "";
|
||||
result = LoadFromFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
|
||||
ExtraTaskSettings.TaskIndex = TaskIndex; // Needed when an empty task was requested
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Save Custom Task settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
|
||||
String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_TASKS_SIZE)
|
||||
return false;
|
||||
return SaveToFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize);
|
||||
return F("SaveCustomTaskSettings too big");
|
||||
return(SaveToFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Load Custom Task settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
void LoadCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
|
||||
String LoadCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_TASKS_SIZE)
|
||||
return;
|
||||
LoadFromFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize);
|
||||
return (String(F("LoadCustomTaskSettings too big")));
|
||||
return(LoadFromFile((char*)"config.dat", DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize));
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Save Controller settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
|
||||
String SaveControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_CONTROLLER_SIZE)
|
||||
return false;
|
||||
return F("SaveControllerSettings too big");
|
||||
return SaveToFile((char*)"config.dat", DAT_OFFSET_CONTROLLER + (ControllerIndex * DAT_CONTROLLER_SIZE), memAddress, datasize);
|
||||
}
|
||||
|
||||
@@ -753,20 +795,21 @@ boolean SaveControllerSettings(int ControllerIndex, byte* memAddress, int datasi
|
||||
/********************************************************************************************\
|
||||
Load Controller settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
void LoadControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
|
||||
String LoadControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_CONTROLLER_SIZE)
|
||||
return;
|
||||
LoadFromFile((char*)"config.dat", DAT_OFFSET_CONTROLLER + (ControllerIndex * DAT_CONTROLLER_SIZE), memAddress, datasize);
|
||||
return F("LoadControllerSettings too big");
|
||||
|
||||
return(LoadFromFile((char*)"config.dat", DAT_OFFSET_CONTROLLER + (ControllerIndex * DAT_CONTROLLER_SIZE), memAddress, datasize));
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Save Custom Controller settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
|
||||
String SaveCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_CUSTOM_CONTROLLER_SIZE)
|
||||
return false;
|
||||
return F("SaveCustomControllerSettings too big");
|
||||
return SaveToFile((char*)"config.dat", DAT_OFFSET_CUSTOM_CONTROLLER + (ControllerIndex * DAT_CUSTOM_CONTROLLER_SIZE), memAddress, datasize);
|
||||
}
|
||||
|
||||
@@ -774,20 +817,20 @@ boolean SaveCustomControllerSettings(int ControllerIndex,byte* memAddress, int d
|
||||
/********************************************************************************************\
|
||||
Load Custom Controller settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
void LoadCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
|
||||
String LoadCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_CUSTOM_CONTROLLER_SIZE)
|
||||
return;
|
||||
LoadFromFile((char*)"config.dat", DAT_OFFSET_CUSTOM_CONTROLLER + (ControllerIndex * DAT_CUSTOM_CONTROLLER_SIZE), memAddress, datasize);
|
||||
return(F("LoadCustomControllerSettings too big"));
|
||||
return(LoadFromFile((char*)"config.dat", DAT_OFFSET_CUSTOM_CONTROLLER + (ControllerIndex * DAT_CUSTOM_CONTROLLER_SIZE), memAddress, datasize));
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Save Controller settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
|
||||
String SaveNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_NOTIFICATION_SIZE)
|
||||
return false;
|
||||
return F("SaveNotificationSettings too big");
|
||||
return SaveToFile((char*)"notification.dat", NotificationIndex * DAT_NOTIFICATION_SIZE, memAddress, datasize);
|
||||
}
|
||||
|
||||
@@ -795,64 +838,103 @@ boolean SaveNotificationSettings(int NotificationIndex, byte* memAddress, int da
|
||||
/********************************************************************************************\
|
||||
Load Controller settings to SPIFFS
|
||||
\*********************************************************************************************/
|
||||
void LoadNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
|
||||
String LoadNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
|
||||
{
|
||||
if (datasize > DAT_NOTIFICATION_SIZE)
|
||||
return;
|
||||
LoadFromFile((char*)"notification.dat", NotificationIndex * DAT_NOTIFICATION_SIZE, memAddress, datasize);
|
||||
return(F("LoadNotificationSettings too big"));
|
||||
return(LoadFromFile((char*)"notification.dat", NotificationIndex * DAT_NOTIFICATION_SIZE, memAddress, datasize));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
SPIFFS error handling
|
||||
Look here for error # reference: https://github.com/pellepl/spiffs/blob/master/src/spiffs.h
|
||||
\*********************************************************************************************/
|
||||
#define SPIFFS_CHECK(result, fname) if (!(result)) { return(FileError(__LINE__, fname)); }
|
||||
String FileError(int line, const char * fname)
|
||||
{
|
||||
String err("FS : Error while reading/writing ");
|
||||
err=err+fname;
|
||||
err=err+" in ";
|
||||
err=err+line;
|
||||
addLog(LOG_LEVEL_ERROR, err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Init a file with zeros on SPIFFS
|
||||
\*********************************************************************************************/
|
||||
String InitFile(const char* fname, int datasize)
|
||||
{
|
||||
|
||||
FLASH_GUARD();
|
||||
|
||||
fs::File f = SPIFFS.open(fname, "w");
|
||||
SPIFFS_CHECK(f, fname);
|
||||
|
||||
for (int x = 0; x < datasize ; x++)
|
||||
{
|
||||
SPIFFS_CHECK(f.write(0), fname);
|
||||
}
|
||||
f.close();
|
||||
|
||||
//OK
|
||||
return String();
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Save data into config file on SPIFFS
|
||||
\*********************************************************************************************/
|
||||
boolean SaveToFile(char* fname, int index, byte* memAddress, int datasize)
|
||||
String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
if (RTC.flashDayCounter > MAX_FLASHWRITES_PER_DAY)
|
||||
{
|
||||
String log = F("FS : Daily flash write rate exceeded!");
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
FLASH_GUARD();
|
||||
|
||||
fs::File f = SPIFFS.open(fname, "r+");
|
||||
if (f)
|
||||
SPIFFS_CHECK(f, fname);
|
||||
|
||||
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
|
||||
byte *pointerToByteToSave = memAddress;
|
||||
for (int x = 0; x < datasize ; x++)
|
||||
{
|
||||
f.seek(index, fs::SeekSet);
|
||||
byte *pointerToByteToSave = memAddress;
|
||||
for (int x = 0; x < datasize ; x++)
|
||||
{
|
||||
f.write(*pointerToByteToSave);
|
||||
pointerToByteToSave++;
|
||||
}
|
||||
f.close();
|
||||
String log = F("FILE : File saved");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
flashCount();
|
||||
SPIFFS_CHECK(f.write(*pointerToByteToSave), fname);
|
||||
pointerToByteToSave++;
|
||||
}
|
||||
return success;
|
||||
f.close();
|
||||
String log = F("FILE : Saved ");
|
||||
log=log+fname;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
//OK
|
||||
return String();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Load data from config file on SPIFFS
|
||||
\*********************************************************************************************/
|
||||
void LoadFromFile(char* fname, int index, byte* memAddress, int datasize)
|
||||
String LoadFromFile(char* fname, int index, byte* memAddress, int datasize)
|
||||
{
|
||||
// addLog(LOG_LEVEL_INFO, String(F("FILE : Load size "))+datasize);
|
||||
|
||||
fs::File f = SPIFFS.open(fname, "r+");
|
||||
if (f)
|
||||
SPIFFS_CHECK(f, fname);
|
||||
|
||||
// addLog(LOG_LEVEL_INFO, String(F("FILE : File size "))+f.size());
|
||||
|
||||
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
|
||||
byte *pointerToByteToRead = memAddress;
|
||||
for (int x = 0; x < datasize; x++)
|
||||
{
|
||||
f.seek(index, fs::SeekSet);
|
||||
byte *pointerToByteToRead = memAddress;
|
||||
for (int x = 0; x < datasize; x++)
|
||||
{
|
||||
*pointerToByteToRead = f.read();
|
||||
pointerToByteToRead++;// next byte
|
||||
}
|
||||
f.close();
|
||||
int readres=f.read();
|
||||
SPIFFS_CHECK(readres >=0, fname);
|
||||
*pointerToByteToRead = readres;
|
||||
pointerToByteToRead++;// next byte
|
||||
}
|
||||
f.close();
|
||||
|
||||
return(String());
|
||||
}
|
||||
|
||||
|
||||
@@ -874,62 +956,54 @@ void ResetFactory(void)
|
||||
{
|
||||
|
||||
// Direct Serial is allowed here, since this is only an emergency task.
|
||||
Serial.println(F("Resetting factory defaults..."));
|
||||
Serial.println(F("RESET: Resetting factory defaults..."));
|
||||
delay(1000);
|
||||
if (readFromRTC())
|
||||
{
|
||||
Serial.print(F("RESET: Reboot count: "));
|
||||
Serial.print(F("RESET: Warm boot, reset count: "));
|
||||
Serial.println(RTC.factoryResetCounter);
|
||||
if (RTC.factoryResetCounter > 3)
|
||||
if (RTC.factoryResetCounter >= 3)
|
||||
{
|
||||
Serial.println(F("RESET: To many reset attempts"));
|
||||
Serial.println(F("RESET: Too many resets, protecting your flash memory (powercycle to solve this)"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("RESET: Cold boot"));
|
||||
initRTC();
|
||||
}
|
||||
|
||||
RTC.flashCounter=0; //reset flashcounter, since we're already counting the number of factory-resets. we dont want to hit a flash-count limit during reset.
|
||||
RTC.factoryResetCounter++;
|
||||
RTC.flashDayCounter = 0;
|
||||
saveToRTC();
|
||||
|
||||
//always format on factory reset, in case of corrupt SPIFFS
|
||||
SPIFFS.end();
|
||||
Serial.println(F("FS : formatting..."));
|
||||
Serial.println(F("RESET: formatting..."));
|
||||
SPIFFS.format();
|
||||
Serial.println(F("FS : formatting done..."));
|
||||
Serial.println(F("RESET: formatting done..."));
|
||||
if (!SPIFFS.begin())
|
||||
{
|
||||
Serial.println(F("FS : FORMATTING SPIFFS FAILED!"));
|
||||
Serial.println(F("RESET: FORMAT SPIFFS FAILED!"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fs::File f = SPIFFS.open("config.dat", "w");
|
||||
if (f)
|
||||
{
|
||||
for (int x = 0; x < 65536; x++)
|
||||
f.write(0);
|
||||
f.close();
|
||||
}
|
||||
//pad files with extra zeros for future extensions
|
||||
String fname;
|
||||
|
||||
f = SPIFFS.open("security.dat", "w");
|
||||
if (f)
|
||||
{
|
||||
for (int x = 0; x < 512; x++)
|
||||
f.write(0);
|
||||
f.close();
|
||||
}
|
||||
fname=F("config.dat");
|
||||
InitFile(fname.c_str(), 65536);
|
||||
|
||||
f = SPIFFS.open("notification.dat", "w");
|
||||
if (f)
|
||||
{
|
||||
for (int x = 0; x < 4096; x++)
|
||||
f.write(0);
|
||||
f.close();
|
||||
}
|
||||
f = SPIFFS.open("rules1.txt", "w");
|
||||
f.close();
|
||||
fname=F("security.dat");
|
||||
InitFile(fname.c_str(), 4096);
|
||||
|
||||
fname=F("notification.dat");
|
||||
InitFile(fname.c_str(), 4096);
|
||||
|
||||
fname=F("rules1.txt");
|
||||
InitFile(fname.c_str(), 0);
|
||||
|
||||
LoadSettings();
|
||||
// now we set all parameters that need to be non-zero as default value
|
||||
@@ -941,11 +1015,6 @@ void ResetFactory(void)
|
||||
str2ip((char*)DEFAULT_SUBNET, Settings.Subnet);
|
||||
#endif
|
||||
|
||||
#if DEFAULT_MQTT_TEMPLATE
|
||||
strcpy_P(Settings.MQTTsubscribe, PSTR(DEFAULT_MQTT_SUB));
|
||||
strcpy_P(Settings.MQTTpublish, PSTR(DEFAULT_MQTT_PUB));
|
||||
#endif
|
||||
|
||||
Settings.PID = ESP_PROJECT_PID;
|
||||
Settings.Version = VERSION;
|
||||
Settings.Unit = UNIT;
|
||||
@@ -953,8 +1022,6 @@ void ResetFactory(void)
|
||||
strcpy_P(SecuritySettings.WifiKey, PSTR(DEFAULT_KEY));
|
||||
strcpy_P(SecuritySettings.WifiAPKey, PSTR(DEFAULT_AP_KEY));
|
||||
SecuritySettings.Password[0] = 0;
|
||||
//str2ip((char*)DEFAULT_SERVER, Settings.Controller_IP[0]);
|
||||
//Settings.ControllerPort[0] = DEFAULT_PORT;
|
||||
Settings.Delay = DEFAULT_DELAY;
|
||||
Settings.Pin_i2c_sda = 4;
|
||||
Settings.Pin_i2c_scl = 5;
|
||||
@@ -984,7 +1051,19 @@ void ResetFactory(void)
|
||||
Settings.Build = BUILD;
|
||||
Settings.UseSerial = true;
|
||||
SaveSettings();
|
||||
Serial.println("Factory reset succesful, rebooting...");
|
||||
|
||||
#if DEFAULT_CONTROLLER
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
strcpy_P(ControllerSettings.Subscribe, PSTR(DEFAULT_SUB));
|
||||
strcpy_P(ControllerSettings.Publish, PSTR(DEFAULT_PUB));
|
||||
str2ip((char*)DEFAULT_SERVER, ControllerSettings.IP);
|
||||
ControllerSettings.HostName[0]=0;
|
||||
ControllerSettings.Port = DEFAULT_PORT;
|
||||
SaveControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
#endif
|
||||
|
||||
Serial.println("RESET: Succesful, rebooting. (you might need to press the reset button if you've justed flashed the firmware)");
|
||||
//NOTE: this is a known ESP8266 bug, not our fault. :)
|
||||
delay(1000);
|
||||
WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
|
||||
WiFi.disconnect(); // this will store empty ssid/wpa into sdk storage
|
||||
@@ -1128,17 +1207,34 @@ void delayedReboot(int rebootDelay)
|
||||
/********************************************************************************************\
|
||||
Save RTC struct to RTC memory
|
||||
\*********************************************************************************************/
|
||||
//user-area of the esp starts at block 64 (bytes = block * 4)
|
||||
#define RTC_BASE_STRUCT 64
|
||||
boolean saveToRTC()
|
||||
{
|
||||
RTC.ID1 = 0xAA;
|
||||
RTC.ID2 = 0x55;
|
||||
RTC.valid = true;
|
||||
return(system_rtc_mem_write(RTC_BASE_STRUCT, (byte*)&RTC, sizeof(RTC)));
|
||||
if (!system_rtc_mem_write(RTC_BASE_STRUCT, (byte*)&RTC, sizeof(RTC)) || !readFromRTC())
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("RTC : Error while writing to RTC"));
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Initialize RTC memory
|
||||
\*********************************************************************************************/
|
||||
void initRTC()
|
||||
{
|
||||
memset(&RTC, 0, sizeof(RTC));
|
||||
RTC.ID1 = 0xAA;
|
||||
RTC.ID2 = 0x55;
|
||||
saveToRTC();
|
||||
|
||||
memset(&UserVar, 0, sizeof(UserVar));
|
||||
saveUserVarToRTC();
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Read RTC struct from RTC memory
|
||||
\*********************************************************************************************/
|
||||
@@ -1148,18 +1244,15 @@ boolean readFromRTC()
|
||||
return(false);
|
||||
|
||||
if (RTC.ID1 == 0xAA && RTC.ID2 == 0x55)
|
||||
{
|
||||
RTC.valid = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Save values to RTC memory
|
||||
\*********************************************************************************************/
|
||||
#define RTC_BASE_USERVAR 74
|
||||
boolean saveUserVarToRTC()
|
||||
{
|
||||
//addLog(LOG_LEVEL_DEBUG, F("RTCMEM: saveUserVarToRTC"));
|
||||
@@ -1347,6 +1440,8 @@ String getTimeString(char delimiter)
|
||||
reply += minute();
|
||||
if (delimiter != '\0')
|
||||
reply += delimiter;
|
||||
if (second() < 10)
|
||||
reply += F("0");
|
||||
reply += second();
|
||||
return reply;
|
||||
}
|
||||
@@ -1451,10 +1546,12 @@ String parseTemplate(String &tmpString, byte lineSize)
|
||||
{
|
||||
if (deviceName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName))
|
||||
{
|
||||
boolean match = false;
|
||||
for (byte z = 0; z < VARS_PER_TASK; z++)
|
||||
if (valueName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceValueNames[z]))
|
||||
{
|
||||
// here we know the task and value, so find the uservar
|
||||
match = true;
|
||||
String value = "";
|
||||
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]);
|
||||
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG)
|
||||
@@ -1471,6 +1568,14 @@ String parseTemplate(String &tmpString, byte lineSize)
|
||||
newString += String(value);
|
||||
break;
|
||||
}
|
||||
if (!match) // try if this is a get config request
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.TaskIndex = y;
|
||||
String tmpName = valueName;
|
||||
if (PluginCall(PLUGIN_GET_CONFIG, &TempEvent, tmpName))
|
||||
newString += tmpName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2431,14 +2536,53 @@ void createRuleEvents(byte TaskIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void checkRAM(byte id)
|
||||
|
||||
void SendValueLogger(byte TaskIndex)
|
||||
{
|
||||
String logger;
|
||||
|
||||
LoadTaskSettings(TaskIndex);
|
||||
byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
|
||||
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
|
||||
byte sensorType = Device[DeviceIndex].VType;
|
||||
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
|
||||
{
|
||||
logger += getDateString('-');
|
||||
logger += F(" ");
|
||||
logger += getTimeString(':');
|
||||
logger += F(",");
|
||||
logger += Settings.Unit;
|
||||
logger += F(",");
|
||||
logger += ExtraTaskSettings.TaskDeviceName;
|
||||
logger += F(",");
|
||||
logger += ExtraTaskSettings.TaskDeviceValueNames[varNr];
|
||||
logger += F(",");
|
||||
|
||||
if (sensorType == SENSOR_TYPE_LONG)
|
||||
logger += (unsigned long)UserVar[BaseVarIndex] + ((unsigned long)UserVar[BaseVarIndex + 1] << 16);
|
||||
else
|
||||
logger += String(UserVar[BaseVarIndex + varNr], ExtraTaskSettings.TaskDeviceValueDecimals[varNr]);
|
||||
logger += F("\r\n");
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG, logger);
|
||||
|
||||
String filename = F("VALUES.CSV");
|
||||
File logFile = SD.open(filename, FILE_WRITE);
|
||||
if (logFile)
|
||||
logFile.print(logger);
|
||||
logFile.close();
|
||||
}
|
||||
|
||||
|
||||
void checkRAM( const __FlashStringHelper* flashString)
|
||||
{
|
||||
uint16_t freeRAM = FreeMem();
|
||||
|
||||
if (freeRAM < lowestRAM)
|
||||
{
|
||||
lowestRAM = freeRAM;
|
||||
lowestRAMid = id;
|
||||
lowestRAMfunction = flashString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2702,4 +2846,4 @@ void htmlEscape(String & html)
|
||||
html.replace("'", "'");
|
||||
html.replace("<", "<");
|
||||
html.replace(">", ">");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -25,8 +25,10 @@ void serial()
|
||||
InputBuffer_Serial[SerialInByteCounter++] = SerialInByte;
|
||||
}
|
||||
|
||||
if (SerialInByte == '\n')
|
||||
if (SerialInByte == '\r' || SerialInByte == '\n')
|
||||
{
|
||||
if (SerialInByteCounter == 0) //empty command?
|
||||
break;
|
||||
InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed
|
||||
Serial.write('>');
|
||||
Serial.println(InputBuffer_Serial);
|
||||
@@ -41,4 +43,3 @@ void serial()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+652
-290
File diff suppressed because it is too large
Load Diff
+165
-101
@@ -1,52 +1,90 @@
|
||||
//********************************************************************************
|
||||
// Determine Wifi AP name to set. (also used for mDNS)
|
||||
//********************************************************************************
|
||||
String WifiGetAPssid()
|
||||
{
|
||||
String ssid(Settings.Name);
|
||||
ssid+=F("_");
|
||||
ssid+=Settings.Unit;
|
||||
return (ssid);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Determine hostname: basically WifiGetAPssid with spaces changed to -
|
||||
//********************************************************************************
|
||||
String WifiGetHostname()
|
||||
{
|
||||
String hostname(WifiGetAPssid());
|
||||
hostname.replace(F(" "), F("-"));
|
||||
return (hostname);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode config
|
||||
//********************************************************************************
|
||||
void WifiAPconfig()
|
||||
{
|
||||
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
|
||||
char ap_ssid[20];
|
||||
ap_ssid[0] = 0;
|
||||
strcpy(ap_ssid, "ESP_");
|
||||
sprintf_P(ap_ssid, PSTR("%s%u"), ap_ssid, Settings.Unit);
|
||||
// setup ssid for AP Mode when needed
|
||||
WiFi.softAP(ap_ssid, SecuritySettings.WifiAPKey);
|
||||
WiFi.softAP(WifiGetAPssid().c_str(), SecuritySettings.WifiAPKey);
|
||||
// We start in STA mode
|
||||
WiFi.mode(WIFI_STA);
|
||||
WifiAPMode(false);
|
||||
|
||||
String log("WIFI : AP Mode ssid will be ");
|
||||
log=log+WifiGetAPssid();
|
||||
|
||||
log=log+F(" with address ");
|
||||
log=log+apIP.toString();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool WifiIsAP()
|
||||
{
|
||||
byte wifimode = wifi_get_opmode();
|
||||
return(wifimode == 2 || wifimode == 3); //apmode is enabled
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode
|
||||
//********************************************************************************
|
||||
void WifiAPMode(boolean state)
|
||||
{
|
||||
if (state)
|
||||
if (WifiIsAP())
|
||||
{
|
||||
AP_Mode = true;
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
//want to disable?
|
||||
if (!state)
|
||||
{
|
||||
WiFi.mode(WIFI_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode disabled"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AP_Mode = false;
|
||||
WiFi.mode(WIFI_STA);
|
||||
//want to enable?
|
||||
if (state)
|
||||
{
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Connect to Wifi AP
|
||||
// Configure network and connect to Wifi SSID and SSID2
|
||||
//********************************************************************************
|
||||
boolean WifiConnect(boolean primary, byte connectAttempts)
|
||||
boolean WifiConnect(byte connectAttempts)
|
||||
{
|
||||
String log = "";
|
||||
char hostname[40];
|
||||
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
|
||||
wifi_station_set_hostname(hostname);
|
||||
|
||||
char hostName[sizeof(Settings.Name)];
|
||||
strcpy(hostName,Settings.Name);
|
||||
for(byte x=0; x< sizeof(hostName); x++)
|
||||
if (hostName[x] == ' ')
|
||||
hostName[x] = '-';
|
||||
wifi_station_set_hostname(hostName);
|
||||
|
||||
//use static ip?
|
||||
if (Settings.IP[0] != 0 && Settings.IP[0] != 255)
|
||||
{
|
||||
char str[20];
|
||||
@@ -61,87 +99,120 @@ boolean WifiConnect(boolean primary, byte connectAttempts)
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
//try to connect to one of the access points
|
||||
if (WifiConnectSSID(SecuritySettings.WifiSSID, SecuritySettings.WifiKey, connectAttempts) ||
|
||||
WifiConnectSSID(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2, connectAttempts))
|
||||
{
|
||||
if ((SecuritySettings.WifiSSID[0] != 0) && (strcasecmp(SecuritySettings.WifiSSID, "ssid") != 0))
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++)
|
||||
{
|
||||
log = F("WIFI : Connecting... ");
|
||||
log += tryConnect;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
}
|
||||
|
||||
if (tryConnect == 1)
|
||||
{
|
||||
if (primary)
|
||||
WiFi.begin(SecuritySettings.WifiSSID, SecuritySettings.WifiKey);
|
||||
else
|
||||
WiFi.begin(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2);
|
||||
}
|
||||
else
|
||||
WiFi.begin();
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
for (byte x = 0; x < 200; x++)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
statusLED(false);
|
||||
delay(50);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char str[20];
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
log += str;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
log = F("WIFI : Disconnecting!");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_disconnect();
|
||||
ETS_UART_INTR_ENABLE();
|
||||
for (byte x = 0; x < 20; x++)
|
||||
{
|
||||
statusLED(true);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
String log = F("WIFI : ");
|
||||
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
|
||||
|
||||
log += F("mDNS started, with name: ");
|
||||
log += WifiGetHostname();
|
||||
log += F(".local");
|
||||
}
|
||||
|
||||
// fix ip if last octet is set
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP :");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
else{
|
||||
log += F("mDNS failed");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
|
||||
|
||||
//everything failed, activate AP mode (will deactivate automaticly after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Connect to Wifi specific SSID
|
||||
//********************************************************************************
|
||||
boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
|
||||
{
|
||||
String log;
|
||||
|
||||
//already connected, need to disconnect first
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return(true);
|
||||
|
||||
//no ssid specified
|
||||
if ((WifiSSID[0] == 0) || (strcasecmp(WifiSSID, "ssid") == 0))
|
||||
return(false);
|
||||
|
||||
for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++)
|
||||
{
|
||||
log = F("WIFI : Connecting ");
|
||||
log += WifiSSID;
|
||||
log += F(" attempt #");
|
||||
log += tryConnect;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (tryConnect == 1)
|
||||
WiFi.begin(WifiSSID, WifiKey);
|
||||
else
|
||||
WiFi.begin();
|
||||
|
||||
//wait until it connects
|
||||
for (byte x = 0; x < 200; x++)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
statusLED(false);
|
||||
delay(50);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char str[20];
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
log += str;
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(")");
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
log = F("WIFI : No SSID!");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
NC_Count = 1;
|
||||
WifiAPMode(true);
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_disconnect();
|
||||
ETS_UART_INTR_ENABLE();
|
||||
for (byte x = 0; x < 20; x++)
|
||||
{
|
||||
statusLED(true);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -203,30 +274,23 @@ void WifiCheck()
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
NC_Count++;
|
||||
//give it time to automaticly reconnect
|
||||
if (NC_Count > 2)
|
||||
{
|
||||
if (!WifiConnect(true,2))
|
||||
WifiConnect(false,2);
|
||||
WifiConnect(2);
|
||||
|
||||
C_Count=0;
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
WifiAPMode(true);
|
||||
NC_Count = 0;
|
||||
}
|
||||
}
|
||||
//connected
|
||||
else
|
||||
{
|
||||
C_Count++;
|
||||
NC_Count = 0;
|
||||
if (C_Count > 2) // close AP after timeout if a Wifi connection is established...
|
||||
if (C_Count > 2) // disable AP after timeout if a Wifi connection is established...
|
||||
{
|
||||
byte wifimode = wifi_get_opmode();
|
||||
if (wifimode == 2 || wifimode == 3) //apmode is active
|
||||
{
|
||||
WifiAPMode(false);
|
||||
log = F("WIFI : AP Mode inactive");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
WifiAPMode(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +166,17 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE: // any sensor that uses three simple values
|
||||
root[F("nvalue")] = 0;
|
||||
values = toString(UserVar[event->BaseVarIndex ], ExtraTaskSettings.TaskDeviceValueDecimals[0]);
|
||||
values += ";";
|
||||
values += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
values += ";";
|
||||
values += toString(UserVar[event->BaseVarIndex + 2], ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
|
||||
root[F("nvalue")] = 0;
|
||||
values = toString(UserVar[event->BaseVarIndex], ExtraTaskSettings.TaskDeviceValueDecimals[0]);
|
||||
|
||||
+16
-16
@@ -8,17 +8,17 @@
|
||||
#define CPLUGIN_ID_011 11
|
||||
#define CPLUGIN_NAME_011 "Generic HTTP Advanced [TESTING]"
|
||||
|
||||
#define P011_HTTP_METHOD_MAX_LEN 16
|
||||
#define P011_HTTP_URI_MAX_LEN 240
|
||||
#define P011_HTTP_HEADER_MAX_LEN 256
|
||||
#define P011_HTTP_BODY_MAX_LEN 512
|
||||
#define C011_HTTP_METHOD_MAX_LEN 16
|
||||
#define C011_HTTP_URI_MAX_LEN 240
|
||||
#define C011_HTTP_HEADER_MAX_LEN 256
|
||||
#define C011_HTTP_BODY_MAX_LEN 512
|
||||
|
||||
struct P011_ConfigStruct
|
||||
struct C011_ConfigStruct
|
||||
{
|
||||
char HttpMethod[P011_HTTP_METHOD_MAX_LEN];
|
||||
char HttpUri[P011_HTTP_URI_MAX_LEN];
|
||||
char HttpHeader[P011_HTTP_HEADER_MAX_LEN];
|
||||
char HttpBody[P011_HTTP_BODY_MAX_LEN];
|
||||
char HttpMethod[C011_HTTP_METHOD_MAX_LEN];
|
||||
char HttpUri[C011_HTTP_URI_MAX_LEN];
|
||||
char HttpHeader[C011_HTTP_HEADER_MAX_LEN];
|
||||
char HttpBody[C011_HTTP_BODY_MAX_LEN];
|
||||
};
|
||||
|
||||
boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
|
||||
@@ -48,7 +48,7 @@ boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
String escapeBuffer;
|
||||
|
||||
P011_ConfigStruct customConfig;
|
||||
C011_ConfigStruct customConfig;
|
||||
|
||||
LoadCustomControllerSettings(event->ControllerIndex,(byte*)&customConfig, sizeof(customConfig));
|
||||
String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") };
|
||||
@@ -65,14 +65,14 @@ boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
|
||||
string += F("</select>");
|
||||
|
||||
string += F("<TR><TD>HTTP URI:<TD><input type='text' name='P011httpuri' size=80 maxlength='");
|
||||
string += P011_HTTP_URI_MAX_LEN-1;
|
||||
string += C011_HTTP_URI_MAX_LEN-1;
|
||||
string += F("' value='");
|
||||
string += customConfig.HttpUri;
|
||||
|
||||
string += F("'>");
|
||||
|
||||
string += F("<TR><TD>HTTP Header:<TD><textarea name='P011httpheader' rows='4' cols='50' maxlength='");
|
||||
string += P011_HTTP_HEADER_MAX_LEN-1;
|
||||
string += C011_HTTP_HEADER_MAX_LEN-1;
|
||||
string += F("'>");
|
||||
escapeBuffer=customConfig.HttpHeader;
|
||||
htmlEscape(escapeBuffer);
|
||||
@@ -80,7 +80,7 @@ boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
|
||||
string += F("</textarea>");
|
||||
|
||||
string += F("<TR><TD>HTTP Body:<TD><textarea name='P011httpbody' rows='8' cols='50' maxlength='");
|
||||
string += P011_HTTP_BODY_MAX_LEN-1;
|
||||
string += C011_HTTP_BODY_MAX_LEN-1;
|
||||
string += F("'>");
|
||||
escapeBuffer=customConfig.HttpBody;
|
||||
htmlEscape(escapeBuffer);
|
||||
@@ -91,7 +91,7 @@ boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
P011_ConfigStruct customConfig;
|
||||
C011_ConfigStruct customConfig;
|
||||
String httpmethod = WebServer.arg(F("P011httpmethod"));
|
||||
String httpuri = WebServer.arg(F("P011httpuri"));
|
||||
String httpheader = WebServer.arg(F("P011httpheader"));
|
||||
@@ -135,7 +135,7 @@ boolean HTTPSend011(struct EventStruct *event)
|
||||
authHeader += F(" \r\n");
|
||||
}
|
||||
|
||||
P011_ConfigStruct customConfig;
|
||||
C011_ConfigStruct customConfig;
|
||||
LoadCustomControllerSettings(event->ControllerIndex,(byte*)&customConfig, sizeof(customConfig));
|
||||
|
||||
boolean success = false;
|
||||
@@ -312,7 +312,7 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event)
|
||||
s.replace(F("%systime%"), getTimeString(':'));
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
newString.replace(F("%vcc%"), String(vcc));
|
||||
s.replace(F("%vcc%"), String(vcc));
|
||||
#endif
|
||||
|
||||
// IPAddress ip = WiFi.localIP();
|
||||
|
||||
+6
-6
@@ -78,12 +78,12 @@ boolean NPlugin_001_send(String aDomain , String aTo, String aFrom, String aSub,
|
||||
// The MTA Exchange
|
||||
while (true) {
|
||||
|
||||
if (NPlugin_001_MTA(client, "", PSTR("220 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, PSTR("EHLO ") + aDomain, PSTR("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, PSTR("MAIL FROM:") + aFrom + "", PSTR("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, PSTR("RCPT TO:") + aTo + "", PSTR("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, PSTR("DATA"), PSTR("354 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, PSTR("Subject:") + aSub + PSTR("\r\n\r\n") + aMesg + PSTR("\r\n.\r\n"), PSTR("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, "", F("220 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("EHLO ")) + aDomain, F("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("MAIL FROM:")) + aFrom + "", F("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("RCPT TO:")) + aTo + "", F("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, F("DATA"), F("354 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("Subject:")) + aSub + F("\r\n\r\n") + aMesg + F("\r\n.\r\n"), F("250 ")) == false) break;
|
||||
|
||||
myStatus = true;
|
||||
break;
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
|
||||
case 3:
|
||||
{
|
||||
event->sensorType = SENSOR_TYPE_DUAL;
|
||||
UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#define PLUGIN_004
|
||||
#define PLUGIN_ID_004 4
|
||||
#define PLUGIN_NAME_004 "Temperature - DS18b20"
|
||||
#define PLUGIN_NAME_004 "Environment - DS18b20"
|
||||
#define PLUGIN_VALUENAME1_004 "Temperature"
|
||||
|
||||
uint8_t Plugin_004_DallasPin;
|
||||
|
||||
+84
-24
@@ -7,15 +7,13 @@
|
||||
#define PLUGIN_NAME_008 "RFID Reader - Wiegand"
|
||||
#define PLUGIN_VALUENAME1_008 "Tag"
|
||||
|
||||
#define PLUGIN_008_WGSIZE 26
|
||||
|
||||
void Plugin_008_interrupt1() ICACHE_RAM_ATTR;
|
||||
void Plugin_008_interrupt2() ICACHE_RAM_ATTR;
|
||||
|
||||
volatile byte Plugin_008_bitCount = 0; // Count the number of bits received.
|
||||
volatile unsigned long Plugin_008_keyBuffer = 0; // A 32-bit-long keyBuffer into which the number is stored.
|
||||
byte Plugin_008_bitCountPrev = 0; // to detect noise
|
||||
byte Plugin_008_Unit = 0;
|
||||
volatile byte Plugin_008_bitCount = 0; // Count the number of bits received.
|
||||
uint64_t Plugin_008_keyBuffer = 0; // A 64-bit-long keyBuffer into which the number is stored.
|
||||
byte Plugin_008_timeoutCount = 0;
|
||||
byte Plugin_008_WiegandSize = 26; // size of a tag via wiegand (26-bits or 36-bits)
|
||||
|
||||
boolean Plugin_008_init = false;
|
||||
|
||||
@@ -52,10 +50,11 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string)
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_008));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Plugin_008_init = true;
|
||||
Plugin_008_WiegandSize = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
|
||||
pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP);
|
||||
attachInterrupt(Settings.TaskDevicePin1[event->TaskIndex], Plugin_008_interrupt1, FALLING);
|
||||
@@ -68,31 +67,93 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (Plugin_008_init)
|
||||
{
|
||||
if ((Plugin_008_bitCount != PLUGIN_008_WGSIZE) && (Plugin_008_bitCount == Plugin_008_bitCountPrev))
|
||||
if (Plugin_008_bitCount > 0)
|
||||
{
|
||||
// must be noise
|
||||
Plugin_008_bitCount = 0;
|
||||
if (Plugin_008_bitCount % 4 == 0 && ((Plugin_008_keyBuffer & 0xF) == 11))
|
||||
{
|
||||
// a number of keys were pressed and finished by #
|
||||
Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 4; // Strip #
|
||||
UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF);
|
||||
UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF);
|
||||
}
|
||||
else if (Plugin_008_bitCount == Plugin_008_WiegandSize)
|
||||
{
|
||||
// read a tag
|
||||
Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 1; // Strip leading and trailing parity bits from the keyBuffer
|
||||
if (Plugin_008_WiegandSize == 26)
|
||||
Plugin_008_keyBuffer &= 0xFFFFFF;
|
||||
else
|
||||
Plugin_008_keyBuffer &= 0xFFFFFFFF;
|
||||
UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF);
|
||||
UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// not enough bits, maybe next time
|
||||
Plugin_008_timeoutCount++;
|
||||
if (Plugin_008_timeoutCount > 5)
|
||||
{
|
||||
String log = F("RFID : reset bits: ");
|
||||
log += Plugin_008_bitCount;
|
||||
addLog(LOG_LEVEL_INFO, log );
|
||||
// reset after ~5 sec
|
||||
Plugin_008_keyBuffer = 0;
|
||||
Plugin_008_bitCount = 0;
|
||||
Plugin_008_timeoutCount = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// reset everything
|
||||
unsigned long bitCount = Plugin_008_bitCount; // copy for log
|
||||
unsigned long keyBuffer = Plugin_008_keyBuffer; // copy for log
|
||||
Plugin_008_keyBuffer = 0;
|
||||
}
|
||||
|
||||
if (Plugin_008_bitCount == PLUGIN_008_WGSIZE)
|
||||
{
|
||||
Plugin_008_bitCount = 0; // Read in the current key and reset everything so that the interrupts can
|
||||
|
||||
Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 1; // Strip leading and trailing parity bits from the keyBuffer
|
||||
Plugin_008_keyBuffer &= 0xFFFFFF;
|
||||
UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF);
|
||||
UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF);
|
||||
Plugin_008_bitCount = 0;
|
||||
Plugin_008_timeoutCount = 0;
|
||||
// write log
|
||||
String log = F("RFID : Tag: ");
|
||||
log += Plugin_008_keyBuffer;
|
||||
log += keyBuffer;
|
||||
log += F(" Bits: ");
|
||||
log += bitCount;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendData(event);
|
||||
}
|
||||
|
||||
Plugin_008_bitCountPrev = Plugin_008_bitCount; // store this value for next check, detect noise
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[2];
|
||||
options[0] = F("26 Bits");
|
||||
options[1] = F("34 Bits");
|
||||
int optionValues[2];
|
||||
optionValues[0] = 26;
|
||||
optionValues[1] = 34;
|
||||
string += F("<TR><TD>Wiegand Type:<TD><select name='plugin_008_type'>");
|
||||
for (byte x = 0; x < 2; x++)
|
||||
{
|
||||
string += F("<option value='");
|
||||
string += optionValues[x];
|
||||
string += "'";
|
||||
if (choice == optionValues[x])
|
||||
string += F(" selected");
|
||||
string += ">";
|
||||
string += options[x];
|
||||
string += F("</option>");
|
||||
}
|
||||
string += F("</select>");
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
String plugin1 = WebServer.arg(F("plugin_008_type"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -115,4 +176,3 @@ void Plugin_008_interrupt2()
|
||||
Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2)
|
||||
Plugin_008_bitCount++; // Increment the bit count
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -94,14 +94,16 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
AS_BH1750 sensor = AS_BH1750(address);
|
||||
sensors_resolution_t mode;
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_LOW)
|
||||
mode = RESOLUTION_LOW;
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_NORMAL)
|
||||
mode = RESOLUTION_NORMAL;
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_HIGH)
|
||||
mode = RESOLUTION_HIGH;
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_AUTO_HIGH)
|
||||
mode = RESOLUTION_AUTO_HIGH;
|
||||
// replaced the 8 lines below to optimize code
|
||||
mode = (sensors_resolution_t)Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
// if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_LOW)
|
||||
// mode = RESOLUTION_LOW;
|
||||
// if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_NORMAL)
|
||||
// mode = RESOLUTION_NORMAL;
|
||||
// if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_HIGH)
|
||||
// mode = RESOLUTION_HIGH;
|
||||
// if (Settings.TaskDevicePluginConfig[event->TaskIndex][1]==RESOLUTION_AUTO_HIGH)
|
||||
// mode = RESOLUTION_AUTO_HIGH;
|
||||
|
||||
sensor.begin(mode,Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
@@ -97,14 +97,14 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
|
||||
Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
float value = Plugin_013_read();
|
||||
String log = F("SR04 : Distance: ");
|
||||
if (value != -1)
|
||||
if (value > 0)
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = (float)Plugin_013_timer / 58;
|
||||
UserVar[event->BaseVarIndex] = value;
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
log += F("SR04 : Distance: No reading!");
|
||||
log += F("No reading!");
|
||||
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
}
|
||||
@@ -118,7 +118,7 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
|
||||
Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
byte state = 0;
|
||||
float value = Plugin_013_read();
|
||||
if (value != -1)
|
||||
if (value > 0)
|
||||
{
|
||||
if (value < Settings.TaskDevicePluginConfig[event->TaskIndex][1])
|
||||
state = 1;
|
||||
|
||||
+19
-10
@@ -53,7 +53,7 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
|
||||
string += F("<TR><TD>Check Value:<TD>");
|
||||
addTaskValueSelect(string, "plugin_021_value", Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
|
||||
addFormTextBox(string, F("Set Value"), F("plugin_021_setvalue"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0]), 8);
|
||||
addFormTextBox(string, F("Set Level"), F("plugin_021_setvalue"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0]), 8);
|
||||
|
||||
addFormTextBox(string, F("Hysteresis"), F("plugin_021_hyst"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]), 8);
|
||||
|
||||
@@ -72,26 +72,34 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_REMOTE_CONFIG:
|
||||
case PLUGIN_SET_CONFIG:
|
||||
{
|
||||
Serial.print("levelplugin: ");
|
||||
Serial.println(string);
|
||||
String command = parseString(string, 1);
|
||||
if (command == F("setlevel"))
|
||||
{
|
||||
String value = parseString(string, 2);
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = value.toFloat();
|
||||
Serial.println(value);
|
||||
float result=0;
|
||||
byte error = Calculate(value.c_str(), &result);
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = result;
|
||||
SaveSettings();
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_CONFIG:
|
||||
{
|
||||
String command = parseString(string, 1);
|
||||
if (command == F("getlevel"))
|
||||
{
|
||||
string = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0];
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Serial.print(F("INIT : Output "));
|
||||
Serial.println(Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT);
|
||||
success = true;
|
||||
break;
|
||||
@@ -113,8 +121,9 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
|
||||
state = 0;
|
||||
if (state != switchstate[event->TaskIndex])
|
||||
{
|
||||
Serial.print(F("Out : State "));
|
||||
Serial.println(state);
|
||||
String log = F("LEVEL: State ");
|
||||
log += state;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
switchstate[event->TaskIndex] = state;
|
||||
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex],state);
|
||||
UserVar[event->BaseVarIndex] = state;
|
||||
|
||||
+27
-3
@@ -1,5 +1,5 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 026: Analog ###############################################
|
||||
//#################################### Plugin 026: System Info ##########################################
|
||||
//#######################################################################################################
|
||||
|
||||
#define PLUGIN_026
|
||||
@@ -40,13 +40,17 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[5];
|
||||
String options[9];
|
||||
options[0] = F("Uptime");
|
||||
options[1] = F("Free RAM");
|
||||
options[2] = F("Wifi RSSI");
|
||||
options[3] = F("Input VCC");
|
||||
options[4] = F("System load");
|
||||
addFormSelector(string, F("Indicator"), F("plugin_026"), 5, options, NULL, choice);
|
||||
options[5] = F("IP 1.Octet");
|
||||
options[6] = F("IP 2.Octet");
|
||||
options[7] = F("IP 3.Octet");
|
||||
options[8] = F("IP 4.Octet");
|
||||
addFormSelector(string, F("Indicator"), F("plugin_026"), 9, options, NULL, choice);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -93,6 +97,26 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
|
||||
value = (100 - (100 * loopCounterLast / loopCounterMax));
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
value = WiFi.localIP()[0];
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
value = WiFi.localIP()[1];
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
value = WiFi.localIP()[2];
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
value = WiFi.localIP()[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
UserVar[event->BaseVarIndex] = value;
|
||||
String log = F("SYS : ");
|
||||
|
||||
+94
-39
@@ -6,6 +6,8 @@
|
||||
#define PLUGIN_ID_027 27
|
||||
#define PLUGIN_NAME_027 "Voltage & Current (DC) - INA219"
|
||||
#define PLUGIN_VALUENAME1_027 "Voltage"
|
||||
#define PLUGIN_VALUENAME2_027 "Current"
|
||||
#define PLUGIN_VALUENAME3_027 "Power"
|
||||
|
||||
#define INA219_ADDRESS (0x40) // 1000000 (A0+A1=GND)
|
||||
#define INA219_ADDRESS2 (0x41) // 1000000 (A0+A1=GND)
|
||||
@@ -77,13 +79,13 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_027;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_TRIPLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].ValueCount = 3;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
@@ -98,26 +100,25 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_027));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_027));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_027));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[3];
|
||||
options[0] = F("Voltage");
|
||||
options[1] = F("Current");
|
||||
options[2] = F("Power");
|
||||
addFormSelector(string, F("Report"), F("plugin_027_value"), 3, options, NULL, choice);
|
||||
byte choiceMode = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String optionsMode[3];
|
||||
optionsMode[0] = F("32V, 2A");
|
||||
optionsMode[1] = F("32V, 1A");
|
||||
optionsMode[2] = F("16V, 0.4A");
|
||||
int optionValuesMode[3];
|
||||
optionValuesMode[0] = 0;
|
||||
optionValuesMode[1] = 1;
|
||||
optionValuesMode[2] = 2;
|
||||
addFormSelector(string, F("Measure range"), F("plugin_027_range"), 3, optionsMode, optionValuesMode, choiceMode);
|
||||
|
||||
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
/*
|
||||
String options2[4];
|
||||
options2[0] = F("0x40 - (default)");
|
||||
options2[1] = F("0x41");
|
||||
options2[2] = F("0x44");
|
||||
options2[3] = F("0x45");
|
||||
*/
|
||||
int optionValues2[4];
|
||||
optionValues2[0] = INA219_ADDRESS;
|
||||
optionValues2[1] = INA219_ADDRESS2;
|
||||
@@ -125,15 +126,19 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
|
||||
optionValues2[3] = INA219_ADDRESS4;
|
||||
addFormSelectorI2C(string, F("plugin_027_i2c"), 4, optionValues2, choice2);
|
||||
|
||||
byte choiceMeasureType = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
String options[4] = { F("Voltage"), F("Current"), F("Power"), F("Voltage/Current/Power") };
|
||||
addFormSelector(string, F("Measurement Type"), F("plugin_027_measuretype"), 4, options, NULL, choiceMeasureType );
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_027_value"));
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_027_range"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_027_i2c"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_027_measuretype"));
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -141,7 +146,31 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
ina219_i2caddr = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
Plugin_027_begin();
|
||||
|
||||
ina219_currentDivider_mA = 0;
|
||||
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("INA219 setting Range to: 32V, 2A"));
|
||||
Plugin_027_setCalibration_32V_2A();
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("INA219 setting Range to: 32V, 1A"));
|
||||
Plugin_027_setCalibration_32V_1A();
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("INA219 setting Range to: 16V, 400mA"));
|
||||
Plugin_027_setCalibration_16V_400mA();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -152,29 +181,66 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
|
||||
// busvoltage = Plugin_027_getBusVoltage_V();
|
||||
// current_mA = Plugin_027_getCurrent_mA();
|
||||
// loadvoltage = Plugin_027_getBusVoltage_V() + (Plugin_027_getShuntVoltage_mV() / 1000);
|
||||
float value=0;
|
||||
switch(Settings.TaskDevicePluginConfig[event->TaskIndex][0])
|
||||
|
||||
|
||||
float voltage = Plugin_027_getBusVoltage_V() + (Plugin_027_getShuntVoltage_mV() / 1000);
|
||||
|
||||
float current = Plugin_027_getCurrent_mA()/1000;
|
||||
|
||||
float power = (Plugin_027_getBusVoltage_V() + (Plugin_027_getShuntVoltage_mV() / 1000)) * Plugin_027_getCurrent_mA() / 1000;
|
||||
|
||||
UserVar[event->BaseVarIndex] = voltage;
|
||||
UserVar[event->BaseVarIndex + 1] = current;
|
||||
UserVar[event->BaseVarIndex + 2] = power;
|
||||
|
||||
String log = F("INA219 0x");
|
||||
log += String(ina219_i2caddr,HEX);
|
||||
|
||||
// for backward compability we allow the user to select if only one measurement should be returned
|
||||
// or all 3 measurement at once
|
||||
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][2])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
value = Plugin_027_getBusVoltage_V() + (Plugin_027_getShuntVoltage_mV() / 1000);
|
||||
event->sensorType = SENSOR_TYPE_SINGLE;
|
||||
UserVar[event->BaseVarIndex] = voltage;
|
||||
log += F(": Voltage: ");
|
||||
log += voltage;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
value = Plugin_027_getCurrent_mA()/1000;
|
||||
event->sensorType = SENSOR_TYPE_SINGLE;
|
||||
UserVar[event->BaseVarIndex] = current;
|
||||
log += F(" Current: ");
|
||||
log += current;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
value = (Plugin_027_getBusVoltage_V() + (Plugin_027_getShuntVoltage_mV() / 1000)) * Plugin_027_getCurrent_mA() / 1000;
|
||||
event->sensorType = SENSOR_TYPE_SINGLE;
|
||||
UserVar[event->BaseVarIndex] = power;
|
||||
log += F(" Power: ");
|
||||
log += power;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
event->sensorType = SENSOR_TYPE_TRIPLE;
|
||||
UserVar[event->BaseVarIndex] = voltage;
|
||||
UserVar[event->BaseVarIndex+1] = current;
|
||||
UserVar[event->BaseVarIndex+2] = power;
|
||||
log += F(": Voltage: ");
|
||||
log += voltage;
|
||||
log += F(" Current: ");
|
||||
log += current;
|
||||
log += F(" Power: ");
|
||||
log += power;
|
||||
break;
|
||||
}
|
||||
}
|
||||
UserVar[event->BaseVarIndex] = value;
|
||||
String log = F("INA : value: ");
|
||||
log += value;
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -279,17 +345,6 @@ void Plugin_027_setCalibration_16V_400mA(void) {
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************/
|
||||
// Setups the HW (defaults to 32V and 2A for calibration values)
|
||||
//**************************************************************************/
|
||||
|
||||
void Plugin_027_begin(void) {
|
||||
ina219_currentDivider_mA = 0;
|
||||
|
||||
// Set chip to large range config values to start
|
||||
Plugin_027_setCalibration_32V_2A();
|
||||
}
|
||||
|
||||
//**************************************************************************/
|
||||
// Gets the raw bus voltage (16-bit signed integer, so +-32767)
|
||||
//**************************************************************************/
|
||||
|
||||
@@ -39,6 +39,24 @@ boolean Plugin_029(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
// We need the index of the controller we are: 0-CONTROLLER_MAX
|
||||
byte controllerNr = 0;
|
||||
for (byte i=0; i < CONTROLLER_MAX; i++)
|
||||
{
|
||||
// if (Settings.Protocol[i] == CPLUGIN_ID_002) { controllerNr = i; } -> error: 'CPLUGIN_ID_002' was not declared in this scope
|
||||
if (Settings.Protocol[i] == 2) { controllerNr = i; }
|
||||
}
|
||||
|
||||
string += F("<TR><TD>IDX:<TD>");
|
||||
String id = F("TDID"); //="taskdeviceid"
|
||||
id += controllerNr + 1;
|
||||
addNumericBox(string, id, Settings.TaskDeviceID[controllerNr][event->TaskIndex], 0, 9999);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
success = true;
|
||||
|
||||
+36
-3
@@ -59,7 +59,7 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
|
||||
String IrType;
|
||||
unsigned long IrCode;
|
||||
unsigned int IrBits;
|
||||
char log[120];
|
||||
//char log[120];
|
||||
|
||||
char command[120];
|
||||
command[0] = 0;
|
||||
@@ -109,44 +109,77 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
unsigned int buf[200];
|
||||
unsigned int idx = 0;
|
||||
unsigned int c0 = 0;
|
||||
unsigned int c1 = 0;
|
||||
unsigned int c0 = 0; //count consecutives 0s
|
||||
unsigned int c1 = 0; //count consecutives 1s
|
||||
|
||||
printWebString += F("Interpreted RAW Code: ");
|
||||
//Loop throught every char in RAW string
|
||||
for(int i = 0; i < IrRaw.length(); i++)
|
||||
{
|
||||
//Get the decimal value from base32 table
|
||||
//See: https://en.wikipedia.org/wiki/Base32#base32hex
|
||||
char c = ((IrRaw[i] | ('A' ^ 'a')) - '0') % 39;
|
||||
|
||||
//Loop through 5 LSB (bits 16, 8, 4, 2, 1)
|
||||
for (unsigned int shft = 1; shft < 6; shft++)
|
||||
{
|
||||
//if bit is 1 (5th position - 00010000 = 16)
|
||||
if ((c & 16) != 0) {
|
||||
//add 1 to counter c1
|
||||
c1++;
|
||||
//if we already have any 0s in counting (the previous
|
||||
//bit was 0)
|
||||
if (c0 > 0) {
|
||||
//add the total ms into the buffer (number of 0s multiplied
|
||||
//by defined blank length ms)
|
||||
buf[idx++] = c0 * IrBLen;
|
||||
//print the number of 0s just for debuging/info purpouses
|
||||
for (uint t = 0; t < c0; t++)
|
||||
printWebString += F("0");
|
||||
}
|
||||
//So, as we recieve a "1", and processed the counted 0s
|
||||
//sending them as a ms timing into the buffer, we clear
|
||||
//the 0s counter
|
||||
c0 = 0;
|
||||
} else {
|
||||
//So, bit is 0
|
||||
|
||||
//On first call, ignore 0s (supress left-most 0s)
|
||||
if (c0+c1 != 0) {
|
||||
//add 1 to counter c0
|
||||
c0++;
|
||||
//if we already have any 1s in counting (the previous
|
||||
//bit was 1)
|
||||
if (c1 > 0) {
|
||||
//add the total ms into the buffer (number of 1s
|
||||
//multiplied by defined pulse length ms)
|
||||
buf[idx++] = c1 * IrPLen;
|
||||
//print the number of 1s just for debuging/info purpouses
|
||||
for (uint t = 0; t < c1; t++)
|
||||
printWebString += F("1");
|
||||
}
|
||||
//So, as we recieve a "0", and processed the counted 1s
|
||||
//sending them as a ms timing into the buffer, we clear
|
||||
//the 1s counter
|
||||
c1 = 0;
|
||||
}
|
||||
}
|
||||
//shift to left the "c" variable to process the next bit that is
|
||||
//in 5th position (00010000 = 16)
|
||||
c <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//Finally, we need to process the last counted bit that we were
|
||||
//processing
|
||||
|
||||
//If we have pendings 0s
|
||||
if (c0 > 0) {
|
||||
buf[idx] = c0 * IrBLen;
|
||||
for (uint t = 0; t < c0; t++)
|
||||
printWebString += F("0");
|
||||
}
|
||||
//If we have pendings 1s
|
||||
if (c1 > 0) {
|
||||
buf[idx] = c1 * IrPLen;
|
||||
for (uint t = 0; t < c1; t++)
|
||||
|
||||
@@ -39,7 +39,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_037;
|
||||
Device[deviceCount].Type = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_DUMMY;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE; // This means it has a single pin
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
|
||||
+33
-28
@@ -2,6 +2,8 @@
|
||||
//#################################### Plugin 038: NeoPixel Basic #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
// 15-June-2017: Fixed broken plugin; tested with several neopixels (single LED, 8 LED bars and 300 leds strips.
|
||||
|
||||
// List of commands:
|
||||
// (1) NeoPixel,<led nr>,<red 0-255>,<green 0-255>,<blue 0-255>
|
||||
// (2) NeoPixelAll,<red 0-255>,<green 0-255>,<blue 0-255>
|
||||
@@ -20,6 +22,9 @@ Adafruit_NeoPixel *Plugin_038_pixels;
|
||||
#define PLUGIN_ID_038 38
|
||||
#define PLUGIN_NAME_038 "NeoPixel - Basic"
|
||||
#define PLUGIN_VALUENAME1_038 ""
|
||||
|
||||
int MaxPixels = 0;
|
||||
|
||||
boolean Plugin_038(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
@@ -50,10 +55,8 @@ boolean Plugin_038(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormNumericBox(string, F("Led Count"), F("plugin_038_leds"), Settings.TaskDevicePluginConfig[event->TaskIndex][0],1 ,999);
|
||||
|
||||
addFormNumericBox(string, F("Led Count"), F("plugin_038_leds"), Settings.TaskDevicePluginConfig[event->TaskIndex][0],1,999);
|
||||
addFormPinSelect(string, F("GPIO"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -61,6 +64,7 @@ boolean Plugin_038(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_038_leds"));
|
||||
MaxPixels = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -72,6 +76,7 @@ boolean Plugin_038(byte function, struct EventStruct *event, String& string)
|
||||
Plugin_038_pixels = new Adafruit_NeoPixel(Settings.TaskDevicePluginConfig[event->TaskIndex][0], Settings.TaskDevicePin1[event->TaskIndex], NEO_GRB + NEO_KHZ800);
|
||||
Plugin_038_pixels->begin(); // This initializes the NeoPixel library.
|
||||
}
|
||||
MaxPixels = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -87,43 +92,44 @@ boolean Plugin_038(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
if (tmpString.equalsIgnoreCase(F("NeoPixel")))
|
||||
{
|
||||
char Line[80];
|
||||
char TmpStr1[80];
|
||||
TmpStr1[0] = 0;
|
||||
string.toCharArray(Line, 80);
|
||||
int Par4 = 0;
|
||||
if (GetArgv(Line, TmpStr1, 5)) Par4 = str2int(TmpStr1);
|
||||
Plugin_038_pixels->setPixelColor(event->Par1 - 1, Plugin_038_pixels->Color(event->Par2, event->Par3, Par4));
|
||||
// char Line[80];
|
||||
// char TmpStr1[80];
|
||||
// TmpStr1[0] = 0;
|
||||
// string.toCharArray(Line, 80);
|
||||
// int Par4 = 0;
|
||||
// if (GetArgv(Line, TmpStr1, 5)) Par4 = str2int(TmpStr1);
|
||||
Plugin_038_pixels->setPixelColor(event->Par1 - 1, Plugin_038_pixels->Color(event->Par2, event->Par3, event->Par4));
|
||||
Plugin_038_pixels->show(); // This sends the updated pixel color to the hardware.
|
||||
success = true;
|
||||
}
|
||||
|
||||
|
||||
if (tmpString.equalsIgnoreCase(F("NeoPixelAll")))
|
||||
{
|
||||
char Line[80];
|
||||
char TmpStr1[80];
|
||||
TmpStr1[0] = 0;
|
||||
string.toCharArray(Line, 80);
|
||||
for (int i = 0; i < (Settings.TaskDevicePluginConfig[event->TaskIndex][0]); i++){
|
||||
// char Line[80];
|
||||
// char TmpStr1[80];
|
||||
// TmpStr1[0] = 0;
|
||||
// string.toCharArray(Line, 80);
|
||||
for (int i = 0; i < MaxPixels; i++)
|
||||
{
|
||||
Plugin_038_pixels->setPixelColor(i, Plugin_038_pixels->Color(event->Par1, event->Par2, event->Par3));
|
||||
}
|
||||
Plugin_038_pixels->show();
|
||||
success = true;
|
||||
success = true;
|
||||
}
|
||||
|
||||
|
||||
if (tmpString.equalsIgnoreCase(F("NeoPixelLine")))
|
||||
{
|
||||
char Line[80];
|
||||
char TmpStr1[80];
|
||||
TmpStr1[0] = 0;
|
||||
string.toCharArray(Line, 80);
|
||||
int Par4 = 0;
|
||||
int Par5 = 0;
|
||||
if (GetArgv(Line, TmpStr1, 5)) Par4 = str2int(TmpStr1);
|
||||
if (GetArgv(Line, TmpStr1, 6)) Par5 = str2int(TmpStr1);
|
||||
// char Line[80];
|
||||
// char TmpStr1[80];
|
||||
// TmpStr1[0] = 0;
|
||||
// string.toCharArray(Line, 80);
|
||||
// int Par4 = 0;
|
||||
// int Par5 = 0;
|
||||
// if (GetArgv(Line, TmpStr1, 5)) Par4 = str2int(TmpStr1);
|
||||
// if (GetArgv(Line, TmpStr1, 6)) Par5 = str2int(TmpStr1);
|
||||
for (int i = event->Par1 - 1; i < event->Par2; i++)
|
||||
{
|
||||
Plugin_038_pixels->setPixelColor(i, Plugin_038_pixels->Color(event->Par3, Par4, Par5));
|
||||
Plugin_038_pixels->setPixelColor(i, Plugin_038_pixels->Color(event->Par3, event->Par4, event->Par5));
|
||||
}
|
||||
Plugin_038_pixels->show();
|
||||
success = true;
|
||||
@@ -135,4 +141,3 @@ boolean Plugin_038(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
+63
-21
@@ -13,13 +13,16 @@
|
||||
|
||||
#define PLUGIN_049
|
||||
#define PLUGIN_ID_049 49
|
||||
#define PLUGIN_NAME_049 "NDIR CO2 Sensor MH-Z19 [TESTING]"
|
||||
#define PLUGIN_NAME_049 "Gases - CO2 MH-Z19 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_049 "PPM"
|
||||
#define PLUGIN_VALUENAME2_049 "Temperature" // Temperature in C
|
||||
#define PLUGIN_VALUENAME3_049 "U" // Undocumented, minimum measurement per time period?
|
||||
#define PLUGIN_READ_TIMEOUT 3000
|
||||
|
||||
boolean Plugin_049_init = false;
|
||||
// Default of the sensor is to run ABC
|
||||
boolean Plugin_049_ABC_Disable = false;
|
||||
boolean Plugin_049_ABC_MustApply = false;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial *Plugin_049_SoftSerial;
|
||||
@@ -36,6 +39,12 @@ byte mhzCmdMeasurementRange2000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x07,0xD0,0x
|
||||
byte mhzCmdMeasurementRange3000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x0B,0xB8,0xA3};
|
||||
byte mhzCmdMeasurementRange5000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x13,0x88,0xCB};
|
||||
|
||||
enum
|
||||
{
|
||||
ABC_enabled = 0x01,
|
||||
ABC_disabled = 0x02
|
||||
};
|
||||
|
||||
boolean Plugin_049(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
bool success = false;
|
||||
@@ -73,8 +82,37 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[2] = { F("Normal"), F("ABC disabled") };
|
||||
int optionValues[2] = { ABC_enabled, ABC_disabled };
|
||||
addFormSelector(string, F("Auto Base Calibration"), F("plugin_049_abcdisable"), 2, options, optionValues, choice);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
const int formValue = getFormItemInt(F("plugin_049_abcdisable"));
|
||||
boolean new_ABC_disable = (formValue == ABC_disabled);
|
||||
if (Plugin_049_ABC_Disable != new_ABC_disable) {
|
||||
// Setting changed in the webform.
|
||||
Plugin_049_ABC_MustApply = true;
|
||||
Plugin_049_ABC_Disable = new_ABC_disable;
|
||||
}
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = formValue;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Plugin_049_ABC_Disable = Settings.TaskDevicePluginConfig[event->TaskIndex][0] == ABC_disabled;
|
||||
if (Plugin_049_ABC_Disable) {
|
||||
// No guarantee the correct state is active on the sensor after reboot.
|
||||
Plugin_049_ABC_MustApply = true;
|
||||
}
|
||||
Plugin_049_SoftSerial = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
|
||||
Plugin_049_SoftSerial->begin(9600);
|
||||
addLog(LOG_LEVEL_INFO, F("MHZ19: Init OK "));
|
||||
@@ -245,6 +283,12 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
|
||||
if (u == 15000) {
|
||||
|
||||
log += F("Bootup detected! ");
|
||||
if (Plugin_049_ABC_Disable) {
|
||||
// After bootup of the sensor the ABC will be enabled.
|
||||
// Thus only actively disable after bootup.
|
||||
Plugin_049_ABC_MustApply = true;
|
||||
log += F("Will disable ABC when bootup complete. ");
|
||||
}
|
||||
success = false;
|
||||
|
||||
// If s = 0x40 the reading is stable; anything else should be ignored
|
||||
@@ -256,11 +300,22 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
|
||||
// Finally, stable readings are used for variables
|
||||
} else {
|
||||
|
||||
success = true;
|
||||
|
||||
UserVar[event->BaseVarIndex] = (float)ppm;
|
||||
UserVar[event->BaseVarIndex + 1] = (float)temp;
|
||||
UserVar[event->BaseVarIndex + 2] = (float)u;
|
||||
if (Plugin_049_ABC_MustApply) {
|
||||
// Send ABC enable/disable command based on the desired state.
|
||||
if (Plugin_049_ABC_Disable) {
|
||||
Plugin_049_SoftSerial->write(mhzCmdABCDisable, 9);
|
||||
addLog(LOG_LEVEL_INFO, F("MHZ19: Sent sensor ABC Disable!"));
|
||||
} else {
|
||||
Plugin_049_SoftSerial->write(mhzCmdABCEnable, 9);
|
||||
addLog(LOG_LEVEL_INFO, F("MHZ19: Sent sensor ABC Enable!"));
|
||||
}
|
||||
Plugin_049_ABC_MustApply = false;
|
||||
}
|
||||
success = true;
|
||||
|
||||
}
|
||||
|
||||
// Log values in all cases
|
||||
@@ -286,24 +341,11 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
|
||||
// log verbosely anything else that the sensor reports
|
||||
} else {
|
||||
|
||||
String log = F("MHZ19: Unknown response: ");
|
||||
log += String(mhzResp[0], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[1], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[2], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[3], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[4], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[5], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[6], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[7], HEX);
|
||||
log += F(" ");
|
||||
log += String(mhzResp[8], HEX);
|
||||
String log = F("MHZ19: Unknown response:");
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
log += F(" ");
|
||||
log += String(mhzResp[i], HEX);
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = false;
|
||||
break;
|
||||
|
||||
+121
-21
@@ -1,11 +1,11 @@
|
||||
//#######################################################################################################
|
||||
//############################# Plugin 052: SenseAir CO2 Sensors ########################################
|
||||
//############################# Plugin 052: Senseair CO2 Sensors ########################################
|
||||
//#######################################################################################################
|
||||
/*
|
||||
Plugin originally written by: Daniel Tedenljung info__AT__tedenljungconsulting.com
|
||||
Rewritten by: Mikael Trieb mikael__AT__triebconsulting.se
|
||||
|
||||
This plugin reads availble values of SenseAir Co2 Sensors.
|
||||
This plugin reads availble values of Senseair Co2 Sensors.
|
||||
Datasheet can be found here:
|
||||
S8: http://www.senseair.com/products/oem-modules/senseair-s8/
|
||||
K30: http://www.senseair.com/products/oem-modules/k30/
|
||||
@@ -16,11 +16,10 @@
|
||||
GPIO Setting 2 -> TX
|
||||
Use 1kOhm in serie on datapins!
|
||||
*/
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_052
|
||||
#define PLUGIN_ID_052 52
|
||||
#define PLUGIN_NAME_052 "SenseAir"
|
||||
#define PLUGIN_NAME_052 "Gases - CO2 Senseair"
|
||||
#define PLUGIN_VALUENAME1_052 ""
|
||||
|
||||
boolean Plugin_052_init = false;
|
||||
@@ -63,11 +62,31 @@ boolean Plugin_052(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
String tmpString = string;
|
||||
|
||||
String cmd = parseString(tmpString, 1);
|
||||
String param1 = parseString(tmpString, 2);
|
||||
|
||||
|
||||
if (cmd.equalsIgnoreCase(F("senseair_setrelay")))
|
||||
{
|
||||
if (param1.toInt() == 0 || param1.toInt() == 1 || param1.toInt() == -1) {
|
||||
Plugin_052_setRelayStatus(param1.toInt());
|
||||
addLog(LOG_LEVEL_INFO, String(F("Senseair command: relay=")) + param1);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[4] = { F("Status"), F("Carbon Dioxide"), F("Temperature"), F("Humidity") };
|
||||
addFormSelector(string, F("Sensor"), F("plugin_052"), 4, options, NULL, choice);
|
||||
String options[6] = { F("Error Status"), F("Carbon Dioxide"), F("Temperature"), F("Humidity"), F("Relay Status"), F("Temperature Adjustment") };
|
||||
addFormSelector(string, F("Sensor"), F("plugin_052"), 6, options, NULL, choice);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -96,22 +115,31 @@ boolean Plugin_052(byte function, struct EventStruct *event, String& string)
|
||||
if (Plugin_052_init)
|
||||
{
|
||||
|
||||
String log = F("SenseAir ");
|
||||
String log = F("Senseair: ");
|
||||
switch(Settings.TaskDevicePluginConfig[event->TaskIndex][0])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int sensor_status = Plugin_052_readStatus();
|
||||
UserVar[event->BaseVarIndex] = sensor_status;
|
||||
log += F("status: ");
|
||||
log += sensor_status;
|
||||
int errorWord = Plugin_052_readErrorStatus();
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
if (bitRead(errorWord,i)) {
|
||||
UserVar[event->BaseVarIndex] = i;
|
||||
log += F("error code = ");
|
||||
log += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UserVar[event->BaseVarIndex] = -1;
|
||||
log += F("error code = ");
|
||||
log += -1;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
int co2 = Plugin_052_readCo2();
|
||||
UserVar[event->BaseVarIndex] = co2;
|
||||
log += F("co2: ");
|
||||
log += F("co2 = ");
|
||||
log += co2;
|
||||
break;
|
||||
}
|
||||
@@ -119,7 +147,7 @@ boolean Plugin_052(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
float temperature = Plugin_052_readTemperature();
|
||||
UserVar[event->BaseVarIndex] = (float)temperature;
|
||||
log += F("temperature: ");
|
||||
log += F("temperature = ");
|
||||
log += (float)temperature;
|
||||
break;
|
||||
}
|
||||
@@ -127,10 +155,26 @@ boolean Plugin_052(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
float relativeHumidity = Plugin_052_readRelativeHumidity();
|
||||
UserVar[event->BaseVarIndex] = (float)relativeHumidity;
|
||||
log += F("humidity: ");
|
||||
log += F("humidity = ");
|
||||
log += (float)relativeHumidity;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
int relayStatus = Plugin_052_readRelayStatus();
|
||||
UserVar[event->BaseVarIndex] = relayStatus;
|
||||
log += F("relay status = ");
|
||||
log += relayStatus;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
int temperatureAdjustment = Plugin_052_readTemperatureAdjustment();
|
||||
UserVar[event->BaseVarIndex] = temperatureAdjustment;
|
||||
log += F("temperature adjustment = ");
|
||||
log += temperatureAdjustment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
@@ -185,13 +229,19 @@ int Plugin_052_sendCommand(byte command[])
|
||||
return value;
|
||||
}
|
||||
|
||||
int Plugin_052_readStatus(void)
|
||||
int Plugin_052_readErrorStatus(void)
|
||||
{
|
||||
int sensor_status = -1;
|
||||
int errorBits = 0;
|
||||
int error_Status = -1;
|
||||
byte frame[8] = {0};
|
||||
Plugin_052_buildFrame(0xFE, 0x04, 0x00, 1, frame);
|
||||
sensor_status = Plugin_052_sendCommand(frame);
|
||||
return sensor_status;
|
||||
errorBits = Plugin_052_sendCommand(frame);
|
||||
for (size_t i = 0; i < 15; i++) {
|
||||
if (getBitOfInt(errorBits, i) == 1) {
|
||||
error_Status = i;
|
||||
}
|
||||
}
|
||||
return error_Status;
|
||||
}
|
||||
|
||||
int Plugin_052_readCo2(void)
|
||||
@@ -210,7 +260,7 @@ float Plugin_052_readTemperature(void)
|
||||
byte frame[8] = {0};
|
||||
Plugin_052_buildFrame(0xFE, 0x04, 0x04, 1, frame);
|
||||
temperatureX100 = Plugin_052_sendCommand(frame);
|
||||
temperature = temperatureX100/100;
|
||||
temperature = (float)temperatureX100/100;
|
||||
return temperature;
|
||||
}
|
||||
|
||||
@@ -221,10 +271,47 @@ float Plugin_052_readRelativeHumidity(void)
|
||||
byte frame[8] = {0};
|
||||
Plugin_052_buildFrame(0xFE, 0x04, 0x05, 1, frame);
|
||||
rhX100 = Plugin_052_sendCommand(frame);
|
||||
rh = rhX100/100;
|
||||
rh = (float)rhX100/100;
|
||||
return rh;
|
||||
}
|
||||
|
||||
int Plugin_052_readRelayStatus(void)
|
||||
{
|
||||
int status = 0;
|
||||
bool result;
|
||||
byte frame[8] = {0};
|
||||
|
||||
Plugin_052_buildFrame(0xFE, 0x04, 0x1C, 1, frame);
|
||||
status = Plugin_052_sendCommand(frame);
|
||||
result = status >> 8 & 0x1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Plugin_052_readTemperatureAdjustment(void)
|
||||
{
|
||||
int value = 0;
|
||||
byte frame[8] = {0};
|
||||
|
||||
Plugin_052_buildFrame(0xFE, 0x04, 0x0A, 1, frame);
|
||||
value = Plugin_052_sendCommand(frame);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void Plugin_052_setRelayStatus(int status) {
|
||||
int response;
|
||||
byte frame[8] = {0};
|
||||
if (status == 0) {
|
||||
Plugin_052_buildFrame(0xFE, 0x06, 0x18, 0x0000, frame);
|
||||
} else if (status == 1){
|
||||
Plugin_052_buildFrame(0xFE, 0x06, 0x18, 0x3FFF, frame);
|
||||
} else {
|
||||
Plugin_052_buildFrame(0xFE, 0x06, 0x18, 0x7FFF, frame);
|
||||
}
|
||||
response = Plugin_052_sendCommand(frame);
|
||||
}
|
||||
|
||||
// Compute the MODBUS RTU CRC
|
||||
unsigned int Plugin_052_ModRTU_CRC(byte buf[], int len, byte checkSum[2])
|
||||
{
|
||||
@@ -247,4 +334,17 @@ unsigned int Plugin_052_ModRTU_CRC(byte buf[], int len, byte checkSum[2])
|
||||
checkSum[0] = (byte)(crc & 0xFF);
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int getBitOfInt(int reg, int pos)
|
||||
{
|
||||
// Create a mask
|
||||
int mask = 0x01 << pos;
|
||||
|
||||
// Mask the status register
|
||||
int masked_register = mask & reg;
|
||||
|
||||
// Shift the result of masked register back to position 0
|
||||
int result = masked_register >> pos;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+124
-54
@@ -4,32 +4,47 @@
|
||||
//
|
||||
// http://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf?sfvrsn=2
|
||||
//
|
||||
// The PMSx005 are particle sensors. Particles are measured by blowing air though the enclosue and,
|
||||
// The PMSx003 are particle sensors. Particles are measured by blowing air though the enclosue and,
|
||||
// togther with a laser, count the amount of particles. These sensors have an integrated microcontroller
|
||||
// that counts particles and transmits measurement data over the serial connection.
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#define PLUGIN_053
|
||||
#define PLUGIN_ID_053 53
|
||||
#define PLUGIN_NAME_053 "Particle Sensor - PMSx003"
|
||||
#define PLUGIN_NAME_053 "Dust Sensor - PMSx003"
|
||||
#define PLUGIN_VALUENAME1_053 "pm1.0"
|
||||
#define PLUGIN_VALUENAME2_053 "pm2.5"
|
||||
#define PLUGIN_VALUENAME3_053 "pm10"
|
||||
#define PMSx003_SIG1 0X42
|
||||
#define PMSx003_SIG2 0X4d
|
||||
#define PMSx003_SIZE 32
|
||||
|
||||
SoftwareSerial *swSerial = NULL;
|
||||
boolean Plugin_053_init = false;
|
||||
byte Plugin_PMSx003_UART = 0;
|
||||
byte timer = 0;
|
||||
boolean values_received = false;
|
||||
|
||||
// Read 2 bytes from serial and make an uint16 of it. Additionally calculate
|
||||
// checksum for PMSx003. Assumption is that there is data available, otherwise
|
||||
// this function is blocking.
|
||||
void SerialRead16(uint16_t* value, uint16_t* checksum)
|
||||
{
|
||||
uint8_t data_high, data_low;
|
||||
|
||||
while(Serial.available() == 0) {};
|
||||
data_high = Serial.read();
|
||||
while(Serial.available() == 0) {};
|
||||
data_low = Serial.read();
|
||||
// If swSerial is initialized, we are using soft serial
|
||||
if (swSerial != NULL)
|
||||
{
|
||||
data_high = swSerial->read();
|
||||
data_low = swSerial->read();
|
||||
}
|
||||
else
|
||||
{
|
||||
data_high = Serial.read();
|
||||
data_low = Serial.read();
|
||||
}
|
||||
|
||||
*value = data_low;
|
||||
*value |= (data_high << 8);
|
||||
|
||||
@@ -38,8 +53,9 @@ void SerialRead16(uint16_t* value, uint16_t* checksum)
|
||||
*checksum += data_high;
|
||||
*checksum += data_low;
|
||||
}
|
||||
// Low-level logging to see data from sensor
|
||||
|
||||
#if 0
|
||||
// Low-level logging to see data from sensor
|
||||
String log = F("PMSx003 : byte high=0x");
|
||||
log += String(data_high,HEX);
|
||||
log += F(" byte low=0x");
|
||||
@@ -50,8 +66,42 @@ void SerialRead16(uint16_t* value, uint16_t* checksum)
|
||||
#endif
|
||||
}
|
||||
|
||||
boolean PacketAvailable(void)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
if (swSerial != NULL) // Software serial
|
||||
{
|
||||
// When there is enough data in the buffer, search through the buffer to
|
||||
// find header (buffer may be out of sync)
|
||||
while (swSerial->available() >= PMSx003_SIZE)
|
||||
{
|
||||
if (swSerial->read() == PMSx003_SIG1 && swSerial->read() == PMSx003_SIG2)
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Hardware serial
|
||||
{
|
||||
// When there is enough data in the buffer, search through the buffer to
|
||||
// find header (buffer may be out of sync)
|
||||
while (Serial.available() >= PMSx003_SIZE)
|
||||
{
|
||||
if (Serial.read() == PMSx003_SIG1 && Serial.read() == PMSx003_SIG2)
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
String log;
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
@@ -59,7 +109,7 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_053;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_TRIPLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_TRIPLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
@@ -89,39 +139,63 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO ← TX");
|
||||
event->String2 = F("GPIO → RX");
|
||||
event->String3 = F("GPIO → Reset");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Serial.begin(9600);
|
||||
// Toggle 'reset' to assure we start reading header
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT);
|
||||
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW);
|
||||
delay(250);
|
||||
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH);
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
|
||||
int rxPin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
int txPin = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
int resetPin = Settings.TaskDevicePin3[event->TaskIndex];
|
||||
|
||||
// Put device in suspend by driving 'set'low
|
||||
pinMode(Settings.TaskDevicePin2[event->TaskIndex], OUTPUT);
|
||||
digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH);
|
||||
log = F("PMSx003 : config ");
|
||||
log += rxPin;
|
||||
log += txPin;
|
||||
log += resetPin;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
// Hardware serial is RX on 3 and TX on 1
|
||||
if (rxPin == 3 && txPin == 1)
|
||||
{
|
||||
log = F("PMSx003 : using hardware serial");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
Serial.begin(9600);
|
||||
Serial.flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
log = F("PMSx003: using software serial");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
swSerial = new SoftwareSerial(rxPin, txPin);
|
||||
swSerial->begin(9600);
|
||||
swSerial->flush();
|
||||
}
|
||||
|
||||
if (resetPin >= 0) // Reset if pin is configured
|
||||
{
|
||||
// Toggle 'reset' to assure we start reading header
|
||||
log = F("PMSx003: resetting module");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
pinMode(resetPin, OUTPUT);
|
||||
digitalWrite(resetPin, LOW);
|
||||
delay(250);
|
||||
digitalWrite(resetPin, HIGH);
|
||||
pinMode(resetPin, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
Plugin_053_init = true;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_ONCE_A_SECOND:
|
||||
{
|
||||
// Do measurements only every 30 seconds
|
||||
#if 0
|
||||
if ((timer++) % 30 == 0)
|
||||
if (digitalRead(Settings.TaskDevicePin2[event->TaskIndex]))
|
||||
digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW);
|
||||
else
|
||||
digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH);
|
||||
#endif
|
||||
success = true;
|
||||
}
|
||||
|
||||
case PLUGIN_SERIAL_IN:
|
||||
// The update rate from the module is 200ms .. multiple seconds. Practise
|
||||
// shows that we need to read the buffer many times per seconds to stay in
|
||||
// sync.
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (Plugin_053_init)
|
||||
{
|
||||
@@ -130,25 +204,24 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
uint16_t data[13];
|
||||
byte data_low, data_high;
|
||||
int i = 0;
|
||||
String log;
|
||||
|
||||
// Check for 2-byte header. A total of 32 bytes is to be received.
|
||||
if (Serial.read() == 0x42 && Serial.read() == 0x4d)
|
||||
// Check if a packet is available in the UART FIFO.
|
||||
if (PacketAvailable())
|
||||
{
|
||||
checksum += 0x42 + 0x4d;
|
||||
log = F("PMSx003 : Packet available");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
checksum += PMSx003_SIG1 + PMSx003_SIG2;
|
||||
SerialRead16(&framelength, &checksum);
|
||||
if (framelength != 28)
|
||||
if (framelength != (PMSx003_SIZE - 4))
|
||||
{
|
||||
log = F("PMSx003 : invalid framelength - ");
|
||||
log+=framelength;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log += framelength;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 13; i++)
|
||||
{
|
||||
SerialRead16(&data[i], &checksum);
|
||||
}
|
||||
|
||||
log = F("PMSx003 : pm1.0=");
|
||||
log += data[0];
|
||||
@@ -162,7 +235,7 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
log += data[4];
|
||||
log += F(", pm10a=");
|
||||
log += data[5];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
log = F("PMSx003 : count/0.1L : 0.3um=");
|
||||
log += data[6];
|
||||
@@ -176,31 +249,28 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
log += data[10];
|
||||
log += F(", 10um=");
|
||||
log += data[11];
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
// Compare checksums
|
||||
SerialRead16(&checksum2, NULL);
|
||||
if (checksum == checksum2)
|
||||
{
|
||||
/* Data is checked and good, fill in output */
|
||||
// Data is checked and good, fill in output
|
||||
UserVar[event->BaseVarIndex] = data[3];
|
||||
UserVar[event->BaseVarIndex + 1] = data[4];
|
||||
UserVar[event->BaseVarIndex + 2] = data[5];
|
||||
values_received = true;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
// Prevent sending data to controller when nothing received yet
|
||||
if (values_received)
|
||||
success = true;
|
||||
break;
|
||||
// When new data is available, return true
|
||||
success = values_received;
|
||||
values_received = false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
//#######################################################################################################
|
||||
//######################################## Plugin 054: DMX512 TX ########################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to control DMX-512 Devices (DMX 512/1990; DIN 56930-2) like Dimmer-Packs, LED-Bars, Moving-Heads, Event-Lighting
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// List of commands:
|
||||
// (1) DMX,<param>
|
||||
// (2) DMX,<param>,<param>,<param>, ...
|
||||
|
||||
// List of DMX params:
|
||||
// (a) <value>
|
||||
// DMX-value (0...255) to write to the next channel address (1...512) starting with 1
|
||||
// (b) <channel>=<value>
|
||||
// DMX-value (0...255) to write to the given channel address (1...512).
|
||||
// (c) <channel>=<value>,<value>,<value>,...
|
||||
// List of DMX-values (0...255) to write beginning with the given channel address (1...512).
|
||||
// (d) "OFF"
|
||||
// Set DMX-values of all channels to 0.
|
||||
// (e) "ON"
|
||||
// Set DMX-values of all channels to 255.
|
||||
// (f) "LOG"
|
||||
// Print DMX-values of all channels to log output.
|
||||
|
||||
// Examples:
|
||||
// DMX,123" Set channel 1 to value 123
|
||||
// DMX,123,22,33,44" Set channel 1 to value 123, channel 2 to 22, channel 3 to33, channel 4 to 44
|
||||
// DMX,5=123" Set channel 5 to value 123
|
||||
// DMX,5=123,22,33,44" Set channel 5 to value 123, channel 6 to 22, channel 7 to33, channel 8 to 44
|
||||
// DMX,5=123,8=44" Set channel 5 to value 123, channel 8 to 44
|
||||
// DMX,OFF" Pitch Black
|
||||
|
||||
// Transeiver:
|
||||
// SN75176 or MAX485 or LT1785 or ...
|
||||
// Pin 5: GND
|
||||
// Pin 2, 3, 5: +5V
|
||||
// Pin 4: to ESP D4
|
||||
// Pin 6: DMX+ (hot)
|
||||
// Pin 7: DMX- (cold)
|
||||
|
||||
// XLR Plug:
|
||||
// Pin 1: GND, Shield
|
||||
// Pin 2: DMX- (cold)
|
||||
// Pin 3: DMX+ (hot)
|
||||
|
||||
// Note: The ESP serial FIFO has size of 128 byte. Therefore it is rcommented to use DMX buffer sizes below 128
|
||||
|
||||
|
||||
//#include <*.h> //no lib needed
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_054
|
||||
#define PLUGIN_ID_054 54
|
||||
#define PLUGIN_NAME_054 "DMX512 TX [TESTING]"
|
||||
|
||||
byte* Plugin_054_DMXBuffer = 0;
|
||||
int16_t Plugin_054_DMXSize = 32;
|
||||
|
||||
static inline void PLUGIN_054_Limit(int16_t& value, int16_t min, int16_t max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
if (value > max)
|
||||
value = max;
|
||||
}
|
||||
|
||||
|
||||
boolean Plugin_054(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_054;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].TimerOptional = false;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_054);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
Settings.TaskDevicePin1[event->TaskIndex] = 2;
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = Plugin_054_DMXSize;
|
||||
addFormNote(string, F("Only GPIO-2 (D4) can be used as TX1!"));
|
||||
addFormNumericBox(string, F("Channels"), F("channels"), Plugin_054_DMXSize, 1, 512);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
Settings.TaskDevicePin1[event->TaskIndex] = 2;
|
||||
if (Settings.Pin_status_led == 2) //Status LED assigned to TX1?
|
||||
Settings.Pin_status_led = -1;
|
||||
Plugin_054_DMXSize = getFormItemInt(F("channels"));
|
||||
PLUGIN_054_Limit (Plugin_054_DMXSize, 1, 512);
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = Plugin_054_DMXSize;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Settings.TaskDevicePin1[event->TaskIndex] = 2; //TX1 fix to GPIO2 (D4) == onboard LED
|
||||
Plugin_054_DMXSize = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
|
||||
if (Plugin_054_DMXBuffer)
|
||||
delete [] Plugin_054_DMXBuffer;
|
||||
Plugin_054_DMXBuffer = new byte[Plugin_054_DMXSize];
|
||||
memset(Plugin_054_DMXBuffer, 0, Plugin_054_DMXSize);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
|
||||
if (command == F("dmx"))
|
||||
{
|
||||
String param;
|
||||
String paramKey;
|
||||
String paramVal;
|
||||
byte paramIdx = 2;
|
||||
int16_t channel = 1;
|
||||
int16_t value = 0;
|
||||
|
||||
string.replace(" ", " ");
|
||||
string.replace(" =", "=");
|
||||
string.replace("= ", "=");
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
if (param.length())
|
||||
{
|
||||
while (param.length())
|
||||
{
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, param);
|
||||
|
||||
if (param == F("log"))
|
||||
{
|
||||
String log = F("DMX : ");
|
||||
for (int16_t i = 0; i < Plugin_054_DMXSize; i++)
|
||||
{
|
||||
log += Plugin_054_DMXBuffer[i];
|
||||
log += F(", ");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
else if (param == F("test"))
|
||||
{
|
||||
for (int16_t i = 0; i < Plugin_054_DMXSize; i++)
|
||||
//Plugin_054_DMXBuffer[i] = i+1;
|
||||
Plugin_054_DMXBuffer[i] = rand()&255;
|
||||
success = true;
|
||||
}
|
||||
|
||||
else if (param == F("on"))
|
||||
{
|
||||
memset(Plugin_054_DMXBuffer, 255, Plugin_054_DMXSize);
|
||||
success = true;
|
||||
}
|
||||
|
||||
else if (param == F("off"))
|
||||
{
|
||||
memset(Plugin_054_DMXBuffer, 0, Plugin_054_DMXSize);
|
||||
success = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int16_t index = param.indexOf('=');
|
||||
if (index > 0) //syntax: "<channel>=<value>"
|
||||
{
|
||||
paramKey = param.substring(0, index);
|
||||
paramVal = param.substring(index+1);
|
||||
channel = paramKey.toInt();
|
||||
}
|
||||
else //syntax: "<value>"
|
||||
{
|
||||
paramVal = param;
|
||||
}
|
||||
|
||||
value = paramVal.toInt();
|
||||
PLUGIN_054_Limit (value, 0, 255);
|
||||
|
||||
if (channel > 0 && channel <= Plugin_054_DMXSize)
|
||||
Plugin_054_DMXBuffer[channel-1] = value;
|
||||
channel++;
|
||||
}
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//??? no params
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (Plugin_054_DMXBuffer)
|
||||
{
|
||||
int16_t sendPin = 2; //TX1 fix to GPIO2 (D4) == onboard LED
|
||||
|
||||
//empty serial from prev. transmit
|
||||
Serial1.flush();
|
||||
|
||||
//send break
|
||||
Serial1.end();
|
||||
pinMode(sendPin, OUTPUT);
|
||||
digitalWrite(sendPin, LOW);
|
||||
delayMicroseconds(120); //88µs ... inf
|
||||
digitalWrite(sendPin, HIGH);
|
||||
delayMicroseconds(12); //8µs ... 1s
|
||||
|
||||
//send DMX data
|
||||
Serial1.begin(250000, SERIAL_8N2);
|
||||
Serial1.write(0); //start byte
|
||||
Serial1.write(Plugin_054_DMXBuffer, Plugin_054_DMXSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif //PLUGIN_BUILD_TESTING
|
||||
@@ -0,0 +1,503 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 055: Chiming Mechanism ####################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy plugin to strike up to 4 pysical bells and gongs with chiming sequences.
|
||||
// You also can use an antique door bell as a single strikes (not ringing) notification.
|
||||
// Optional you can use it as hourly chiming clock
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// List of commands:
|
||||
// (1) CHIME,<tokens> Play token direct
|
||||
// (2) CHIMESAVE,<name>,<tokens> Save tokens with given name in FFS
|
||||
// (3) CHIMEPLAY,<name> Play saved tokens given name out of FFS
|
||||
|
||||
// List of tokens:
|
||||
// (a) '1'...'9', 'A'...'F' Bell number - 1=1st bell, 2=2nd bell, 4=3rd bell, 8=4th bell, numbers can be added to strike simultaniouly, F=all bells
|
||||
// (b) '!' Double strike prev. token
|
||||
// (c) '-' or ' ' Normal Pause
|
||||
// (d) '=' Long Pause (3 times normal)
|
||||
// (e) '.' Short Pause (1/3 of normal)
|
||||
// (f) '|' Shortest Pause
|
||||
// (g) '#' Comment - rest of the tokens will be ignored
|
||||
// Note: If no pause is specified, a normal pause will be inserted "111" -> "1-1-1"
|
||||
|
||||
// Usage as Hourly Chime Clock:
|
||||
// save twelve comma separated tokens with name "hours", enable checkbox "Hourly Chiming Clock Strike" in plugin web interface and enable NTP (advanced settings)
|
||||
//
|
||||
// examples:
|
||||
// Historical coded with 1 bell: "1,11,111,1111,11111,111111,1111111,11111111,111111111,1111111111,11111111111,111111111111"
|
||||
// Binary coded with 2 bells (2nd bell=1): "1112,1121,1122,1211,1212,1221,1222,2111,2112,2121,2122,2211"
|
||||
// Binary coded with 1 bell (short pause=1): "1_1_1_11,1_1_11_1,1_1_111,1_11_1_1,1_11_11,1_111_1,1_1111,11_1_1_1,11_1_11,11_11_1,11_111,111_1_1"
|
||||
// Binary coded with 1 bell (double strike=1):"1111!,111!1,111!1!,11!11,11!11!,11!1!1,11!1!1!,1!111,1!111!,1!11!1,1!11!1!,1!1!11"
|
||||
//
|
||||
// CHIMESAVE,hours,1111!,111!1,111!1!,11!11,11!11!,11!1!1,11!1!1!,1!111,1!111!,1!11!1,1!11!1!,1!1!11
|
||||
|
||||
// Usage as Alarm Clock:
|
||||
// save tokens with name "<HH><MM>" and enable NTP (advanced settings)
|
||||
//
|
||||
// examples:
|
||||
// CHIMESAVE,0815,1111! Dayly Alarm at 8:15am
|
||||
// CHIMESAVE,2015,11121 Dayly Alarm at 8:15pm
|
||||
// CHIMESAVE,2015 Delete Alarm at 8:15pm
|
||||
|
||||
// Electronics:
|
||||
// Use a power-FET or an ULN2003 to switch on the bells coil with 12 or 24 volts
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
//#include <*.h> - no external lib required
|
||||
|
||||
#define PLUGIN_055
|
||||
#define PLUGIN_ID_055 55
|
||||
#define PLUGIN_NAME_055 "Chiming Mechanism [TESTING]"
|
||||
|
||||
#define PLUGIN_055_FIFO_SIZE 64 // must be power of 2
|
||||
#define PLUGIN_055_FIFO_MASK (PLUGIN_055_FIFO_SIZE-1)
|
||||
|
||||
class CPlugin_055_Data
|
||||
{
|
||||
public:
|
||||
long millisStateEnd;
|
||||
long millisChimeTime;
|
||||
long millisPauseTime;
|
||||
|
||||
int pin[4];
|
||||
byte lowActive;
|
||||
byte chimeClock;
|
||||
|
||||
char FIFO[PLUGIN_055_FIFO_SIZE];
|
||||
byte FIFO_IndexR;
|
||||
byte FIFO_IndexW;
|
||||
|
||||
void Plugin_055_Data()
|
||||
{
|
||||
millisStateEnd = 0;
|
||||
millisChimeTime = 60;
|
||||
millisPauseTime = 400;
|
||||
|
||||
for (byte i=0; i<4; i++)
|
||||
pin[i] = -1;
|
||||
lowActive = false;
|
||||
chimeClock = true;
|
||||
|
||||
FIFO_IndexR = 0;
|
||||
FIFO_IndexW = 0;
|
||||
}
|
||||
};
|
||||
|
||||
static CPlugin_055_Data* Plugin_055_Data = NULL;
|
||||
|
||||
|
||||
boolean Plugin_055(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_055;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_TRIPLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = true;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].TimerOptional = false;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_055);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO → Driver#1");
|
||||
event->String2 = F("GPIO → Driver#2");
|
||||
event->String3 = F("GPIO → Driver#4");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
//default values
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] <= 0) //Plugin_055_millisChimeTime
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = 60;
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] <= 0) //Plugin_055_millisPauseTime
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = 400;
|
||||
|
||||
addFormPinSelect(string, F("GPIO → Driver#8"), F("TDP4"), (int)(Settings.TaskDevicePin[3][event->TaskIndex]));
|
||||
|
||||
|
||||
addFormSubHeader(string, F("Timing"));
|
||||
|
||||
addFormNumericBox(string, F("Chiming/Strike Time (ct)"), F("chimetime"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
addUnit(string, F("ms"));
|
||||
|
||||
addFormNumericBox(string, F("Normal Pause Time (t)"), F("pausetime"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
|
||||
addUnit(string, F("ms"));
|
||||
|
||||
addFormNote(string, F("'1=1'⇒3t, '1-1' or '11'⇒1t, '1.1'⇒⅓t, '1|1'⇒½ct"));
|
||||
|
||||
|
||||
addFormSubHeader(string, F("Chiming Clock"));
|
||||
|
||||
addFormCheckBox(string, F("Hourly Chiming Clock Strike"), F("chimeclock"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
|
||||
//string += F("<TR><TD><TD>");
|
||||
string += F(" ");
|
||||
addButton(string, F("'control?cmd=chimeplay,hours'"), F("Test 1…12"));
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] && !Settings.UseNTP)
|
||||
addFormNote(string, F("Enable and configure NTP!"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
Settings.TaskDevicePin[3][event->TaskIndex] = (int8_t)getFormItemInt(F("TDP4"));
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("chimetime"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("pausetime"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = isFormItemChecked(F("chimeclock"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (!Plugin_055_Data)
|
||||
Plugin_055_Data = new CPlugin_055_Data();
|
||||
|
||||
Plugin_055_Data->lowActive = Settings.TaskDevicePin1Inversed[event->TaskIndex];
|
||||
Plugin_055_Data->millisChimeTime = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
Plugin_055_Data->millisPauseTime = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
Plugin_055_Data->chimeClock = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
|
||||
String log = F("Chime: GPIO: ");
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
int pin = Settings.TaskDevicePin[i][event->TaskIndex];
|
||||
Plugin_055_Data->pin[i] = pin;
|
||||
if (pin >= 0)
|
||||
{
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin, Plugin_055_Data->lowActive);
|
||||
}
|
||||
log += pin;
|
||||
log += F(" ");
|
||||
}
|
||||
if (Plugin_055_Data->lowActive)
|
||||
log += F("!");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (!Plugin_055_Data)
|
||||
break;
|
||||
|
||||
String command = parseString(string, 1);
|
||||
|
||||
if (command == F("chime"))
|
||||
{
|
||||
int paramPos = getParamStartPos(string, 2);
|
||||
String param = string.substring(paramPos);
|
||||
Plugin_055_AddStringFIFO(param);
|
||||
success = true;
|
||||
}
|
||||
if (command == F("chimeplay"))
|
||||
{
|
||||
String name = parseString(string, 2);
|
||||
String param;
|
||||
Plugin_055_ReadChime(name, param);
|
||||
Plugin_055_AddStringFIFO(param);
|
||||
success = true;
|
||||
}
|
||||
if (command == F("chimesave"))
|
||||
{
|
||||
String name = parseString(string, 2);
|
||||
int paramPos = getParamStartPos(string, 3);
|
||||
String param = string.substring(paramPos);
|
||||
Plugin_055_WriteChime(name, param);
|
||||
Plugin_055_AddStringFIFO(F("1"));
|
||||
success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_CLOCK_IN:
|
||||
{
|
||||
if (!Plugin_055_Data)
|
||||
break;
|
||||
|
||||
String tokens = "";
|
||||
byte hours = hour();
|
||||
byte minutes = minute();
|
||||
|
||||
if (Plugin_055_Data->chimeClock)
|
||||
{
|
||||
char tmpString[8];
|
||||
|
||||
sprintf_P(tmpString, PSTR("%02d%02d"), hours, minutes);
|
||||
if (Plugin_055_ReadChime(tmpString, tokens))
|
||||
Plugin_055_AddStringFIFO(tokens);
|
||||
|
||||
if (minutes == 0)
|
||||
{
|
||||
if (Plugin_055_ReadChime("hours", tokens) == 0)
|
||||
tokens = F("1111!,111!1,111!1!,11!11,11!11!,11!1!1,11!1!1!,1!111,1!111!,1!11!1,1!11!1!,1!1!11"); //1..12
|
||||
|
||||
// hours 0..23 -> 1..12
|
||||
hours = hours % 12;
|
||||
if (hours == 0)
|
||||
hours = 12;
|
||||
|
||||
byte index = hours;
|
||||
|
||||
tokens = parseString(tokens, index);
|
||||
Plugin_055_AddStringFIFO(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case PLUGIN_FIFTY_PER_SECOND:
|
||||
//case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (!Plugin_055_Data)
|
||||
break;
|
||||
|
||||
long millisAct = millis();
|
||||
|
||||
if (Plugin_055_Data->millisStateEnd > 0) // just striking?
|
||||
{
|
||||
if (Plugin_055_Data->millisStateEnd <= millisAct) // end reached?
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
if (Plugin_055_Data->pin[i] >= 0)
|
||||
digitalWrite(Plugin_055_Data->pin[i], Plugin_055_Data->lowActive);
|
||||
}
|
||||
Plugin_055_Data->millisStateEnd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (Plugin_055_Data->millisStateEnd == 0) // just finished?
|
||||
{
|
||||
if (! Plugin_055_IsEmptyFIFO())
|
||||
{
|
||||
char c = Plugin_055_ReadFIFO();
|
||||
|
||||
String log = F("Chime: Process '");
|
||||
log += c;
|
||||
log += "'";
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
c -= 'A' - '0' - 10;
|
||||
//vvv
|
||||
|
||||
case '0': //strikes 1=1st bell, 2=2nd bell, 4=3rd bell, 8=4rd bell
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
byte mask = 1;
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
if (Plugin_055_Data->pin[i] >= 0)
|
||||
if (c & mask)
|
||||
digitalWrite(Plugin_055_Data->pin[i], !Plugin_055_Data->lowActive);
|
||||
mask <<= 1;
|
||||
}
|
||||
Plugin_055_Data->millisStateEnd = millisAct + Plugin_055_Data->millisChimeTime;
|
||||
break;
|
||||
}
|
||||
case '=': //long pause
|
||||
case ' ':
|
||||
case ',':
|
||||
Plugin_055_Data->millisStateEnd = millisAct + Plugin_055_Data->millisPauseTime*3;
|
||||
break;
|
||||
case '-': //single pause
|
||||
Plugin_055_Data->millisStateEnd = millisAct + Plugin_055_Data->millisPauseTime;
|
||||
break;
|
||||
case '.': //short pause
|
||||
Plugin_055_Data->millisStateEnd = millisAct + Plugin_055_Data->millisPauseTime/3;
|
||||
break;
|
||||
case '|': //shortest pause
|
||||
Plugin_055_Data->millisStateEnd = millisAct + Plugin_055_Data->millisChimeTime/2;
|
||||
break;
|
||||
case '#': //comment -> eat till FIFO is empty
|
||||
while (Plugin_055_ReadFIFO());
|
||||
break;
|
||||
default: //unknown char -> do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// FIFO functions
|
||||
|
||||
void Plugin_055_WriteFIFO(char c)
|
||||
{
|
||||
if (Plugin_055_Data->FIFO_IndexR == ((Plugin_055_Data->FIFO_IndexW+1) & PLUGIN_055_FIFO_MASK)) // FIFO full?
|
||||
return;
|
||||
|
||||
Plugin_055_Data->FIFO[Plugin_055_Data->FIFO_IndexW] = c;
|
||||
Plugin_055_Data->FIFO_IndexW++;
|
||||
Plugin_055_Data->FIFO_IndexW &= PLUGIN_055_FIFO_MASK;
|
||||
}
|
||||
|
||||
char Plugin_055_ReadFIFO()
|
||||
{
|
||||
if (Plugin_055_IsEmptyFIFO())
|
||||
return '\0';
|
||||
|
||||
char c = Plugin_055_Data->FIFO[Plugin_055_Data->FIFO_IndexR];
|
||||
Plugin_055_Data->FIFO_IndexR++;
|
||||
Plugin_055_Data->FIFO_IndexR &= PLUGIN_055_FIFO_MASK;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
char Plugin_055_PeekFIFO()
|
||||
{
|
||||
if (Plugin_055_IsEmptyFIFO())
|
||||
return '\0';
|
||||
|
||||
return Plugin_055_Data->FIFO[Plugin_055_Data->FIFO_IndexR];
|
||||
}
|
||||
|
||||
boolean Plugin_055_IsEmptyFIFO()
|
||||
{
|
||||
return (Plugin_055_Data->FIFO_IndexR == Plugin_055_Data->FIFO_IndexW);
|
||||
}
|
||||
|
||||
void Plugin_055_AddStringFIFO(const String& param)
|
||||
{
|
||||
if (param.length() == 0)
|
||||
return;
|
||||
|
||||
byte i = 0;
|
||||
char c = param[i];
|
||||
char c_last = '\0';
|
||||
|
||||
while (c != 0)
|
||||
{
|
||||
if (isDigit(c) && isDigit(c_last)) // "11" is shortcut for "1-1" -> add pause
|
||||
Plugin_055_WriteFIFO('-');
|
||||
if (c == '!') //double strike -> add shortest pause and repeat last strike
|
||||
{
|
||||
Plugin_055_WriteFIFO('|');
|
||||
c = c_last;
|
||||
}
|
||||
Plugin_055_WriteFIFO(c);
|
||||
c_last = c;
|
||||
|
||||
c = param[++i];
|
||||
}
|
||||
|
||||
Plugin_055_WriteFIFO('=');
|
||||
}
|
||||
|
||||
//File I/O functions
|
||||
|
||||
void Plugin_055_WriteChime(const String& name, const String& tokens)
|
||||
{
|
||||
String fileName = F("chime_");
|
||||
fileName += name;
|
||||
fileName += F(".txt");
|
||||
|
||||
String log = F("Chime: write ");
|
||||
log += fileName;
|
||||
log += F(" ");
|
||||
|
||||
fs::File f = SPIFFS.open(fileName, "w");
|
||||
if (f)
|
||||
{
|
||||
f.print(tokens);
|
||||
f.close();
|
||||
//flashCount();
|
||||
log += tokens;
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
byte Plugin_055_ReadChime(const String& name, String& tokens)
|
||||
{
|
||||
String fileName = F("chime_");
|
||||
fileName += name;
|
||||
fileName += F(".txt");
|
||||
|
||||
String log = F("Chime: read ");
|
||||
log += fileName;
|
||||
log += F(" ");
|
||||
|
||||
tokens = "";
|
||||
fs::File f = SPIFFS.open(fileName, "r+");
|
||||
if (f)
|
||||
{
|
||||
char c;
|
||||
while (f.available())
|
||||
{
|
||||
c = f.read();
|
||||
tokens += c;
|
||||
}
|
||||
f.close();
|
||||
|
||||
log += tokens;
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
return tokens.length();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,135 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 056: Dust Sensor SDS011 / SDS018 ##########################
|
||||
//#######################################################################################################
|
||||
/*
|
||||
Plugin is based upon SDS011 dust sensor PM2.5 and PM10 lib
|
||||
This plugin and lib was written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
This plugin reads the particle concentration from SDS011 Sensor
|
||||
DevicePin1 - RX on ESP, TX on SDS
|
||||
*/
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_056
|
||||
#define PLUGIN_ID_056 56
|
||||
#define PLUGIN_NAME_056 "Dust Sensor - SDS011/018/198 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_056 "PM2.5" // Dust <2.5µm in µg/m³ SDS198:<100µm in µg/m³
|
||||
#define PLUGIN_VALUENAME2_056 "PM10" // Dust <10µm in µg/m³
|
||||
|
||||
#include <jkSDS011.h>
|
||||
|
||||
|
||||
CjkSDS011 *Plugin_056_SDS = NULL;
|
||||
|
||||
|
||||
boolean Plugin_056(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_056;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_DUAL;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 2;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_056);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_056));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_056));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO ← TX");
|
||||
//event->String2 = F("GPIO ⇢ RX (optional)");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (Plugin_056_SDS)
|
||||
delete Plugin_056_SDS;
|
||||
Plugin_056_SDS = new CjkSDS011(Settings.TaskDevicePin1[event->TaskIndex], -1);
|
||||
addLog(LOG_LEVEL_INFO, F("SDS : Init OK "));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_EXIT:
|
||||
{
|
||||
if (Plugin_056_SDS)
|
||||
delete Plugin_056_SDS;
|
||||
addLog(LOG_LEVEL_INFO, F("SDS : Exit"));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_FIFTY_PER_SECOND:
|
||||
{
|
||||
if (!Plugin_056_SDS)
|
||||
break;
|
||||
|
||||
Plugin_056_SDS->Process();
|
||||
|
||||
if (Plugin_056_SDS->available())
|
||||
{
|
||||
String log = F("SDS : act ");
|
||||
log += Plugin_056_SDS->GetPM2_5();
|
||||
log += F(" ");
|
||||
log += Plugin_056_SDS->GetPM10_();
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
if (Settings.TaskDeviceTimer[event->TaskIndex] == 0)
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_056_SDS->GetPM2_5();
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_056_SDS->GetPM10_();
|
||||
event->sensorType = SENSOR_TYPE_DUAL;
|
||||
sendData(event);
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (!Plugin_056_SDS)
|
||||
break;
|
||||
|
||||
float pm25, pm10;
|
||||
Plugin_056_SDS->ReadAverage(pm25, pm10);
|
||||
|
||||
UserVar[event->BaseVarIndex + 0] = pm25;
|
||||
UserVar[event->BaseVarIndex + 1] = pm10;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif //PLUGIN_BUILD_TESTING
|
||||
@@ -0,0 +1,319 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 057: HT16K33 LED ##########################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to control a 16x8 LED matrix or 8 7-segment displays with chip HT16K33
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// List of commands:
|
||||
// (1) M,<param>,<param>,<param>, ... with decimal values
|
||||
// (2) MX,<param>,<param>,<param>, ... with hexadecimal values
|
||||
// (3) MNUM,<param>,<param>,<param>, ... with decimal values for 7-segment displays
|
||||
// (4) MPRINT,<text> with decimal values for 7-segment displays
|
||||
|
||||
// List of M* params:
|
||||
// (a) <value>
|
||||
// Writes a decimal / hexadecimal (0...0xFFFF) values to actual segment starting with 0
|
||||
// (b) <seg>=<value>
|
||||
// Writes a decimal / hexadecimal (0...0xFFFF) values to given segment (0...7)
|
||||
// (c) "CLEAR"
|
||||
// Set all LEDs to 0.
|
||||
// (d) "TEST"
|
||||
// Set test pattern to LED buffer.
|
||||
// (e) "LOG"
|
||||
// Print LED buffer to log output.
|
||||
|
||||
// Examples:
|
||||
// MX,AA,55,AA,55,AA,55,AA,55 Set chess pattern to LED buffer
|
||||
// MNUM,CLEAR,1,0 Clear the LED buffer and then set 0x06 to 1st segment and 0x3F to 2nd segment
|
||||
|
||||
// Connecting LEDs to HT16K33-board:
|
||||
// Cathode for Column 0 = C0
|
||||
// Cathode for Column 1 = C1
|
||||
// ...
|
||||
// Cathode for Column 7 = C7
|
||||
//
|
||||
// Anode for bit 0x0001 = A0
|
||||
// Anode for bit 0x0002 = A1
|
||||
// ...
|
||||
// Anode for bit 0x0080 = A7
|
||||
// ...
|
||||
// Anode for bit 0x8000 = A15
|
||||
|
||||
// Note: The HT16K33-LED-plugin and the HT16K33-key-plugin can be used at the same time with the same I2C address
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_057
|
||||
#define PLUGIN_ID_057 57
|
||||
#define PLUGIN_NAME_057 "LED - HT16K33 [TESTING]"
|
||||
|
||||
#include <HT16K33.h>
|
||||
|
||||
CHT16K33* Plugin_057_M = NULL;
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
|
||||
boolean Plugin_057(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_057;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].TimerOptional = false;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_057);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
int optionValues[8] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 8, optionValues, addr);
|
||||
|
||||
|
||||
addFormSubHeader(string, F("7-Seg. Clock"));
|
||||
|
||||
int16_t choice = CONFIG(1);
|
||||
String options[2] = { F("none"), F("7-Seg. HH:MM") };
|
||||
addFormSelector(string, F("Clock Type"), F("clocktype"), 2, options, NULL, choice);
|
||||
|
||||
addFormNumericBox(string, F("Seg. for <b>X</b>x:xx"), F("clocksegh10"), CONFIG(2), 0, 7);
|
||||
addFormNumericBox(string, F("Seg. for x<b>X</b>:xx"), F("clocksegh1"), CONFIG(3), 0, 7);
|
||||
addFormNumericBox(string, F("Seg. for xx:<b>X</b>x"), F("clocksegm10"), CONFIG(4), 0, 7);
|
||||
addFormNumericBox(string, F("Seg. for xx:x<b>X</b>"), F("clocksegm1"), CONFIG(5), 0, 7);
|
||||
|
||||
addFormNumericBox(string, F("Seg. for Colon"), F("clocksegcol"), CONFIG(6), -1, 7);
|
||||
string += F(" Value ");
|
||||
addNumericBox(string, F("clocksegcolval"), CONFIG(7), 0, 255);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
CONFIG(1) = getFormItemInt(F("clocktype"));
|
||||
|
||||
CONFIG(2) = getFormItemInt(F("clocksegh10"));
|
||||
CONFIG(3) = getFormItemInt(F("clocksegh1"));
|
||||
CONFIG(4) = getFormItemInt(F("clocksegm10"));
|
||||
CONFIG(5) = getFormItemInt(F("clocksegm1"));
|
||||
CONFIG(6) = getFormItemInt(F("clocksegcol"));
|
||||
CONFIG(7) = getFormItemInt(F("clocksegcolval"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
if (!Plugin_057_M)
|
||||
Plugin_057_M = new CHT16K33;
|
||||
|
||||
Plugin_057_M->Init(addr);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (!Plugin_057_M)
|
||||
return false;
|
||||
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
|
||||
if (command == F("mprint"))
|
||||
{
|
||||
int paramPos = getParamStartPos(string, 2);
|
||||
String text = string.substring(paramPos);
|
||||
byte seg = 0;
|
||||
|
||||
Plugin_057_M->ClearRowBuffer();
|
||||
while (text[seg] && seg < 8)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
char c = text[seg];
|
||||
Plugin_057_M->SetDigit(seg, c);
|
||||
seg++;
|
||||
}
|
||||
Plugin_057_M->TransmitRowBuffer();
|
||||
success = true;
|
||||
}
|
||||
|
||||
else if (command == F("m") || command == F("mx") || command == F("mnum"))
|
||||
{
|
||||
String param;
|
||||
String paramKey;
|
||||
String paramVal;
|
||||
byte paramIdx = 2;
|
||||
uint8_t seg = 0;
|
||||
uint16_t value = 0;
|
||||
|
||||
string.replace(" ", " ");
|
||||
string.replace(" =", "=");
|
||||
string.replace("= ", "=");
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
if (param.length())
|
||||
{
|
||||
while (param.length())
|
||||
{
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, param);
|
||||
|
||||
if (param == F("log"))
|
||||
{
|
||||
String log = F("MX : ");
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
log += String(Plugin_057_M->GetRow(i), 16);
|
||||
log += F("h, ");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
else if (param == F("test"))
|
||||
{
|
||||
for (byte i = 0; i < 8; i++)
|
||||
Plugin_057_M->SetRow(i, 1 << i);
|
||||
success = true;
|
||||
}
|
||||
|
||||
else if (param == F("clear"))
|
||||
{
|
||||
Plugin_057_M->ClearRowBuffer();
|
||||
success = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int index = param.indexOf('=');
|
||||
if (index > 0) //syntax: "<seg>=<value>"
|
||||
{
|
||||
paramKey = param.substring(0, index);
|
||||
paramVal = param.substring(index+1);
|
||||
seg = paramKey.toInt();
|
||||
}
|
||||
else //syntax: "<value>"
|
||||
{
|
||||
paramVal = param;
|
||||
}
|
||||
|
||||
if (command == F("mnum"))
|
||||
{
|
||||
value = paramVal.toInt();
|
||||
if (value < 16)
|
||||
Plugin_057_M->SetDigit(seg, value);
|
||||
else
|
||||
Plugin_057_M->SetRow(seg, value);
|
||||
}
|
||||
else if (command == F("mx"))
|
||||
{
|
||||
char* ep;
|
||||
value = strtol(paramVal.c_str(), &ep, 16);
|
||||
Plugin_057_M->SetRow(seg, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = paramVal.toInt();
|
||||
Plugin_057_M->SetRow(seg, value);
|
||||
}
|
||||
|
||||
success = true;
|
||||
seg++;
|
||||
}
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//??? no params
|
||||
}
|
||||
|
||||
if (success)
|
||||
Plugin_057_M->TransmitRowBuffer();
|
||||
success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_CLOCK_IN:
|
||||
{
|
||||
if (!Plugin_057_M || CONFIG(1) == 0)
|
||||
break;
|
||||
|
||||
byte hours = hour();
|
||||
byte minutes = minute();
|
||||
|
||||
//Plugin_057_M->ClearRowBuffer();
|
||||
if (hours >= 10)
|
||||
Plugin_057_M->SetDigit(CONFIG(2), hours/10);
|
||||
else
|
||||
Plugin_057_M->SetRow(CONFIG(2), 0); //empty seg
|
||||
Plugin_057_M->SetDigit(CONFIG(3), hours%10);
|
||||
Plugin_057_M->SetDigit(CONFIG(4), minutes/10);
|
||||
Plugin_057_M->SetDigit(CONFIG(5), minutes%10);
|
||||
//if (CONFIG(6) >= 0)
|
||||
// Plugin_057_M->SetRow(CONFIG(6), CONFIG(7));
|
||||
Plugin_057_M->TransmitRowBuffer();
|
||||
|
||||
success = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (!Plugin_057_M || CONFIG(1) == 0) //clock enabled?
|
||||
break;
|
||||
|
||||
if (CONFIG(6) >= 0) //colon used?
|
||||
{
|
||||
uint8_t act = ((uint16_t)millis() >> 9) & 1; //blink with about 2 Hz
|
||||
static uint8_t last = 0;
|
||||
if (act != last)
|
||||
{
|
||||
last = act;
|
||||
Plugin_057_M->SetRow(CONFIG(6), (act) ? CONFIG(7) : 0);
|
||||
Plugin_057_M->TransmitRowBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,151 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 058: HT16K33 KeyPad #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan a 13x3 key pad matrix chip HT16K33
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Connecting KeyPad to HT16K33-board:
|
||||
// Column 1 = C1 (over diode)
|
||||
// Column 2 = C2 (over diode)
|
||||
// Column 3 = C3 (over diode)
|
||||
// Row 1 = A3
|
||||
// Row 2 = A4
|
||||
// Row 3 = A5
|
||||
// ...
|
||||
// Row 13 = A15
|
||||
|
||||
// ScanCode;
|
||||
// 16*Column + Row
|
||||
// Pressing the top left key (typically "1") the code is 17 (0x11)
|
||||
// Pressing the key in column 2 and row 3 (typically "8") the code is 35 (0x23)
|
||||
|
||||
// Use diodes (e.g. 1N4148) for column lines:
|
||||
// HT16K33]-----|>|-----[key-matrix
|
||||
|
||||
// Note: The HT16K33-LED-plugin and the HT16K33-key-plugin can be used at the same time with the same I2C address
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_058
|
||||
#define PLUGIN_ID_058 58
|
||||
#define PLUGIN_NAME_058 "KeyPad - HT16K33 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_058 "ScanCode"
|
||||
|
||||
#include <HT16K33.h>
|
||||
|
||||
CHT16K33* Plugin_058_K = NULL;
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
|
||||
boolean Plugin_058(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_058;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_058);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_058));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
int optionValues[8] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 8, optionValues, addr);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
if (!Plugin_058_K)
|
||||
Plugin_058_K = new CHT16K33;
|
||||
|
||||
Plugin_058_K->Init(addr);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (Plugin_058_K)
|
||||
{
|
||||
static uint8_t keyLast = 0;
|
||||
|
||||
uint8_t key = Plugin_058_K->ReadKeys();
|
||||
|
||||
if (keyLast != key)
|
||||
{
|
||||
keyLast = key;
|
||||
UserVar[event->BaseVarIndex] = (float)key;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
|
||||
String log = F("Mkey : key=0x");
|
||||
log += String(key, 16);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
sendData(event);
|
||||
}
|
||||
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (Plugin_058_K)
|
||||
{
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 059: Rotary Encoder #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to process the quadrature encoder interface signals (e.g. rotary encoder)
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Connection:
|
||||
// Use 1st and 2nd GPIO for encoders A and B signal.
|
||||
// Optional use 3rd GPIO for encoders I signel to reset counter to 0 at first trigger.
|
||||
// If counter runs in wrong direction, change A and B GPIOs in settings page
|
||||
|
||||
// Note: Up to 4 encoders can be used simultaniously
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_059
|
||||
#define PLUGIN_ID_059 59
|
||||
#define PLUGIN_NAME_059 "Switch Input - Rotary Encoder [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_059 "Counter"
|
||||
|
||||
#include <QEIx4.h>
|
||||
|
||||
QEIx4* Plugin_059_QE = NULL;
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
#ifndef CONFIG_L
|
||||
#define CONFIG_L(n) (Settings.TaskDevicePluginConfigLong[event->TaskIndex][n])
|
||||
#endif
|
||||
#ifndef PIN
|
||||
#define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex])
|
||||
#endif
|
||||
|
||||
|
||||
boolean Plugin_059(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_059;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_TRIPLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_059);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_059));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO ← A");
|
||||
event->String2 = F("GPIO ← B");
|
||||
event->String3 = F("GPIO ⇠ I (optional)");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
// default values
|
||||
if (CONFIG_L(0) == 0 && CONFIG_L(1) == 0)
|
||||
CONFIG_L(1) = 100;
|
||||
|
||||
String options[3] = { F("1 pulse per cycle"), F("2 pulses per cycle"), F("4 pulses per cycle") };
|
||||
int optionValues[3] = { 1, 2, 4 };
|
||||
addFormSelector(string, F("Mode"), F("qei_mode"), 3, options, optionValues, CONFIG(0));
|
||||
|
||||
addFormNumericBox(string, F("Limit min."), F("qei_limitmin"), CONFIG_L(0));
|
||||
addFormNumericBox(string, F("Limit max."), F("qei_limitmax"), CONFIG_L(1));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("qei_mode"));
|
||||
|
||||
CONFIG_L(0) = getFormItemInt(F("qei_limitmin"));
|
||||
CONFIG_L(1) = getFormItemInt(F("qei_limitmax"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (!Plugin_059_QE)
|
||||
Plugin_059_QE = new QEIx4;
|
||||
|
||||
Plugin_059_QE->begin(PIN(0),PIN(1),PIN(2),CONFIG(0));
|
||||
Plugin_059_QE->setLimit(CONFIG_L(0), CONFIG_L(1));
|
||||
Plugin_059_QE->setIndexTrigger(true);
|
||||
|
||||
ExtraTaskSettings.TaskDeviceValueDecimals[event->BaseVarIndex] = 0;
|
||||
|
||||
String log = F("QEI : GPIO: ");
|
||||
for (byte i=0; i<3; i++)
|
||||
{
|
||||
int pin = PIN(i);
|
||||
if (pin >= 0)
|
||||
{
|
||||
//pinMode(pin, (Settings.TaskDevicePin1PullUp[event->TaskIndex]) ? INPUT_PULLUP : INPUT);
|
||||
setPinState(PLUGIN_ID_059, pin, PIN_MODE_INPUT, 0);
|
||||
}
|
||||
log += pin;
|
||||
log += F(" ");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (Plugin_059_QE)
|
||||
{
|
||||
if (Plugin_059_QE->hasChanged())
|
||||
{
|
||||
long c = Plugin_059_QE->read();
|
||||
UserVar[event->BaseVarIndex] = (float)c;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
|
||||
String log = F("QEI : ");
|
||||
log += c;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
sendData(event);
|
||||
}
|
||||
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (Plugin_059_QE)
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = (float)Plugin_059_QE->read();
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,169 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 060: MCP3221 ##############################################
|
||||
//#######################################################################################################
|
||||
|
||||
// Plugin to read 12-bit-values from ADC chip MCP3221. It is used e.g. in MinipH pH interface to sample a pH probe in an aquarium
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_060
|
||||
#define PLUGIN_ID_060 60
|
||||
#define PLUGIN_NAME_060 "Analog input - MCP3221 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_060 "Analog"
|
||||
|
||||
uint32_t Plugin_060_OversamplingValue = 0;
|
||||
uint16_t Plugin_060_OversamplingCount = 0;
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
|
||||
uint16_t readMCP3221(byte addr)
|
||||
{
|
||||
uint16_t value;
|
||||
Wire.requestFrom(addr, (uint8_t)2);
|
||||
if (Wire.available() == 2)
|
||||
{
|
||||
value = (Wire.read() << 8) | Wire.read();
|
||||
}
|
||||
else
|
||||
value = 9999;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
boolean Plugin_060(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_060;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_060);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_060));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
int optionValues[8] = { 0x4D, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4E, 0x4F };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 8, optionValues, addr);
|
||||
|
||||
addFormCheckBox(string, F("Oversampling"), F("plugin_060_oversampling"), CONFIG(1));
|
||||
|
||||
addFormSubHeader(string, F("Two Point Calibration"));
|
||||
|
||||
addFormCheckBox(string, F("Calibration Enabled"), F("plugin_060_cal"), CONFIG(3));
|
||||
|
||||
addFormNumericBox(string, F("Point 1"), F("plugin_060_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_060_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
|
||||
|
||||
addFormNumericBox(string, F("Point 2"), F("plugin_060_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_060_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
CONFIG(1) = isFormItemChecked(F("plugin_060_oversampling"));
|
||||
|
||||
CONFIG(3) = isFormItemChecked(F("plugin_060_cal"));
|
||||
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][0] = getFormItemInt(F("plugin_060_adc1"));
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = getFormItemFloat(F("plugin_060_out1"));
|
||||
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][1] = getFormItemInt(F("plugin_060_adc2"));
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = getFormItemFloat(F("plugin_060_out2"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (CONFIG(1)) //Oversampling?
|
||||
{
|
||||
Plugin_060_OversamplingValue += readMCP3221(CONFIG(0));
|
||||
Plugin_060_OversamplingCount ++;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
String log = F("ADMCP: Analog value: ");
|
||||
|
||||
if (Plugin_060_OversamplingCount > 0)
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = (float)Plugin_060_OversamplingValue / Plugin_060_OversamplingCount;
|
||||
Plugin_060_OversamplingValue = 0;
|
||||
Plugin_060_OversamplingCount = 0;
|
||||
|
||||
log += String(UserVar[event->BaseVarIndex], 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
int16_t value = readMCP3221(CONFIG(0));
|
||||
UserVar[event->BaseVarIndex] = (float)value;
|
||||
|
||||
log += value;
|
||||
}
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][3]) //Calibration?
|
||||
{
|
||||
int adc1 = Settings.TaskDevicePluginConfigLong[event->TaskIndex][0];
|
||||
int adc2 = Settings.TaskDevicePluginConfigLong[event->TaskIndex][1];
|
||||
float out1 = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0];
|
||||
float out2 = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1];
|
||||
if (adc1 != adc2)
|
||||
{
|
||||
float normalized = (float)(UserVar[event->BaseVarIndex] - adc1) / (float)(adc2 - adc1);
|
||||
UserVar[event->BaseVarIndex] = normalized * (out2 - out1) + out1;
|
||||
|
||||
log += F(" = ");
|
||||
log += String(UserVar[event->BaseVarIndex], 3);
|
||||
}
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,375 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 061: PCF8574/MCP23017 KeyPad ##############################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan a (up to) 9x8 key pad matrix chip MCP23017
|
||||
// or a (up to) 5x4 key pad matrix chip PCF8574
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Connecting KeyPad matrix to MCP23017 chip:
|
||||
// row 0 = GND (optional if 9 rows needed)
|
||||
// row 1 = GPA0
|
||||
// row 2 = GPA1
|
||||
// ...
|
||||
// row 8 = GPA7
|
||||
//
|
||||
// column 1 = GPB0
|
||||
// column 2 = GPB1
|
||||
// ...
|
||||
// column 8 = GPB7
|
||||
|
||||
//Typical Key Pad:
|
||||
// C1 C2 C3
|
||||
// R1 [1] [2] [3]
|
||||
// R2 [4] [5] [6]
|
||||
// R3 [7] [8] [9]
|
||||
// R4 [*] [0] [#]
|
||||
|
||||
// Connecting KeyPad matrix to PCF8574 chip:
|
||||
// row 0 = GND (optional if 5 rows needed)
|
||||
// row 1 = P0
|
||||
// row 2 = P1
|
||||
// row 3 = P2
|
||||
// row 4 = P3
|
||||
//
|
||||
// column 1 = P4
|
||||
// column 2 = P5
|
||||
// column 3 = P6
|
||||
// column 4 = P7
|
||||
|
||||
// Connecting KeyPad direct to PCF8574 chip:
|
||||
// common = GND
|
||||
// key 1 = P0
|
||||
// key 2 = P1
|
||||
// ...
|
||||
// key 8 = P7
|
||||
|
||||
// ScanCode;
|
||||
// 16*col + row
|
||||
// Pressing the top left key (typically "1") the code is 17 (0x11)
|
||||
// Pressing the key in rowumn 2 and col 3 (typically "8") the code is 35 (0x23)
|
||||
// No key - the code 0
|
||||
// If more than one key is pressed, the scan code is the code with the lowest value
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_061
|
||||
#define PLUGIN_ID_061 61
|
||||
#define PLUGIN_NAME_061 "KeyPad - PCF8574 / MCP23017 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_061 "ScanCode"
|
||||
|
||||
// #include <*.h> // no include needed
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
|
||||
boolean Plugin_061(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_061;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_061);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_061));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
int optionValues[16] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), (CONFIG(1) == 0) ? 8 : 16, optionValues, addr);
|
||||
if (CONFIG(1) != 0)
|
||||
addFormNote(string, F("PCF8574 uses address 0x20+; PCF8574<b>A</b> uses address 0x38+"));
|
||||
|
||||
String options[3] = { F("MCP23017 (Matrix 9x8)"), F("PCF8574 (Matrix 5x4)"), F("PCF8574 (Direct 8)") };
|
||||
addFormSelector(string, F("Chip (Mode)"), F("chip"), 3, options, NULL, CONFIG(1));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
CONFIG(1) = getFormItemInt(F("chip"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
switch (CONFIG(1))
|
||||
{
|
||||
case 0: MCP23017_KeyPadMatrixInit(CONFIG(0)); break;
|
||||
case 1: PCF8574_KeyPadMatrixInit(CONFIG(0)); break;
|
||||
case 2: PCF8574_KeyPadDirectInit(CONFIG(0)); break;
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_FIFTY_PER_SECOND:
|
||||
{
|
||||
static byte lastScanCode = 0xFF;
|
||||
static byte sentScanCode = 0xFF;
|
||||
byte actScanCode = 0;
|
||||
|
||||
switch (CONFIG(1))
|
||||
{
|
||||
case 0: actScanCode = MCP23017_KeyPadMatrixScan(CONFIG(0)); break;
|
||||
case 1: actScanCode = PCF8574_KeyPadMatrixScan(CONFIG(0)); break;
|
||||
case 2: actScanCode = PCF8574_KeyPadDirectScan(CONFIG(0)); break;
|
||||
}
|
||||
|
||||
if (lastScanCode == actScanCode) // debounced? - two times the same value?
|
||||
{
|
||||
if (sentScanCode != actScanCode) // any change to last sent data?
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = (float)actScanCode;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
|
||||
String log = F("KPad : ScanCode=0x");
|
||||
log += String(actScanCode, 16);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
sendData(event);
|
||||
|
||||
sentScanCode = actScanCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
lastScanCode = actScanCode;
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
// work is done in PLUGIN_FIFTY_PER_SECOND
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
// MCP23017 Matrix /////////////////////////////////////////////////////////////
|
||||
|
||||
#define MCP23017_IODIRA 0x00 // I/O DIRECTION REGISTER IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
|
||||
#define MCP23017_IODIRB 0x01 // I/O DIRECTION REGISTER IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
|
||||
#define MCP23017_IPOLA 0x02 // INPUT POLARITY PORT REGISTER IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
|
||||
#define MCP23017_IPOLB 0x03 // INPUT POLARITY PORT REGISTER IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
|
||||
#define MCP23017_GPINTENA 0x04 // INTERRUPT-ON-CHANGE PINS GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
|
||||
#define MCP23017_GPINTENB 0x05 // INTERRUPT-ON-CHANGE PINS GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
|
||||
#define MCP23017_DEFVALA 0x06 // DEFAULT VALUE REGISTER DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
|
||||
#define MCP23017_DEFVALB 0x07 // DEFAULT VALUE REGISTER DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
|
||||
#define MCP23017_INTCONA 0x08 // INTERRUPT-ON-CHANGE CONTROL REGISTER IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
|
||||
#define MCP23017_INTCONB 0x09 // INTERRUPT-ON-CHANGE CONTROL REGISTER IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
|
||||
#define MCP23017_IOCON 0x0A // I/O EXPANDER CONFIGURATION REGISTER BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL — 0000 0000 - also on addr 0x0B
|
||||
#define MCP23017_GPPUA 0x0C // GPIO PULL-UP RESISTOR REGISTER PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
|
||||
#define MCP23017_GPPUB 0x0D // GPIO PULL-UP RESISTOR REGISTER PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
|
||||
#define MCP23017_INTFA 0x0E // INTERRUPT FLAG REGISTER INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
|
||||
#define MCP23017_INTFB 0x0F // INTERRUPT FLAG REGISTER INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
|
||||
#define MCP23017_INTCAPA 0x10 // INTERRUPT CAPTURED VALUE FOR PORT REGISTER ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
|
||||
#define MCP23017_INTCAPB 0x11 // INTERRUPT CAPTURED VALUE FOR PORT REGISTER ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
|
||||
#define MCP23017_GPIOA 0x12 // GENERAL PURPOSE I/O PORT REGISTER GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
|
||||
#define MCP23017_GPIOB 0x13 // GENERAL PURPOSE I/O PORT REGISTER GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
|
||||
#define MCP23017_OLATA 0x14 // OUTPUT LATCH REGISTER OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
|
||||
#define MCP23017_OLATB 0x15 // OUTPUT LATCH REGISTER OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
|
||||
|
||||
|
||||
void MCP23017_setReg(byte addr, byte reg, byte data)
|
||||
{
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write(reg);
|
||||
Wire.write(data);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
byte MCP23017_getReg(byte addr, byte reg)
|
||||
{
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(addr, (uint8_t)0x1);
|
||||
if (Wire.available())
|
||||
{
|
||||
return Wire.read();
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void MCP23017_KeyPadMatrixInit(byte addr)
|
||||
{
|
||||
MCP23017_setReg(addr, MCP23017_IODIRA, 0x00); // port A to output
|
||||
MCP23017_setReg(addr, MCP23017_GPIOA, 0x00); // port A to low
|
||||
MCP23017_setReg(addr, MCP23017_IODIRB, 0xFF); // port B to input
|
||||
MCP23017_setReg(addr, MCP23017_GPPUA, 0xFF); // port A pullup on
|
||||
MCP23017_setReg(addr, MCP23017_GPPUB, 0xFF); // port B pullup on
|
||||
}
|
||||
|
||||
byte MCP23017_KeyPadMatrixScan(byte addr)
|
||||
{
|
||||
byte rowMask = 1;
|
||||
byte colData;
|
||||
|
||||
colData = MCP23017_getReg(addr, MCP23017_GPIOB);
|
||||
if (colData == 0xFF) // no key pressed?
|
||||
return 0; // no key pressed!
|
||||
|
||||
for (byte row = 0; row <= 8; row++)
|
||||
{
|
||||
if (row == 0)
|
||||
MCP23017_setReg(addr, MCP23017_IODIRA, 0xFF); // no bit of port A to output
|
||||
else
|
||||
{
|
||||
MCP23017_setReg(addr, MCP23017_IODIRA, ~rowMask); // one bit of port A to output 0
|
||||
rowMask <<= 1;
|
||||
}
|
||||
|
||||
colData = MCP23017_getReg(addr, MCP23017_GPIOB);
|
||||
if (colData != 0xFF) // any key pressed?
|
||||
{
|
||||
byte colMask = 1;
|
||||
for (byte col = 1; col <= 8; col++)
|
||||
{
|
||||
if ((colData & colMask) == 0) // this key pressed?
|
||||
{
|
||||
MCP23017_setReg(addr, MCP23017_IODIRA, 0x00); // port A to output 0
|
||||
return ((row << 4) | col);
|
||||
}
|
||||
colMask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MCP23017_setReg(addr, MCP23017_IODIRA, 0x00); // port A to output 0
|
||||
return 0; // no key pressed!
|
||||
}
|
||||
|
||||
// PCF8574 Matrix //////////////////////////////////////////////////////////////
|
||||
|
||||
void PCF8574_setReg(byte addr, byte data)
|
||||
{
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write(data);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
byte PCF8574_getReg(byte addr)
|
||||
{
|
||||
Wire.requestFrom(addr, (uint8_t)0x1);
|
||||
if (Wire.available())
|
||||
{
|
||||
return Wire.read();
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void PCF8574_KeyPadMatrixInit(byte addr)
|
||||
{
|
||||
PCF8574_setReg(addr, 0xF0); // low nibble to output 0
|
||||
}
|
||||
|
||||
byte PCF8574_KeyPadMatrixScan(byte addr)
|
||||
{
|
||||
byte rowMask = 1;
|
||||
byte colData;
|
||||
|
||||
colData = PCF8574_getReg(addr) & 0xF0;
|
||||
if (colData == 0xF0) // no key pressed?
|
||||
return 0; // no key pressed!
|
||||
|
||||
for (byte row = 0; row <= 4; row++)
|
||||
{
|
||||
if (row == 0)
|
||||
PCF8574_setReg(addr, 0xFF); // no bit of port A to output
|
||||
else
|
||||
{
|
||||
PCF8574_setReg(addr, ~rowMask); // one bit of port A to output 0
|
||||
rowMask <<= 1;
|
||||
}
|
||||
|
||||
colData = PCF8574_getReg(addr) & 0xF0;
|
||||
if (colData != 0xF0) // any key pressed?
|
||||
{
|
||||
byte colMask = 0x10;
|
||||
for (byte col = 1; col <= 4; col++)
|
||||
{
|
||||
if ((colData & colMask) == 0) // this key pressed?
|
||||
{
|
||||
PCF8574_setReg(addr, 0xF0); // low nibble to output 0
|
||||
return ((row << 4) | col);
|
||||
}
|
||||
colMask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PCF8574_setReg(addr, 0xF0); // low nibble to output 0
|
||||
return 0; // no key pressed!
|
||||
}
|
||||
|
||||
// PCF8574 Direct //////////////////////////////////////////////////////////////
|
||||
|
||||
void PCF8574_KeyPadDirectInit(byte addr)
|
||||
{
|
||||
PCF8574_setReg(addr, 0xFF); // all to input
|
||||
}
|
||||
|
||||
byte PCF8574_KeyPadDirectScan(byte addr)
|
||||
{
|
||||
byte colData;
|
||||
|
||||
colData = PCF8574_getReg(addr);
|
||||
if (colData == 0xFF) // no key pressed?
|
||||
return 0; // no key pressed!
|
||||
|
||||
byte colMask = 0x01;
|
||||
for (byte col = 1; col <= 8; col++)
|
||||
{
|
||||
if ((colData & colMask) == 0) // this key pressed?
|
||||
{
|
||||
return (col);
|
||||
}
|
||||
colMask <<= 1;
|
||||
}
|
||||
|
||||
return 0; // no key pressed!
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 062: MPR121 KeyPad ########################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan a 12 key touch pad chip MPR121
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// ScanCode;
|
||||
// Value 1...12 for the key number
|
||||
// No key - the code 0
|
||||
// If more than one key is pressed, the scan code is the code with the lowest value
|
||||
|
||||
// If ScanCode is unchecked the value is the KeyMap 1.Key=1, 2.Key=2, 3.Key=4, 4.Key=8 ... 1.Key=2048
|
||||
// If more than one key is pressed, the value is sum of all KeyMap-values
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_062
|
||||
#define PLUGIN_ID_062 62
|
||||
#define PLUGIN_NAME_062 "KeyPad - MPR121 Touch [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_062 "ScanCode"
|
||||
|
||||
#include <Adafruit_MPR121.h>
|
||||
|
||||
Adafruit_MPR121* Plugin_062_K = NULL;
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
|
||||
boolean Plugin_062(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_062;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_062);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_062));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
int optionValues[4] = { 0x5A, 0x5B, 0x5C, 0x5D };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 4, optionValues, addr);
|
||||
|
||||
addFormCheckBox(string, F("ScanCode"), F("scancode"), CONFIG(1));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
CONFIG(1) = isFormItemChecked(F("scancode"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
byte addr = CONFIG(0);
|
||||
|
||||
if (!Plugin_062_K)
|
||||
Plugin_062_K = new Adafruit_MPR121;
|
||||
|
||||
Plugin_062_K->begin(addr);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
if (Plugin_062_K)
|
||||
{
|
||||
static uint16_t keyLast = 0;
|
||||
|
||||
uint16_t key = Plugin_062_K->touched();
|
||||
|
||||
if (key && CONFIG(1))
|
||||
{
|
||||
uint16_t colMask = 0x01;
|
||||
for (byte col = 1; col <= 12; col++)
|
||||
{
|
||||
if (key & colMask) // this key pressed?
|
||||
{
|
||||
key = col;
|
||||
break;
|
||||
}
|
||||
colMask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyLast != key)
|
||||
{
|
||||
keyLast = key;
|
||||
UserVar[event->BaseVarIndex] = (float)key;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
|
||||
String log = F("Tkey : ");
|
||||
if (CONFIG(1))
|
||||
log = F("ScanCode=0x");
|
||||
else
|
||||
log = F("KeyMap=0x");
|
||||
log += String(key, 16);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
sendData(event);
|
||||
}
|
||||
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (Plugin_062_K)
|
||||
{
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 063: TTP229 KeyPad ########################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan a 16 key touch pad chip TTP229
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Important: There are several types of TTP299 chips with different features available. They are namead all TTP229 but differ in the letter(s) followed.
|
||||
// On the china boards (found on eBay and AliExpress) the TTP229-B is used which has NO! I2C-interface. It uses a properitary serial protocol with clock (SCL) and bidirectional data (SDO)
|
||||
|
||||
// ScanCode;
|
||||
// Value 1...16 for the key number
|
||||
// No key - the code 0
|
||||
// If more than one key is pressed, the scan code is the code with the lowest value
|
||||
|
||||
// If ScanCode is unchecked the value is the KeyMap 1.Key=1, 2.Key=2, 3.Key=4, 4.Key=8 ... 16.Key=32768
|
||||
// If more than one key is pressed, the value is sum of all KeyMap-values
|
||||
|
||||
// Electronics:
|
||||
// Connect SCL to 1st GPIO and SDO to 2nd GPIO. Use 3.3 volt for VCC.
|
||||
// Set the jumper for 16 key mode (TP2=jumper3). Additional set jumper for multi-key (TP3=jumper4, TP4=jumper5).
|
||||
// Scematics: https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/TTP229B-Schematic-Diagram.pdf
|
||||
// Datasheet: http://www.datasheet4u.com/download_new.php?id=996751
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_063
|
||||
#define PLUGIN_ID_063 63
|
||||
#define PLUGIN_NAME_063 "KeyPad - TTP229 Touch [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_063 "ScanCode"
|
||||
|
||||
// #include <*.h> no lib required
|
||||
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
#ifndef PIN
|
||||
#define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex])
|
||||
#endif
|
||||
|
||||
uint16_t readTTP229(int16_t pinSCL, int16_t pinSDO)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
uint16_t mask = 1;
|
||||
|
||||
pinMode(pinSDO, OUTPUT);
|
||||
digitalWrite(pinSDO, HIGH);
|
||||
delayMicroseconds(100);
|
||||
|
||||
digitalWrite(pinSDO, LOW);
|
||||
delayMicroseconds(10);
|
||||
|
||||
pinMode(pinSDO, INPUT);
|
||||
for (byte i = 0; i < 16; i++)
|
||||
{
|
||||
digitalWrite(pinSCL, HIGH);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(pinSCL, LOW);
|
||||
if (!digitalRead(pinSDO))
|
||||
value |= mask;
|
||||
delayMicroseconds(1);
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
boolean Plugin_063(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_063;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_063);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_063));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO → SCL");
|
||||
event->String2 = F("GPIO ⇄ SDO");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormCheckBox(string, F("ScanCode"), F("scancode"), CONFIG(1));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(1) = isFormItemChecked(F("scancode"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
int16_t pinSCL = PIN(0);
|
||||
int16_t pinSDO = PIN(1);
|
||||
|
||||
String log = F("Tkey : GPIO: ");
|
||||
log += pinSCL;
|
||||
log += F(" ");
|
||||
log += pinSDO;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (pinSCL >= 0 && pinSDO >= 0)
|
||||
{
|
||||
pinMode(pinSCL, OUTPUT);
|
||||
digitalWrite(pinSCL, LOW);
|
||||
setPinState(PLUGIN_ID_063, pinSCL, PIN_MODE_OUTPUT, 0);
|
||||
pinMode(pinSDO, OUTPUT);
|
||||
digitalWrite(pinSDO, LOW);
|
||||
setPinState(PLUGIN_ID_063, pinSDO, PIN_MODE_INPUT, 0);
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
static uint16_t keyLast = 0;
|
||||
int16_t pinSCL = PIN(0);
|
||||
int16_t pinSDO = PIN(1);
|
||||
|
||||
if (pinSCL >= 0 && pinSDO >= 0)
|
||||
{
|
||||
uint16_t key = readTTP229(pinSCL, pinSDO);
|
||||
|
||||
if (key && CONFIG(1))
|
||||
{
|
||||
uint16_t colMask = 0x01;
|
||||
for (byte col = 1; col <= 16; col++)
|
||||
{
|
||||
if (key & colMask) // this key pressed?
|
||||
{
|
||||
key = col;
|
||||
break;
|
||||
}
|
||||
colMask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyLast != key)
|
||||
{
|
||||
keyLast = key;
|
||||
UserVar[event->BaseVarIndex] = (float)key;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
|
||||
String log = F("Tkey : ");
|
||||
if (CONFIG(1))
|
||||
log = F("ScanCode=0x");
|
||||
else
|
||||
log = F("KeyMap=0x");
|
||||
log += String(key, 16);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
sendData(event);
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
// work is done in PLUGIN_TEN_PER_SECOND
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,217 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 064: APDS9960 Gesture ##############################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan a gesture, proximity and light chip APDS9960
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// A new gesture is send immediately to controllers.
|
||||
// Proximity and Light are scanned frequently by given 'Delay' setting.
|
||||
// RGB is not scanned because there are only 4 vars per task.
|
||||
|
||||
// Known BUG: While performing a gesture the reader function blocks rest of ESPEasy processing!!! (Feel free to fix...)
|
||||
|
||||
// Note: The chip has a wide view-of-angle. If housing is in this angle the chip blocks!
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_DEV
|
||||
|
||||
#define PLUGIN_064
|
||||
#define PLUGIN_ID_064 64
|
||||
#define PLUGIN_NAME_064 "Gesture - APDS9960 [DEV]"
|
||||
#define PLUGIN_VALUENAME1_064 "Gesture"
|
||||
#define PLUGIN_VALUENAME2_064 "Proximity"
|
||||
#define PLUGIN_VALUENAME3_064 "Light"
|
||||
/*
|
||||
#define PLUGIN_VALUENAME4_064 "R"
|
||||
#define PLUGIN_VALUENAME5_064 "G"
|
||||
#define PLUGIN_VALUENAME6_064 "B"
|
||||
*/
|
||||
|
||||
#include <SparkFun_APDS9960.h> //Lib is modified to work with ESP
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
SparkFun_APDS9960* PLUGIN_064_pds = NULL;
|
||||
|
||||
|
||||
boolean Plugin_064(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_064;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 3;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_064);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_064));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_064));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_064));
|
||||
/*
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_064));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[4], PSTR(PLUGIN_VALUENAME5_064));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[5], PSTR(PLUGIN_VALUENAME6_064));
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte addr = 0x39; // CONFIG(0); chip has only 1 address
|
||||
|
||||
int optionValues[1] = { 0x39 };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 1, optionValues, addr); //Only for display I2C address
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
//CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (PLUGIN_064_pds)
|
||||
delete PLUGIN_064_pds;
|
||||
PLUGIN_064_pds = new SparkFun_APDS9960();
|
||||
|
||||
String log = F("APDS : ");
|
||||
if ( PLUGIN_064_pds->init() )
|
||||
{
|
||||
log += F("Init");
|
||||
|
||||
PLUGIN_064_pds->enablePower();
|
||||
|
||||
if (! PLUGIN_064_pds->enableLightSensor(false))
|
||||
log += F(" - Error during light sensor init!");
|
||||
if (! PLUGIN_064_pds->enableProximitySensor(false))
|
||||
log += F(" - Error during proximity sensor init!");
|
||||
|
||||
if (! PLUGIN_064_pds->enableGestureSensor(false))
|
||||
log += F(" - Error during gesture sensor init!");
|
||||
}
|
||||
else
|
||||
{
|
||||
log += F("Error during APDS-9960 init!");
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_FIFTY_PER_SECOND:
|
||||
{
|
||||
if (!PLUGIN_064_pds)
|
||||
break;
|
||||
|
||||
if ( !PLUGIN_064_pds->isGestureAvailable() )
|
||||
break;
|
||||
|
||||
int gesture = PLUGIN_064_pds->readGesture();
|
||||
|
||||
//int gesture = PLUGIN_064_pds->readGestureNonBlocking();
|
||||
|
||||
//if (gesture == -1) Serial.print(".");
|
||||
//if (gesture == -2) Serial.print(":");
|
||||
//if (gesture == -3) Serial.print("|");
|
||||
|
||||
//if ( 0 && PLUGIN_064_pds->isGestureAvailable() )
|
||||
if (gesture >= 0)
|
||||
{
|
||||
String log = F("APDS : Gesture=");
|
||||
|
||||
switch ( gesture )
|
||||
{
|
||||
case DIR_UP: log += F("UP"); break;
|
||||
case DIR_DOWN: log += F("DOWN"); break;
|
||||
case DIR_LEFT: log += F("LEFT"); break;
|
||||
case DIR_RIGHT: log += F("RIGHT"); break;
|
||||
case DIR_NEAR: log += F("NEAR"); break;
|
||||
case DIR_FAR: log += F("FAR"); break;
|
||||
default: log += F("NONE"); break;
|
||||
}
|
||||
log += F(" (");
|
||||
log += gesture;
|
||||
log += F(")");
|
||||
|
||||
UserVar[event->BaseVarIndex] = (float)gesture;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
|
||||
sendData(event);
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (!PLUGIN_064_pds)
|
||||
break;
|
||||
|
||||
// Gesture - work is done in PLUGIN_FIFTY_PER_SECOND
|
||||
|
||||
if (1)
|
||||
{
|
||||
uint8_t proximity_data = 0;
|
||||
PLUGIN_064_pds->readProximity(proximity_data);
|
||||
UserVar[event->BaseVarIndex + 1] = (float)proximity_data;
|
||||
|
||||
uint16_t ambient_light = 0;
|
||||
PLUGIN_064_pds->readAmbientLight(ambient_light);
|
||||
UserVar[event->BaseVarIndex + 2] = (float)ambient_light;
|
||||
|
||||
/*
|
||||
uint16_t red_light = 0;
|
||||
uint16_t green_light = 0;
|
||||
uint16_t blue_light = 0;
|
||||
PLUGIN_064_pds->readRedLight(red_light);
|
||||
PLUGIN_064_pds->readGreenLight(green_light);
|
||||
PLUGIN_064_pds->readBlueLight(blue_light);
|
||||
UserVar[event->BaseVarIndex + 3] = (float)red_light;
|
||||
UserVar[event->BaseVarIndex + 4] = (float)green_light;
|
||||
UserVar[event->BaseVarIndex + 5] = (float)blue_light;
|
||||
*/
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,222 @@
|
||||
//#######################################################################################################
|
||||
//############################# Plugin 065: P065_DFR0299_MP3 ############################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to controls a MP3-player-module DFPlayer-Mini SKU:DFR0299
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Important! The module WTV020-SD look similar to the module DFPlayer-Mini but is NOT pin and command compatible!
|
||||
|
||||
// Commands:
|
||||
// play,<track> Plays the n-th track 1...3000 on SD-card in root folder. The track number is the physical ordenr - not the order displayed in file explorer!
|
||||
// stop Stops actual playing sound
|
||||
// vol,<volume> Set volume level 1...30
|
||||
// eq,<type> Set the equalizer type 0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=classic, 5=Base
|
||||
|
||||
// Circuit wiring
|
||||
// 1st-GPIO -> ESP TX to module RX [Pin2]
|
||||
// 5V to module VCC [Pin1] (can be more than 100mA) Note: Use a capacitor to denoise VCC
|
||||
// GND to module GND [Pin7+Pin10]
|
||||
// Speaker to module SPK_1 and SPK_2 [Pin6,Pin8] (not to GND!) Note: If speaker has to low impedance, use a resistor (like 33 Ohm) in line to speaker
|
||||
// (optional) module BUSY [Pin16] to LED driver (3.3V on idle, 0V on playing)
|
||||
// All other pins unconnected
|
||||
|
||||
// Note: Notification sounds with Creative Commons Attribution license: https://notificationsounds.com/
|
||||
|
||||
// Datasheet: https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_065
|
||||
#define PLUGIN_ID_065 65
|
||||
#define PLUGIN_NAME_065 "Notify - DFPlayer-Mini MP3 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_065 ""
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
#ifndef PIN
|
||||
#define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex])
|
||||
#endif
|
||||
|
||||
SoftwareSerial* Plugin_065_SoftSerial = NULL;
|
||||
|
||||
|
||||
boolean Plugin_065(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_065;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].GlobalSyncOption = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_065);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO → RX");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormNumericBox(string, F("Volume"), F("volume"), CONFIG(0), 1, 30);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("volume"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (Plugin_065_SoftSerial)
|
||||
delete Plugin_065_SoftSerial;
|
||||
Plugin_065_SoftSerial = new SoftwareSerial(-1, PIN(0)); // no RX, only TX
|
||||
|
||||
Plugin_065_SoftSerial->begin(9600);
|
||||
|
||||
Plugin_065_SetVol(CONFIG(0)); // set default volume
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (!Plugin_065_SoftSerial)
|
||||
break;
|
||||
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String param = parseString(string, 2);
|
||||
|
||||
if (command == F("play"))
|
||||
{
|
||||
String log = F("MP3 : play=");
|
||||
|
||||
uint16_t track = param.toInt();
|
||||
Plugin_065_Play(track);
|
||||
log += track;
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("stop"))
|
||||
{
|
||||
String log = F("MP3 : stop");
|
||||
|
||||
Plugin_065_SendCmd(0x0E, 0);
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("vol"))
|
||||
{
|
||||
String log = F("MP3 : vol=");
|
||||
|
||||
int8_t vol = param.toInt();
|
||||
if (vol == 0) vol = 30;
|
||||
CONFIG(0) = vol;
|
||||
Plugin_065_SetVol(vol);
|
||||
log += vol;
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("eq"))
|
||||
{
|
||||
String log = F("MP3 : eq=");
|
||||
|
||||
int8_t eq = param.toInt();
|
||||
Plugin_065_SetEQ(eq);
|
||||
log += eq;
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void Plugin_065_Play(uint16_t track)
|
||||
{
|
||||
Plugin_065_SendCmd(0x03, track);
|
||||
}
|
||||
|
||||
void Plugin_065_SetVol(int8_t vol)
|
||||
{
|
||||
if (vol < 1) vol = 1;
|
||||
if (vol > 30) vol = 30;
|
||||
Plugin_065_SendCmd(0x06, vol);
|
||||
}
|
||||
|
||||
void Plugin_065_SetEQ(int8_t eq)
|
||||
{
|
||||
if (eq < 0) eq = 0;
|
||||
if (eq > 5) eq = 5;
|
||||
Plugin_065_SendCmd(0x07, eq);
|
||||
}
|
||||
|
||||
void Plugin_065_SendCmd(byte cmd, int16_t data)
|
||||
{
|
||||
if (!Plugin_065_SoftSerial)
|
||||
return;
|
||||
|
||||
byte buffer[10] = { 0x7E, 0xFF, 0x06, 0, 0x00, 0, 0, 0, 0, 0xEF };
|
||||
|
||||
buffer[3] = cmd;
|
||||
buffer[5] = data >> 8; // high byte
|
||||
buffer[6] = data & 0xFF; // low byte
|
||||
|
||||
int16_t checksum = -(buffer[1] + buffer[2] + buffer[3] + buffer[4] + buffer[5] + buffer[6]);
|
||||
buffer[7] = checksum >> 8; // high byte
|
||||
buffer[8] = checksum & 0xFF; // low byte
|
||||
|
||||
Plugin_065_SoftSerial->write(buffer, 10); //Send the byte array
|
||||
|
||||
String log = F("MP3 : Send Cmd ");
|
||||
for (byte i=0; i<10; i++)
|
||||
{
|
||||
log += String(buffer[i], 16);
|
||||
log += F(" ");
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,236 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 066: VEML6040 RGBW ##############################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan color values (RGBW) with chip VEML6040
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Datasheet: https://www.vishay.com/docs/84276/veml6040.pdf
|
||||
// Application Note: www.vishay.com/doc?84331
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_066
|
||||
#define PLUGIN_ID_066 66
|
||||
#define PLUGIN_NAME_066 "Color - VEML6040 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_066 "R"
|
||||
#define PLUGIN_VALUENAME2_066 "G"
|
||||
#define PLUGIN_VALUENAME3_066 "B"
|
||||
#define PLUGIN_VALUENAME4_066 "W"
|
||||
|
||||
#define VEML6040_ADDR 0x10
|
||||
|
||||
// #include <*.h> // no include needed
|
||||
#include <math.h> // no include needed
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
|
||||
boolean Plugin_066(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_066;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_QUAD;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 4;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = false;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_066);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_066));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_066));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_066));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_066));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
int optionValues[1] = { VEML6040_ADDR };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 1, optionValues, VEML6040_ADDR); //Only for display I2C address
|
||||
|
||||
String optionsMode[6] = { F("40ms (16496)"), F("80ms (8248)"), F("160ms (4124)"), F("320ms (2062)"), F("640ms (1031)"), F("1280ms (515)") };
|
||||
addFormSelector(string, F("Integration Time (Max Lux)"), F("itime"), 6, optionsMode, NULL, CONFIG(1));
|
||||
|
||||
String optionsVarMap[6] = {
|
||||
F("R, G, B, W"),
|
||||
F("r, g, b, W - relative rgb [%]"),
|
||||
F("r, g, b, W - relative rgb^Gamma [%]"),
|
||||
F("R, G, B, Color Temperature [K]"),
|
||||
F("R, G, B, Ambient Light [Lux]"),
|
||||
F("Color Temperature [K], Ambient Light [Lux], Y, W") };
|
||||
addFormSelector(string, F("Value Mapping"), F("map"), 6, optionsVarMap, NULL, CONFIG(2));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
//CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
CONFIG(1) = getFormItemInt(F("itime"));
|
||||
CONFIG(2) = getFormItemInt(F("map"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
VEML6040_Init(CONFIG(1));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
float R, G, B, W;
|
||||
|
||||
R = VEML6040_GetValue(0x08);
|
||||
G = VEML6040_GetValue(0x09);
|
||||
B = VEML6040_GetValue(0x0A);
|
||||
W = VEML6040_GetValue(0x0B);
|
||||
|
||||
switch (CONFIG(2))
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = R;
|
||||
UserVar[event->BaseVarIndex + 1] = G;
|
||||
UserVar[event->BaseVarIndex + 2] = B;
|
||||
UserVar[event->BaseVarIndex + 3] = W;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_066_CalcRelW(R, W) * 100.0;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_066_CalcRelW(G, W) * 100.0;
|
||||
UserVar[event->BaseVarIndex + 2] = Plugin_066_CalcRelW(B, W) * 100.0;
|
||||
UserVar[event->BaseVarIndex + 3] = W;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = pow(Plugin_066_CalcRelW(R, W), 0.4545) * 100.0;
|
||||
UserVar[event->BaseVarIndex + 1] = pow(Plugin_066_CalcRelW(G, W), 0.4545) * 100.0;
|
||||
UserVar[event->BaseVarIndex + 2] = pow(Plugin_066_CalcRelW(B, W), 0.4545) * 100.0;
|
||||
UserVar[event->BaseVarIndex + 3] = W;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = R;
|
||||
UserVar[event->BaseVarIndex + 1] = G;
|
||||
UserVar[event->BaseVarIndex + 2] = B;
|
||||
UserVar[event->BaseVarIndex + 3] = Plugin_066_CalcCCT(R, G, B);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = R;
|
||||
UserVar[event->BaseVarIndex + 1] = G;
|
||||
UserVar[event->BaseVarIndex + 2] = B;
|
||||
UserVar[event->BaseVarIndex + 3] = Plugin_066_CalcAmbientLight(G, CONFIG(1));
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_066_CalcCCT(R, G, B);
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_066_CalcAmbientLight(G, CONFIG(1));
|
||||
UserVar[event->BaseVarIndex + 2] = (R + G + B) / 3.0; //0.299*R + 0.587*G + 0.114*B;
|
||||
UserVar[event->BaseVarIndex + 3] = W;
|
||||
break;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
// VEML6040 /////////////////////////////////////////////////////////////
|
||||
|
||||
void VEML6040_setControlReg(byte data)
|
||||
{
|
||||
Wire.beginTransmission(VEML6040_ADDR);
|
||||
Wire.write(0); //command 0=control register
|
||||
Wire.write(data); //lsb
|
||||
Wire.write(0); //msb
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
float VEML6040_GetValue(byte reg)
|
||||
{
|
||||
Wire.beginTransmission(VEML6040_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission(false);
|
||||
Wire.requestFrom((uint8_t)VEML6040_ADDR, (uint8_t)0x2);
|
||||
if (Wire.available() == 2)
|
||||
{
|
||||
uint16_t lsb = Wire.read();
|
||||
uint16_t msb = Wire.read();
|
||||
return (float)((msb << 8) | lsb);
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
void VEML6040_Init(byte it)
|
||||
{
|
||||
VEML6040_setControlReg(it << 4); // IT=it, TRIG=0, AF=0, SD=0
|
||||
}
|
||||
|
||||
|
||||
float Plugin_066_CalcCCT(float R, float G, float B)
|
||||
{
|
||||
if (G == 0)
|
||||
return 0;
|
||||
|
||||
float CCTi = (R - B) / G + 0.5;
|
||||
float CCT = 4278.6 * pow(CCTi, -1.2455);
|
||||
return CCT;
|
||||
}
|
||||
|
||||
float Plugin_066_CalcAmbientLight(float G, byte it)
|
||||
{
|
||||
float Sensitivity[6] = { 0.25168, 0.12584, 0.06292, 0.03146, 0.01573, 0.007865 };
|
||||
|
||||
return G * Sensitivity[it];
|
||||
}
|
||||
|
||||
float Plugin_066_CalcRelW(float X, float W)
|
||||
{
|
||||
if (W == 0)
|
||||
return 0;
|
||||
|
||||
return X / W;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,290 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 063: _P067_HX711_Load_Cell ################################
|
||||
//#######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to scan a 24 bit AD value from a load cell chip HX711
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Electronics:
|
||||
// Connect SCL to 1st GPIO and DOUT to 2nd GPIO. Use 3.3 volt for VCC.
|
||||
|
||||
// Datasheet: https://cdn.sparkfun.com/datasheets/Sensors/ForceFlex/hx711_english.pdf
|
||||
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_067
|
||||
#define PLUGIN_ID_067 67
|
||||
#define PLUGIN_NAME_067 "HX711 Load Cell [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_067 "Weight"
|
||||
|
||||
// #include <*.h> no lib required
|
||||
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
#ifndef PIN
|
||||
#define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex])
|
||||
#endif
|
||||
|
||||
int32_t Plugin_067_OversamplingValue = 0;
|
||||
int16_t Plugin_067_OversamplingCount = 0;
|
||||
|
||||
|
||||
void initHX711(int16_t pinSCL, int16_t pinDOUT)
|
||||
{
|
||||
digitalWrite(pinSCL, LOW);
|
||||
pinMode(pinSCL, OUTPUT);
|
||||
|
||||
pinMode(pinDOUT, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
|
||||
boolean isReadyHX711(int16_t pinSCL, int16_t pinDOUT)
|
||||
{
|
||||
return (!digitalRead(pinDOUT));
|
||||
}
|
||||
|
||||
int32_t readHX711(int16_t pinSCL, int16_t pinDOUT, uint8_t mode)
|
||||
{
|
||||
int32_t value = 0;
|
||||
int32_t mask = 0x00800000;
|
||||
|
||||
for (byte i = 0; i < 24; i++)
|
||||
{
|
||||
digitalWrite(pinSCL, HIGH);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(pinSCL, LOW);
|
||||
if (digitalRead(pinDOUT))
|
||||
value |= mask;
|
||||
delayMicroseconds(1);
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
for (byte i = 0; i < (mode+1); i++)
|
||||
{
|
||||
digitalWrite(pinSCL, HIGH);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(pinSCL, LOW);
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
|
||||
if (value & 0x00800000) //negative?
|
||||
value |= 0xFF000000; //expand sign bit to 32 bit
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
boolean Plugin_067(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_067;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = false;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_067);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_067));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO → SCL");
|
||||
event->String2 = F("GPIO ← DOUT");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormSubHeader(string, F("Measurement"));
|
||||
|
||||
addFormCheckBox(string, F("Oversampling"), F("oversampling"), CONFIG(0));
|
||||
|
||||
String optionsMode[3] = { F("Channel A, Gain 128"), F("Channel B, Gain 32"), F("Channel A, Gain 64") };
|
||||
addFormSelector(string, F("Mode"), F("mode"), 3, optionsMode, NULL, CONFIG(1));
|
||||
|
||||
addFormTextBox(string, F("Offset"), F("Plugin_067_offset"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][3], 3), 25);
|
||||
string += F(" ↩ Tare: ");
|
||||
addCheckBox(string, F("tare"), 0); //always off
|
||||
|
||||
addFormSubHeader(string, F("Two Point Calibration"));
|
||||
|
||||
addFormCheckBox(string, F("Calibration Enabled"), F("Plugin_067_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
|
||||
|
||||
addFormNumericBox(string, F("Point 1"), F("Plugin_067_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0]);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("Plugin_067_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
|
||||
|
||||
addFormNumericBox(string, F("Point 2"), F("Plugin_067_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1]);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("Plugin_067_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = isFormItemChecked(F("oversampling"));
|
||||
|
||||
CONFIG(1) = getFormItemInt(F("mode"));
|
||||
|
||||
if (isFormItemChecked(F("tare")))
|
||||
{
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][3] = -UserVar[event->BaseVarIndex + 1];
|
||||
Plugin_067_OversamplingValue = 0;
|
||||
Plugin_067_OversamplingCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][3] = getFormItemFloat(F("Plugin_067_offset"));
|
||||
}
|
||||
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = isFormItemChecked(F("Plugin_067_cal"));
|
||||
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][0] = getFormItemInt(F("Plugin_067_adc1"));
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = getFormItemFloat(F("Plugin_067_out1"));
|
||||
|
||||
Settings.TaskDevicePluginConfigLong[event->TaskIndex][1] = getFormItemInt(F("Plugin_067_adc2"));
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = getFormItemFloat(F("Plugin_067_out2"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
int16_t pinSCL = PIN(0);
|
||||
int16_t pinDOUT = PIN(1);
|
||||
|
||||
String log = F("HX711: GPIO: SCL=");
|
||||
log += pinSCL;
|
||||
log += F(" DOUT=");
|
||||
log += pinDOUT;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (pinSCL >= 0 && pinDOUT >= 0)
|
||||
{
|
||||
initHX711(pinSCL, pinDOUT);
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_FIFTY_PER_SECOND:
|
||||
{
|
||||
int16_t pinSCL = PIN(0);
|
||||
int16_t pinDOUT = PIN(1);
|
||||
|
||||
if (Plugin_067_OversamplingCount < 250)
|
||||
if (pinSCL >= 0 && pinDOUT >= 0)
|
||||
if (isReadyHX711(pinSCL, pinDOUT))
|
||||
{
|
||||
int32_t value = readHX711(pinSCL, pinDOUT, CONFIG(1));
|
||||
|
||||
if (CONFIG(0)) //Oversampling?
|
||||
{
|
||||
Plugin_067_OversamplingValue += value;
|
||||
Plugin_067_OversamplingCount ++;
|
||||
}
|
||||
else //use last value
|
||||
{
|
||||
Plugin_067_OversamplingValue = value;
|
||||
Plugin_067_OversamplingCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
String log = F("HX711: Value: ");
|
||||
|
||||
if (Plugin_067_OversamplingCount > 0)
|
||||
{
|
||||
UserVar[event->BaseVarIndex + 1] = (float)Plugin_067_OversamplingValue / Plugin_067_OversamplingCount;
|
||||
Plugin_067_OversamplingValue = 0;
|
||||
Plugin_067_OversamplingCount = 0;
|
||||
|
||||
UserVar[event->BaseVarIndex] = UserVar[event->BaseVarIndex + 1] + Settings.TaskDevicePluginConfigFloat[event->TaskIndex][3]; //Offset
|
||||
|
||||
log += String(UserVar[event->BaseVarIndex], 3);
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][3]) //Calibration?
|
||||
{
|
||||
int adc1 = Settings.TaskDevicePluginConfigLong[event->TaskIndex][0];
|
||||
int adc2 = Settings.TaskDevicePluginConfigLong[event->TaskIndex][1];
|
||||
float out1 = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0];
|
||||
float out2 = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1];
|
||||
if (adc1 != adc2)
|
||||
{
|
||||
float normalized = (float)(UserVar[event->BaseVarIndex] - adc1) / (float)(adc2 - adc1);
|
||||
UserVar[event->BaseVarIndex] = normalized * (out2 - out1) + out1;
|
||||
|
||||
log += F(" = ");
|
||||
log += String(UserVar[event->BaseVarIndex], 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log += F("NO NEW VALUE");
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
|
||||
if (command == F("tare"))
|
||||
{
|
||||
String log = F("HX711: tare");
|
||||
|
||||
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][3] = -UserVar[event->BaseVarIndex + 1];
|
||||
Plugin_067_OversamplingValue = 0;
|
||||
Plugin_067_OversamplingCount = 0;
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
//#######################################################################################################
|
||||
//################ Plugin 68: SHT30/SHT31/SHT35 Temperature and Humidity Sensor (I2C) ###################
|
||||
//#######################################################################################################
|
||||
//######################## Library source code for Arduino by WeMos, 2016 ###############################
|
||||
//#######################################################################################################
|
||||
//###################### Plugin for ESP Easy by B.E.I.C. ELECTRONICS, 2017 ##############################
|
||||
//############################### http://www.beicelectronics.com ########################################
|
||||
//#######################################################################################################
|
||||
//########################## Adapted to ESPEasy 2.0 by Jochen Krapf #####################################
|
||||
//#######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_068
|
||||
#define PLUGIN_ID_068 68
|
||||
#define PLUGIN_NAME_068 "Environment - SHT30/31/35 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_068 "Temperature"
|
||||
#define PLUGIN_VALUENAME2_068 "Humidity"
|
||||
|
||||
//==============================================
|
||||
// SHT3X LIBRARY - SHT3X.h
|
||||
// =============================================
|
||||
# ifndef SHT3X_H
|
||||
# define SHT3X_H
|
||||
|
||||
class SHT3X
|
||||
{
|
||||
public:
|
||||
SHT3X(uint8_t addr);
|
||||
void get(void);
|
||||
float tmp=0;
|
||||
float hum=0;
|
||||
|
||||
private:
|
||||
uint8_t _i2c_device_address;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================
|
||||
// SHT3X LIBRARY - SHT3X.cpp
|
||||
// =============================================
|
||||
SHT3X::SHT3X(uint8_t addr)
|
||||
{
|
||||
_i2c_device_address = addr;
|
||||
//Wire.begin(); called in ESPEasy framework
|
||||
|
||||
// Set to periodic mode
|
||||
Wire.beginTransmission(_i2c_device_address);
|
||||
Wire.write(0x20); // periodic 0.5mps
|
||||
Wire.write(0x32); // repeatability high
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void SHT3X::get()
|
||||
{
|
||||
uint16_t data[6];
|
||||
|
||||
Wire.beginTransmission(_i2c_device_address);
|
||||
Wire.write(0xE0); // fetch data command
|
||||
Wire.write(0x00);
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(_i2c_device_address, (uint8_t)6);
|
||||
if (Wire.available() == 6)
|
||||
{
|
||||
data[0] = Wire.read();
|
||||
data[1] = Wire.read();
|
||||
data[2] = Wire.read();
|
||||
data[3] = Wire.read();
|
||||
data[4] = Wire.read();
|
||||
data[5] = Wire.read();
|
||||
|
||||
//TODO: check CRC
|
||||
|
||||
tmp = ((((data[0] << 8) | data[1]) * 175.0) / 65535.0) - 45.0;
|
||||
hum = ((((data[3] << 8) | data[4]) * 100.0) / 65535.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = NAN;
|
||||
hum = NAN;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
SHT3X* Plugin_068_SHT3x = NULL;
|
||||
|
||||
|
||||
//==============================================
|
||||
// PLUGIN
|
||||
// =============================================
|
||||
|
||||
boolean Plugin_068(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_068;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 2;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_068);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_068));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_068));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
int optionValues[2] = { 0x44, 0x45 };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 2, optionValues, CONFIG(0));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (Plugin_068_SHT3x)
|
||||
delete Plugin_068_SHT3x;
|
||||
Plugin_068_SHT3x = new SHT3X(CONFIG(0));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (!Plugin_068_SHT3x)
|
||||
return success;
|
||||
|
||||
Plugin_068_SHT3x->get();
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_068_SHT3x->tmp;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_068_SHT3x->hum;
|
||||
String log = F("SHT3x: Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex + 0];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("SHT3x: Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,204 @@
|
||||
//#######################################################################################################
|
||||
//########################### Plugin 69: LM75A Temperature Sensor (I2C) #################################
|
||||
//#######################################################################################################
|
||||
//###################### Library source code for Arduino by QuentinCG, 2016 #############################
|
||||
//#######################################################################################################
|
||||
//##################### Plugin for ESP Easy by B.E.I.C. ELECTRONICS, 2017 ###############################
|
||||
//############################## http://www.beicelectronics.com #########################################
|
||||
//#######################################################################################################
|
||||
//########################## Adapted to ESPEasy 2.0 by Jochen Krapf #####################################
|
||||
//#######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_069
|
||||
#define PLUGIN_ID_069 69
|
||||
#define PLUGIN_NAME_069 "Environment - LM75A [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_069 "Temperature"
|
||||
|
||||
|
||||
#ifndef LM75A_h
|
||||
#define LM75A_h
|
||||
|
||||
#define INVALID_LM75A_TEMPERATURE 1000
|
||||
|
||||
namespace LM75AConstValues
|
||||
{
|
||||
const int LM75A_BASE_ADDRESS = 0x48;
|
||||
const float LM75A_DEGREES_RESOLUTION = 0.125;
|
||||
const int LM75A_REG_ADDR_TEMP = 0;
|
||||
}
|
||||
|
||||
using namespace LM75AConstValues;
|
||||
|
||||
class LM75A
|
||||
{
|
||||
public:
|
||||
LM75A(bool A0_value = false, bool A1_value = false, bool A2_value = false)
|
||||
{
|
||||
_i2c_device_address = LM75A_BASE_ADDRESS;
|
||||
|
||||
if (A0_value) {
|
||||
_i2c_device_address += 1;
|
||||
}
|
||||
|
||||
if (A1_value) {
|
||||
_i2c_device_address += 2;
|
||||
}
|
||||
|
||||
if (A2_value) {
|
||||
_i2c_device_address += 4;
|
||||
}
|
||||
|
||||
//Wire.begin(); called in ESPEasy framework
|
||||
}
|
||||
|
||||
LM75A(uint8_t addr)
|
||||
{
|
||||
_i2c_device_address = addr;
|
||||
//Wire.begin(); called in ESPEasy framework
|
||||
}
|
||||
|
||||
float getTemperatureInDegrees() const
|
||||
{
|
||||
float real_result = INVALID_LM75A_TEMPERATURE;
|
||||
int16_t value = 0;
|
||||
|
||||
// Go to temperature data register
|
||||
Wire.beginTransmission(_i2c_device_address);
|
||||
Wire.write(LM75A_REG_ADDR_TEMP);
|
||||
if (Wire.endTransmission())
|
||||
{
|
||||
// Transmission error
|
||||
return real_result;
|
||||
}
|
||||
|
||||
// Get content
|
||||
Wire.requestFrom(_i2c_device_address, (uint8_t)2);
|
||||
if (Wire.available() == 2)
|
||||
{
|
||||
value = (Wire.read() << 8) | Wire.read();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't read temperature
|
||||
return real_result;
|
||||
}
|
||||
|
||||
// Shift data (left-aligned)
|
||||
value >>= 5;
|
||||
|
||||
// Relocate negative bit (11th bit to 16th bit)
|
||||
if (value & 0x0400) // negative?
|
||||
{
|
||||
value |= 0xFC00; // expand to 16 bit
|
||||
}
|
||||
|
||||
// Real value can be calculated with sensor resolution
|
||||
real_result = (float)value * LM75A_DEGREES_RESOLUTION;
|
||||
|
||||
return real_result;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _i2c_device_address;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
LM75A* PLUGIN_069_LM75A = NULL;
|
||||
|
||||
|
||||
boolean Plugin_069(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_069;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_069);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_069));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
int optionValues[8] = { 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F };
|
||||
addFormSelectorI2C(string, F("i2c_addr"), 8, optionValues, CONFIG(0));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = getFormItemInt(F("i2c_addr"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (PLUGIN_069_LM75A)
|
||||
delete PLUGIN_069_LM75A;
|
||||
PLUGIN_069_LM75A = new LM75A((uint8_t)CONFIG(0));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (!PLUGIN_069_LM75A)
|
||||
return success;
|
||||
|
||||
float tempC = PLUGIN_069_LM75A->getTemperatureInDegrees();
|
||||
|
||||
if (tempC == INVALID_LM75A_TEMPERATURE)
|
||||
{
|
||||
String log = F("LM75A: No reading!");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = tempC;
|
||||
String log = F("LM75A: Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,282 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 070: NeoPixel ring clock #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
//This plugin is disabled, change it to PLUGIN_BUILD_NORMAL to re-enable it.
|
||||
#ifdef PLUGIN_BUILD_DISABLED
|
||||
|
||||
//A clock that uses a strip/ring of 60 WS2812 NeoPixel LEDs as display for a classic clock.
|
||||
//The hours are RED, the minutes are GREEN, the seconds are BLUE and the hour marks are WHITE.
|
||||
//The brightness of the clock hands and the hour marks can be set in the device page,
|
||||
//or can be set by commands. The format is as follows:
|
||||
// Clock,<Enabled 1/0>,<Hand brightness 0-255>,<Mark brightness 0-255>
|
||||
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
#define NUMBER_LEDS 60 //number of LED in the strip
|
||||
|
||||
boolean Plugin_070_enabled; //used to enable/disable the display.
|
||||
byte Plugin_070_brightness; //brightness of the clock "hands"
|
||||
byte Plugin_070_marks; //brightness of the hour marks
|
||||
byte Plugin_070_offset; //position of the 12 o'clock LED on the strip
|
||||
boolean thick_12_mark;
|
||||
byte marks[14];
|
||||
|
||||
Adafruit_NeoPixel * Plugin_070_pixels;
|
||||
|
||||
#define PLUGIN_070
|
||||
#define PLUGIN_ID_070 70
|
||||
#define PLUGIN_NAME_070 "Output - NeoPixel Ring Clock [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_070 "Enabled"
|
||||
#define PLUGIN_VALUENAME2_070 "Brightness"
|
||||
#define PLUGIN_VALUENAME3_070 "Marks"
|
||||
boolean Plugin_070(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_070;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_TRIPLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 3;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].GlobalSyncOption = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_070);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_070));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_070));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_070));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = F("GPIO → LED");
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormSubHeader(string, F("Clock configuration"));
|
||||
addFormNumericBox(string, F("12 o'clock LED position"), F("offset"), CONFIG(3), 0, 59);
|
||||
addFormNote(string, F("Position of the 12 o'clock LED in the strip"));
|
||||
addFormCheckBox(string, F("Thick 12 o'clock mark"), F("thick_12_mark"), CONFIG(4));
|
||||
addFormNote(string, F("Check to have 3 LEDs marking the 12 o'clock position"));
|
||||
addFormCheckBox(string, F("Clock display enabled"), F("enabled"), CONFIG(0));
|
||||
addFormNote(string, F("LED activation"));
|
||||
addFormNumericBox(string, F("LED brightness"), F("brightness"), CONFIG(1), 0, 255);
|
||||
addFormNote(string, F("Brightness level of the H/M/S hands (0-255)"));
|
||||
addFormNumericBox(string, F("Hour mark brightness"), F("marks"), CONFIG(2), 0, 255);
|
||||
addFormNote(string, F("Brightness level of the hour marks (0-255)"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
CONFIG(0) = isFormItemChecked(F("enabled"));
|
||||
CONFIG(1) = getFormItemInt(F("brightness"));
|
||||
CONFIG(2) = getFormItemInt(F("marks"));
|
||||
CONFIG(3) = getFormItemInt(F("offset"));
|
||||
CONFIG(4) = isFormItemChecked(F("thick_12_mark"));
|
||||
|
||||
Plugin_070_enabled = CONFIG(0);
|
||||
Plugin_070_brightness = CONFIG(1);
|
||||
Plugin_070_marks = CONFIG(2);
|
||||
Plugin_070_offset = CONFIG(3);
|
||||
thick_12_mark = CONFIG(4);
|
||||
|
||||
calculateMarks();
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (!Plugin_070_pixels)
|
||||
{
|
||||
Plugin_070_pixels = new Adafruit_NeoPixel(NUMBER_LEDS, Settings.TaskDevicePin1[event->TaskIndex], NEO_GRB + NEO_KHZ800);
|
||||
Plugin_070_pixels->begin(); // This initializes the NeoPixel library.
|
||||
}
|
||||
Plugin_070_enabled = CONFIG(0);
|
||||
Plugin_070_brightness = CONFIG(1);
|
||||
Plugin_070_marks = CONFIG(2);
|
||||
Plugin_070_offset = CONFIG(3);
|
||||
thick_12_mark = CONFIG(4);
|
||||
|
||||
calculateMarks();
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_ONCE_A_SECOND:
|
||||
{
|
||||
Clock_update();
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String param1 = parseString(string, 2);
|
||||
String param2 = parseString(string, 3);
|
||||
String param3 = parseString(string, 4);
|
||||
|
||||
if (command == F("clock")) {
|
||||
if (param1 != "") {
|
||||
int val_Mode = param1.toInt();
|
||||
if (val_Mode > -1 && val_Mode < 2) {
|
||||
Plugin_070_enabled = val_Mode;
|
||||
CONFIG(0) = Plugin_070_enabled;
|
||||
}
|
||||
}
|
||||
if (param2 != "") {
|
||||
int val_Bright = param2.toInt();
|
||||
if (val_Bright > -1 && val_Bright < 256) {
|
||||
Plugin_070_brightness = val_Bright;
|
||||
CONFIG(1) = Plugin_070_brightness;
|
||||
}
|
||||
}
|
||||
if (param3 != "") {
|
||||
int val_Marks = param3.toInt();
|
||||
if (val_Marks > -1 && val_Marks < 256) {
|
||||
Plugin_070_marks = val_Marks;
|
||||
CONFIG(2) = Plugin_070_marks;
|
||||
}
|
||||
}
|
||||
/* //Command debuging routine
|
||||
String log = F("Clock: ");
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
log = F(" Enabled = ");
|
||||
log += param1;
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
log = F(" Brightness = ");
|
||||
log += param2;
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
log = F(" Marks = ");
|
||||
log += param3;
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
*/
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = Plugin_070_enabled;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_070_brightness;
|
||||
UserVar[event->BaseVarIndex + 2] = Plugin_070_marks;
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void Clock_update()
|
||||
{
|
||||
clearClock(); //turn off the LEDs
|
||||
if (Plugin_070_enabled > 0) { //if the display is enabled, calculate the LEDs to turn on
|
||||
int Hours = hour();
|
||||
int Minutes = minute();
|
||||
int Seconds = second();
|
||||
timeToStrip(Hours, Minutes, Seconds);
|
||||
}
|
||||
Plugin_070_pixels->show(); // This sends the updated pixel color to the hardware.
|
||||
}
|
||||
|
||||
void calculateMarks()
|
||||
{ //generate a list of the LEDs that have hour marks
|
||||
for (int i = 0; i < 12; i++) {
|
||||
marks[i] = 5 * i + (Plugin_070_offset % 5);
|
||||
}
|
||||
if (thick_12_mark) {
|
||||
if (Plugin_070_offset == 0) {
|
||||
marks[12] = 1;
|
||||
marks[13] = 59;
|
||||
}
|
||||
else if (Plugin_070_offset == 59) {
|
||||
marks[12] = 0;
|
||||
marks[13] = 58;
|
||||
}
|
||||
else {
|
||||
marks[12] = Plugin_070_offset + 1;
|
||||
marks[13] = Plugin_070_offset - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
marks[12] = 255;
|
||||
marks[13] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
void clearClock() {
|
||||
for (int i = 0; i < NUMBER_LEDS; i++) {
|
||||
Plugin_070_pixels->setPixelColor(i, Plugin_070_pixels->Color(0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void timeToStrip(int hours, int minutes, int seconds) {
|
||||
if (hours > 11) hours = hours - 12;
|
||||
hours = (hours * 5) + (minutes / 12) + Plugin_070_offset; //make the hour hand move each 12 minutes and apply the offset
|
||||
if (hours > 59) hours = hours - 60;
|
||||
minutes = minutes + Plugin_070_offset; //apply offset to minutes
|
||||
if (minutes > 59) minutes = minutes - 60;
|
||||
seconds = seconds + Plugin_070_offset; //apply offset to seconds
|
||||
if (seconds > 59) seconds = seconds - 60;
|
||||
for (int i = 0 ; i < 14; i ++) { //set the hour marks as white;
|
||||
if ((marks[i] != hours) && (marks[i] != minutes) && (marks[i] != seconds) && (marks[i] != 255)) { //do not draw a mark there is a clock hand in that position
|
||||
Plugin_070_pixels->setPixelColor(marks[i], Plugin_070_pixels->Color(Plugin_070_marks, Plugin_070_marks, Plugin_070_marks));
|
||||
}
|
||||
}
|
||||
uint32_t currentColor;
|
||||
uint8_t r_val, g_val, b_val;
|
||||
for (int i = 0; i < NUMBER_LEDS; i++) { //draw the clock hands, adding the colors together
|
||||
if (i == hours) { //hours hand is RED
|
||||
Plugin_070_pixels->setPixelColor(i, Plugin_070_pixels->Color(Plugin_070_brightness, 0, 0));
|
||||
}
|
||||
if (i == minutes) { //minutes hand is GREEN
|
||||
currentColor = Plugin_070_pixels->getPixelColor(i);
|
||||
r_val = (uint8_t)(currentColor >> 16);
|
||||
Plugin_070_pixels->setPixelColor(i, Plugin_070_pixels->Color(r_val, Plugin_070_brightness, 0));
|
||||
}
|
||||
if (i == seconds) { //seconds hand is BLUE
|
||||
currentColor = Plugin_070_pixels->getPixelColor(i);
|
||||
r_val = (uint8_t)(currentColor >> 16);
|
||||
g_val = (uint8_t)(currentColor >> 8);
|
||||
Plugin_070_pixels->setPixelColor(i, Plugin_070_pixels->Color(r_val, g_val, Plugin_070_brightness));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,267 @@
|
||||
//#######################################################################################################
|
||||
//############################# Plugin 071: Kamstrup Multical 401 #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
//IR RX/TX sensor based on http://wiki.hal9k.dk/projects/kamstrup
|
||||
//schematic http://wiki.hal9k.dk/_media/projects/kamstrup/schematic.pdf
|
||||
//software based on http://elektronikforumet.com/forum/viewtopic.php?f=2&t=79853
|
||||
|
||||
//Device pin 1 = RX
|
||||
//Device pin 2 = TX
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#define PLUGIN_071
|
||||
#define PLUGIN_ID_071 071
|
||||
#define PLUGIN_NAME_071 "Kamstrup Multical 401 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_071 "Heat"
|
||||
#define PLUGIN_VALUENAME2_071 "Volume"
|
||||
|
||||
boolean Plugin_071_init = false;
|
||||
byte PIN_KAMSER_RX = 0;
|
||||
byte PIN_KAMSER_TX = 0;
|
||||
|
||||
boolean Plugin_071(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_071;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_DUAL;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 2;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_071);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_071));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_071));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Plugin_071_init = true;
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
PIN_KAMSER_RX = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
PIN_KAMSER_TX = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
|
||||
SoftwareSerial kamSer(PIN_KAMSER_RX, PIN_KAMSER_TX, false); // Initialize serial
|
||||
|
||||
pinMode(PIN_KAMSER_RX,INPUT);
|
||||
pinMode(PIN_KAMSER_TX,OUTPUT);
|
||||
|
||||
//read Kamstrup
|
||||
byte sendmsg1[] = { 175,163,177 }; // /#1 with even parity
|
||||
|
||||
byte r = 0;
|
||||
byte to = 0;
|
||||
byte i;
|
||||
char message[255];
|
||||
int parityerrors;
|
||||
|
||||
|
||||
kamSer.begin(300);
|
||||
for (int x = 0; x < 3; x++) {
|
||||
kamSer.write(sendmsg1[x]);
|
||||
}
|
||||
|
||||
kamSer.flush();
|
||||
//kamSer.end();
|
||||
kamSer.begin(1200);
|
||||
|
||||
to = 0;
|
||||
r = 0;
|
||||
i = 0;
|
||||
parityerrors = 0;
|
||||
char *tmpstr;
|
||||
double m_energy, m_volume;
|
||||
float m_tempin, m_tempout, m_tempdiff, m_power;
|
||||
long m_hours, m_flow;
|
||||
|
||||
while(r != 0x0A)
|
||||
{
|
||||
if (kamSer.available())
|
||||
{
|
||||
// receive byte
|
||||
r = kamSer.read();
|
||||
//Serial.println(r);
|
||||
if (parity_check(r))
|
||||
{
|
||||
parityerrors += 1;
|
||||
}
|
||||
r = r & 127; // Mask MSB to remove parity
|
||||
|
||||
message[i++] = char(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
to++;
|
||||
delay(25);
|
||||
}
|
||||
|
||||
if (i>=79)
|
||||
{
|
||||
if ( parityerrors == 0 )
|
||||
{
|
||||
// Serial.print("OK: " );
|
||||
// Serial.println(message);
|
||||
message[i] = 0;
|
||||
|
||||
tmpstr = strtok(message, " ");
|
||||
if (tmpstr){
|
||||
m_energy = atol(tmpstr)/3.6*1000;
|
||||
}
|
||||
else
|
||||
m_energy = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_volume = atol(tmpstr);
|
||||
else
|
||||
m_volume = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_hours = atol(tmpstr);
|
||||
else
|
||||
m_hours = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_tempin = atol(tmpstr)/100.0;
|
||||
else
|
||||
m_tempin = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_tempout = atol(tmpstr)/100.0;
|
||||
else
|
||||
m_tempout = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_tempdiff = atol(tmpstr)/100.0;
|
||||
else
|
||||
m_tempdiff = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_power = atol(tmpstr)/10.0;
|
||||
else
|
||||
m_power = 0;
|
||||
|
||||
tmpstr = strtok(NULL, " ");
|
||||
if (tmpstr)
|
||||
m_flow = atol(tmpstr);
|
||||
else
|
||||
m_flow = 0;
|
||||
|
||||
// String log = F("Kamstrup output: ");
|
||||
// log += m_energy;
|
||||
// log += F(" MJ; ");
|
||||
// log += m_volume;
|
||||
// log += F(" L; ");
|
||||
// log += m_hours;
|
||||
// log += F(" h; ");
|
||||
// log += m_tempin;
|
||||
// log += F(" C; ");
|
||||
// log += m_tempout;
|
||||
// log += F(" C; ");
|
||||
// log += m_tempdiff;
|
||||
// log += F(" C; ");
|
||||
// log += m_power;
|
||||
// log += F(" ");
|
||||
// log += m_flow;
|
||||
// log += F(" L/H");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
UserVar[event->BaseVarIndex] = m_energy; //gives energy in Wh
|
||||
UserVar[event->BaseVarIndex+1] = m_volume; //gives volume in liters
|
||||
|
||||
String log = F("Kamstrup : Heat value: ");
|
||||
log += m_energy/1000;
|
||||
log += F(" kWh");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("Kamstrup : Volume value: ");
|
||||
log += m_volume;
|
||||
log += F(" Liter");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
else
|
||||
{
|
||||
message[i] = 0;
|
||||
String log = F("ERR(PARITY):" );
|
||||
Serial.print("par");
|
||||
log += message;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
//UserVar[event->BaseVarIndex] = NAN;
|
||||
//UserVar[event->BaseVarIndex + 1] = NAN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (to>100)
|
||||
{
|
||||
message[i] = 0;
|
||||
String log = F("ERR(TIMEOUT):" );
|
||||
log += message;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
//UserVar[event->BaseVarIndex] = NAN;
|
||||
//UserVar[event->BaseVarIndex + 1] = NAN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//end read Kamstrup
|
||||
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool parity_check(unsigned input) {
|
||||
bool inputparity = input & 128;
|
||||
int x = input & 127;
|
||||
|
||||
int parity = 0;
|
||||
while(x != 0) {
|
||||
parity ^= x;
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
if ( parity & 0x1 != inputparity )
|
||||
return(1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
//######################################################################################################
|
||||
//####################### Plugin 072: Temperature and Humidity sensor HDC1080 (I2C) ####################
|
||||
//######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_072
|
||||
#define PLUGIN_ID_072 72
|
||||
#define PLUGIN_NAME_072 "Environment - HDC1080 (I2C) [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_072 "Temperature"
|
||||
#define PLUGIN_VALUENAME2_072 "Humidity"
|
||||
|
||||
boolean Plugin_072_init = false;
|
||||
|
||||
#define HDC1080_I2C_ADDRESS 0x40 // I2C address for the sensor
|
||||
|
||||
boolean Plugin_072(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_072;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_I2C;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 2;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_072);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_072));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_072));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
byte hdc1080_msb, hdc1080_lsb;
|
||||
uint16_t hdc1080_rawtemp, hdc1080_rawhum;
|
||||
float hdc1080_temp, hdc1080_hum;
|
||||
|
||||
Wire.beginTransmission(HDC1080_I2C_ADDRESS); // start transmission to device
|
||||
Wire.write(0x02); // sends HDC1080_CONFIGURATION
|
||||
Wire.write(0b00000000); // set resolution to 14bits both for T and H
|
||||
Wire.write(0x00); // **reserved**
|
||||
Wire.endTransmission(); // end transmission
|
||||
delay(10);
|
||||
|
||||
Wire.beginTransmission(HDC1080_I2C_ADDRESS); // start transmission to device
|
||||
Wire.write(0x00); // sends HDC1080_TEMPERATURE
|
||||
Wire.endTransmission(); // end transmission
|
||||
delay(9);
|
||||
Wire.requestFrom(HDC1080_I2C_ADDRESS, 2); // read 2 bytes for temperature
|
||||
hdc1080_msb = Wire.read();
|
||||
hdc1080_lsb = Wire.read();
|
||||
hdc1080_rawtemp = hdc1080_msb << 8 | hdc1080_lsb;
|
||||
hdc1080_temp = (hdc1080_rawtemp / pow(2,16)) * 165 -40;
|
||||
|
||||
Wire.beginTransmission(HDC1080_I2C_ADDRESS); // start transmission to device
|
||||
Wire.write(0x01); // sends HDC1080_HUMIDITY
|
||||
Wire.endTransmission(); // end transmission
|
||||
delay(9);
|
||||
Wire.requestFrom(HDC1080_I2C_ADDRESS, 2); // read 2 bytes for humidity
|
||||
hdc1080_msb = Wire.read();
|
||||
hdc1080_lsb = Wire.read();
|
||||
hdc1080_rawhum = hdc1080_msb << 8 | hdc1080_lsb;
|
||||
hdc1080_hum = (hdc1080_rawhum / pow(2,16)) * 100;
|
||||
|
||||
UserVar[event->BaseVarIndex] = hdc1080_temp;
|
||||
UserVar[event->BaseVarIndex + 1] = hdc1080_hum;
|
||||
String log = F("HDC1080: Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("HDC1080: Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
+43
-27
@@ -2,6 +2,23 @@
|
||||
// Initialize all Controller CPlugins that where defined earlier
|
||||
// and initialize the function call pointer into the CCPlugin array
|
||||
//********************************************************************************
|
||||
|
||||
static const char ADDCPLUGIN_ERROR[] PROGMEM = "System: Error - To much C-Plugins";
|
||||
|
||||
// Because of compiler-bug (multiline defines gives an error if file ending is CRLF) the define is striped to a single line
|
||||
/*
|
||||
#define ADDCPLUGIN(NNN) \
|
||||
if (x < CPLUGIN_MAX) \
|
||||
{ \
|
||||
CPlugin_id[x] = CPLUGIN_ID_##NNN; \
|
||||
CPlugin_ptr[x++] = &CPlugin_##NNN; \
|
||||
} \
|
||||
else \
|
||||
addLog(LOG_LEVEL_ERROR, FPSTR(ADDCPLUGIN_ERROR));
|
||||
*/
|
||||
#define ADDCPLUGIN(NNN) if (x < CPLUGIN_MAX) { CPlugin_id[x] = CPLUGIN_ID_##NNN; CPlugin_ptr[x++] = &CPlugin_##NNN; } else addLog(LOG_LEVEL_ERROR, FPSTR(ADDCPLUGIN_ERROR));
|
||||
|
||||
|
||||
void CPluginInit(void)
|
||||
{
|
||||
byte x;
|
||||
@@ -16,103 +33,103 @@ void CPluginInit(void)
|
||||
x = 0;
|
||||
|
||||
#ifdef CPLUGIN_001
|
||||
CPlugin_id[x] = 1; CPlugin_ptr[x++] = &CPlugin_001;
|
||||
ADDCPLUGIN(001)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_002
|
||||
CPlugin_id[x] = 2; CPlugin_ptr[x++] = &CPlugin_002;
|
||||
ADDCPLUGIN(002)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_003
|
||||
CPlugin_id[x] = 3; CPlugin_ptr[x++] = &CPlugin_003;
|
||||
ADDCPLUGIN(003)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_004
|
||||
CPlugin_id[x] = 4; CPlugin_ptr[x++] = &CPlugin_004;
|
||||
ADDCPLUGIN(004)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_005
|
||||
CPlugin_id[x] = 5; CPlugin_ptr[x++] = &CPlugin_005;
|
||||
ADDCPLUGIN(005)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_006
|
||||
CPlugin_id[x] = 6; CPlugin_ptr[x++] = &CPlugin_006;
|
||||
ADDCPLUGIN(006)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_007
|
||||
CPlugin_id[x] = 7; CPlugin_ptr[x++] = &CPlugin_007;
|
||||
ADDCPLUGIN(007)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_008
|
||||
CPlugin_id[x] = 8; CPlugin_ptr[x++] = &CPlugin_008;
|
||||
ADDCPLUGIN(008)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_009
|
||||
CPlugin_id[x] = 9; CPlugin_ptr[x++] = &CPlugin_009;
|
||||
ADDCPLUGIN(009)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_010
|
||||
CPlugin_id[x] = 10; CPlugin_ptr[x++] = &CPlugin_010;
|
||||
ADDCPLUGIN(010)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_011
|
||||
CPlugin_id[x] = 11; CPlugin_ptr[x++] = &CPlugin_011;
|
||||
ADDCPLUGIN(011)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_012
|
||||
CPlugin_id[x] = 12; CPlugin_ptr[x++] = &CPlugin_012;
|
||||
ADDCPLUGIN(012)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_013
|
||||
CPlugin_id[x] = 13; CPlugin_ptr[x++] = &CPlugin_013;
|
||||
ADDCPLUGIN(013)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_014
|
||||
CPlugin_id[x] = 14; CPlugin_ptr[x++] = &CPlugin_014;
|
||||
ADDCPLUGIN(014)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_015
|
||||
CPlugin_id[x] = 15; CPlugin_ptr[x++] = &CPlugin_015;
|
||||
ADDCPLUGIN(015)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_016
|
||||
CPlugin_id[x] = 16; CPlugin_ptr[x++] = &CPlugin_016;
|
||||
ADDCPLUGIN(016)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_017
|
||||
CPlugin_id[x] = 17; CPlugin_ptr[x++] = &CPlugin_017;
|
||||
ADDCPLUGIN(017)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_018
|
||||
CPlugin_id[x] = 18; CPlugin_ptr[x++] = &CPlugin_018;
|
||||
ADDCPLUGIN(018)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_019
|
||||
CPlugin_id[x] = 19; CPlugin_ptr[x++] = &CPlugin_019;
|
||||
ADDCPLUGIN(019)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_020
|
||||
CPlugin_id[x] = 20; CPlugin_ptr[x++] = &CPlugin_020;
|
||||
ADDCPLUGIN(020)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_021
|
||||
CPlugin_id[x] = 21; CPlugin_ptr[x++] = &CPlugin_021;
|
||||
ADDCPLUGIN(021)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_022
|
||||
CPlugin_id[x] = 22; CPlugin_ptr[x++] = &CPlugin_022;
|
||||
ADDCPLUGIN(022)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_023
|
||||
CPlugin_id[x] = 23; CPlugin_ptr[x++] = &CPlugin_023;
|
||||
ADDCPLUGIN(023)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_024
|
||||
CPlugin_id[x] = 24; CPlugin_ptr[x++] = &CPlugin_024;
|
||||
ADDCPLUGIN(024)
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_025
|
||||
CPlugin_id[x] = 25; CPlugin_ptr[x++] = &CPlugin_025;
|
||||
ADDCPLUGIN(025)
|
||||
#endif
|
||||
|
||||
CPluginCall(CPLUGIN_PROTOCOL_ADD, 0);
|
||||
@@ -125,7 +142,7 @@ byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
|
||||
if (event == 0)
|
||||
event=&TempEvent;
|
||||
|
||||
|
||||
switch (Function)
|
||||
{
|
||||
// Unconditional calls to all plugins
|
||||
@@ -139,4 +156,3 @@ byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+43
-27
@@ -2,6 +2,23 @@
|
||||
// Initialize all Controller NPlugins that where defined earlier
|
||||
// and initialize the function call pointer into the CNPlugin array
|
||||
//********************************************************************************
|
||||
|
||||
static const char ADDNPLUGIN_ERROR[] PROGMEM = "System: Error - To much N-Plugins";
|
||||
|
||||
// Because of compiler-bug (multiline defines gives an error if file ending is CRLF) the define is striped to a single line
|
||||
/*
|
||||
#define ADDNPLUGIN(NNN) \
|
||||
if (x < NPLUGIN_MAX) \
|
||||
{ \
|
||||
NPlugin_id[x] = NPLUGIN_ID_##NNN; \
|
||||
NPlugin_ptr[x++] = &NPlugin_##NNN; \
|
||||
} \
|
||||
else \
|
||||
addLog(LOG_LEVEL_ERROR, FPSTR(ADDNPLUGIN_ERROR));
|
||||
*/
|
||||
#define ADDNPLUGIN(NNN) if (x < NPLUGIN_MAX) { NPlugin_id[x] = NPLUGIN_ID_##NNN; NPlugin_ptr[x++] = &NPlugin_##NNN; } else addLog(LOG_LEVEL_ERROR, FPSTR(ADDNPLUGIN_ERROR));
|
||||
|
||||
|
||||
void NPluginInit(void)
|
||||
{
|
||||
byte x;
|
||||
@@ -16,103 +33,103 @@ void NPluginInit(void)
|
||||
x = 0;
|
||||
|
||||
#ifdef NPLUGIN_001
|
||||
NPlugin_id[x] = 1; NPlugin_ptr[x++] = &NPlugin_001;
|
||||
ADDNPLUGIN(001)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_002
|
||||
NPlugin_id[x] = 2; NPlugin_ptr[x++] = &NPlugin_002;
|
||||
ADDNPLUGIN(002)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_003
|
||||
NPlugin_id[x] = 3; NPlugin_ptr[x++] = &NPlugin_003;
|
||||
ADDNPLUGIN(003)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_004
|
||||
NPlugin_id[x] = 4; NPlugin_ptr[x++] = &NPlugin_004;
|
||||
ADDNPLUGIN(004)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_005
|
||||
NPlugin_id[x] = 5; NPlugin_ptr[x++] = &NPlugin_005;
|
||||
ADDNPLUGIN(005)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_006
|
||||
NPlugin_id[x] = 6; NPlugin_ptr[x++] = &NPlugin_006;
|
||||
ADDNPLUGIN(006)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_007
|
||||
NPlugin_id[x] = 7; NPlugin_ptr[x++] = &NPlugin_007;
|
||||
ADDNPLUGIN(007)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_008
|
||||
NPlugin_id[x] = 8; NPlugin_ptr[x++] = &NPlugin_008;
|
||||
ADDNPLUGIN(008)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_009
|
||||
NPlugin_id[x] = 9; NPlugin_ptr[x++] = &NPlugin_009;
|
||||
ADDNPLUGIN(009)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_010
|
||||
NPlugin_id[x] = 10; NPlugin_ptr[x++] = &NPlugin_010;
|
||||
ADDNPLUGIN(010)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_011
|
||||
NPlugin_id[x] = 11; NPlugin_ptr[x++] = &NPlugin_011;
|
||||
ADDNPLUGIN(011)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_012
|
||||
NPlugin_id[x] = 12; NPlugin_ptr[x++] = &NPlugin_012;
|
||||
ADDNPLUGIN(012)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_013
|
||||
NPlugin_id[x] = 13; NPlugin_ptr[x++] = &NPlugin_013;
|
||||
ADDNPLUGIN(013)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_014
|
||||
NPlugin_id[x] = 14; NPlugin_ptr[x++] = &NPlugin_014;
|
||||
ADDNPLUGIN(014)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_015
|
||||
NPlugin_id[x] = 15; NPlugin_ptr[x++] = &NPlugin_015;
|
||||
ADDNPLUGIN(015)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_016
|
||||
NPlugin_id[x] = 16; NPlugin_ptr[x++] = &NPlugin_016;
|
||||
ADDNPLUGIN(016)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_017
|
||||
NPlugin_id[x] = 17; NPlugin_ptr[x++] = &NPlugin_017;
|
||||
ADDNPLUGIN(017)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_018
|
||||
NPlugin_id[x] = 18; NPlugin_ptr[x++] = &NPlugin_018;
|
||||
ADDNPLUGIN(018)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_019
|
||||
NPlugin_id[x] = 19; NPlugin_ptr[x++] = &NPlugin_019;
|
||||
ADDNPLUGIN(019)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_020
|
||||
NPlugin_id[x] = 20; NPlugin_ptr[x++] = &NPlugin_020;
|
||||
ADDNPLUGIN(020)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_021
|
||||
NPlugin_id[x] = 21; NPlugin_ptr[x++] = &NPlugin_021;
|
||||
ADDNPLUGIN(021)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_022
|
||||
NPlugin_id[x] = 22; NPlugin_ptr[x++] = &NPlugin_022;
|
||||
ADDNPLUGIN(022)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_023
|
||||
NPlugin_id[x] = 23; NPlugin_ptr[x++] = &NPlugin_023;
|
||||
ADDNPLUGIN(023)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_024
|
||||
NPlugin_id[x] = 24; NPlugin_ptr[x++] = &NPlugin_024;
|
||||
ADDNPLUGIN(024)
|
||||
#endif
|
||||
|
||||
#ifdef NPLUGIN_025
|
||||
NPlugin_id[x] = 25; NPlugin_ptr[x++] = &NPlugin_025;
|
||||
ADDNPLUGIN(025)
|
||||
#endif
|
||||
|
||||
NPluginCall(NPLUGIN_PROTOCOL_ADD, 0);
|
||||
@@ -125,7 +142,7 @@ byte NPluginCall(byte Function, struct EventStruct *event)
|
||||
|
||||
if (event == 0)
|
||||
event=&TempEvent;
|
||||
|
||||
|
||||
switch (Function)
|
||||
{
|
||||
// Unconditional calls to all plugins
|
||||
@@ -139,4 +156,3 @@ byte NPluginCall(byte Function, struct EventStruct *event)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+277
-257
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
wifi.txt
|
||||
__pycache__
|
||||
wificonfig.py
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user