Compare commits

..
28 Commits
Author SHA1 Message Date
GrovkillenandGitHub 1f1dd6f6b8 Update README.md 2018-02-02 12:51:37 +01:00
DatuXandGitHub 8f7fd936b8 Update README.md 2018-02-02 01:13:00 +01:00
JustMe-NLandDatuX 884205feea Update _P118_MPU6050.ino
Added safeguard against never triggering if detection window is smaller then detection threshold.
Bumped status from Development to Testing.
2017-02-27 15:05:25 +01:00
JustMe-NLandDatuX 21bd7d73d1 Update Misc.ino
Added wind sensor for Plugin 186 & FHEM or generic HTTP controllers.
2017-02-19 18:30:55 +01:00
DatuXandGitHub cd60d32966 Update README.md 2017-02-19 04:56:35 +01:00
DatuXandGitHub e53a92cd82 Update README.md 2017-02-19 04:48:50 +01:00
Edwin Eefting c618d37f0b rename to correct name (118). 2017-02-18 23:48:52 +01:00
Edwin Eefting f450aa4a01 intergrated required changes for _P186_Ventus_W266.ino into core (with proper ifdefs) 2017-02-18 23:48:52 +01:00
Edwin Eefting 32b9f40d02 added _P186_Ventus_W266.ino 2017-02-18 23:48:52 +01:00
JustMe-NLandDatuX ae082fd2bb Create _P186_Ventus_W266
Plugin to embed a esp into the display unit of a Ventus W266 weather station and sniff the data send by the remote sensor unit. The received data can then be send it to a controller like Domoticz.
2017-02-18 23:48:52 +01:00
JustMe-NLandDatuX 315adbc42f Create _P117_MPU6050.ino
This plugin lets the user read the raw values of the sensor, supports both addresses and can be set to monitor movement by setting range-threshold values for each axis (or disable monitoring for a axis) and set a movement detection threshold.

By first monitoring the raw values, a baseline can be determined using the home controllers ability to graph the values. The thresholds can then be added to the plugin and a timeframe can be set in which the thresholds need to be exceeded a programmable number of times before movement is signalled as a switch. By adding multiple instances of the plugin, multiple movement detection schemes can be set, this way it is possible to track a (e.g. washing) cycle.

It is still in development to fine tune the inner workings but is in a working order.
2017-02-18 23:48:52 +01:00
GeraldandDatuX face8a8bfc Update _C025.ino
server port should also be in host header
http status codes starting with 2 are ok, not only 200
2017-02-18 23:48:52 +01:00
Edwin Eefting fe1025e470 implemented speaker plugin from http://www.letscontrolit.com/forum/viewtopic.php?f=4&t=343&hilit=speaker&start=10 2017-02-18 23:48:52 +01:00
Edwin Eefting 4f6d7d1b82 blynk had the wrong plugin id defined 2017-02-18 23:48:52 +01:00
Edwin Eefting 894a01a534 Added all plugins from playground that didnt require extra dependencies and didnt have compile errors. They are all in the DEV plugin group because i dont know their development state yet. 2017-02-18 23:48:52 +01:00
Edwin Eefting a3317bcde1 moved blynk into testing 2017-02-18 23:48:52 +01:00
DatuX 6d9cbb3988 Update README.md 2017-02-18 23:48:52 +01:00
DatuX aa9cf0a795 Update README.md 2017-02-18 23:48:52 +01:00
DatuX d8244e1726 Update README.md 2017-02-18 23:48:52 +01:00
DatuX cabcd33a63 Update README.md 2017-02-18 23:48:52 +01:00
Edwin Eefting 3140833abb added P036 to development plugin set 2017-02-18 23:48:52 +01:00
Edwin Eefting 890351b920 show plugins sets 2017-02-18 23:48:52 +01:00
Edwin Eefting 0868b983d4 now show git version in webinterface 2017-02-18 23:48:52 +01:00
Aurelien.HannoteauxandDatuX 997e612c97 miss rename function name 2017-02-18 23:48:52 +01:00
Aurelien.HannoteauxandDatuX aadb6e0521 Add MQ2 gaz sensor plugin 2017-02-18 23:48:52 +01:00
Edwin Eefting fcd5c1ec01 ignore Version.h because its automaticly generated on builds with platformio 2017-02-18 23:48:52 +01:00
EA4GKQandDatuX e9c55e8685 _C001 Sent humstat to domoticz
Calculate humstat from humidity value.

Tested on 145
2017-02-18 23:48:52 +01:00
ChdidandDatuX 72c57aa2e3 add-Blynk-1.0 2017-02-18 23:48:52 +01:00
600 changed files with 10619 additions and 188815 deletions
-29
View File
@@ -1,29 +0,0 @@
# Contributing to ESPEasy
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
## Issue tracker
* The issue tracker is NOT a support forum. For support questions go to our forum: https://www.letscontrolit.com/forum/viewforum.php?f=1
* Only post an issue if you're 100% sure you've hit a bug. If your not sure, post on the forum first to see if anyone can confirm it.
This way we keep the issue tracker as short as possible, which saves our developers a lot of time.
Also there are more people on the forum that can help you with support.
## Pull requests
* Make sure your code compiles.
* Try to create different pull requests for different features/fixes.
* Dont combine a lot of different stuff in one huge pull request.
* Incomplete or unstable plugins should have a PLUGIN_BUILD_DEV #ifdef around them. Also add [DEVELOPMENT] to the name.
* New plugins that seem to be working correctly should have a PLUGIN_BUILD_TESTING around until they are tested enough.
* Also see our general guidelines at: https://www.letscontrolit.com/wiki/index.php/ESPEasyDevelopmentGuidelines
-16
View File
@@ -1,16 +0,0 @@
### Steps to reproduce
How can we trigger this problem?
Does the problem presist after powering off and on? (just resetting isnt enough sometimes)
### Expected behavior
Tell us what should happen?
### Actual behavior
Tell us what happens instead?
### System configuration
Hardware:
Software or git version:
+1 -6
View File
@@ -1,6 +1 @@
.pioenvs
.clang_complete
.gcc-flags.json
.piolibdeps
lib/readme.txt
Version.h
View File
-50
View File
@@ -1,50 +0,0 @@
language: python
python:
- '2.7'
#we want a newer cppcheck, so use trusty
dist: trusty
sudo: false
cache:
directories:
- "~/.platformio"
- "./.pioenvs"
addons:
apt:
packages:
- cppcheck
install:
- pip install -U platformio
script:
- cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
- ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
- platformio run -s
before_deploy:
- ./before_deploy
- export RELEASE_FILE=$(ls ESPEasy*.zip)
deploy:
provider: releases
prerelease: true
api_key:
secure: bZeuKI7evXeZYmGayfcvIC1fThBGcksAyOrCbZ8kAGeTbHGJqFLBBy8to5UpNBSZVfeDWo25Iqy8Pfbyb7p2c1hg6fG9jS0UzQkLnoUNMxpUM1dJACkZxvFdP4Br3Y3vUPWtrWUbo8rN/b3E6tjSNLE7vQiwsarj+eWTO2V6BGcsN0eHc04/UCM2+DcHvJ4y7Ec36yIUaClNAWMal1osBYaViruylOdBKT/WDs1ZMoJMceXCfxMQ/8J2moYvymKfSkXSmoMGmzlTuq8v5N4AweutjpC4Zba2BbxIJv+PwWjhfIgTviHFggSU90UPTKVWYv13vms92VVKz1CDVrUQNn+YQes9+ROPUnrMc9bJ+q7E1lWJRZeDMqGECB+8BjUtUk6H81K+XhOnW1mtZiMnvMCwkmE0OT1eBObGMcpR962/DUBoQDmulMs2IieB0dLobmUBhpc1syrKEPKxjY7yhhQMr6In82jODVLR3qDkNQ8xtIfevzCo/ocUjiOrXW4b/pDMy28Yh109DMb/KSWEsjjkkpXhsT1YVy2MwOa7FRhHFW+SNKX4Us8T75H+pO4mQ4afnPEtjYKodj7XD92zqNxKfMx3elEx5RK6HKekHjpXdYtuXzGONB9StA+2T43/2llt3n5fzv4BRfCumBEJ77/ufB0U/uhsCe6lVwJf34U=
file_glob: true
file: "${RELEASE_FILE}"
skip_cleanup: true
on:
tags: true
# repo: psy0rz/ESPEasy-platformio
notifications:
email: false
+69 -235
View File
@@ -1,45 +1,3 @@
char* ramtest;
//Reads a string from a stream until a terminator-character.
//We make sure we're not reading more than maxSize bytes and we're not busy for longer than timeout mS.
bool safeReadStringUntil(Stream &input, String &str, char terminator, int maxSize=1024, int timeout=1000)
{
unsigned long startMillis;
int c;
startMillis = millis();
str="";
do {
//read character
c = input.read();
if(c >= 0) {
//found terminator, we're ok
if (c==terminator)
{
return(true);
}
//found character, add to string
else
{
str+=char(c);
//string at max size?
if (str.length()>=maxSize)
{
addLog(LOG_LEVEL_ERROR, F("Not enough bufferspace to read all input data!"));
return(false);
}
}
}
yield();
} while(millis() - startMillis < timeout);
addLog(LOG_LEVEL_ERROR, F("Timeout while reading input data!"));
return(false);
}
#define INPUT_COMMAND_SIZE 80
void ExecuteCommand(byte source, const char *Line)
{
@@ -61,109 +19,6 @@ void ExecuteCommand(byte source, const char *Line)
// ****************************************
// commands for debugging
// ****************************************
if (strcasecmp_P(Command, PSTR("background")) == 0)
{
success = true;
unsigned long timer = millis() + Par1;
Serial.println("start");
while (millis() < timer)
backgroundtasks();
Serial.println("end");
}
if (strcasecmp_P(Command, PSTR("executeRules")) == 0)
{
success = true;
if (GetArgv(Line, TmpStr1, 2))
{
String fileName = TmpStr1;
String event = "";
rulesProcessingFile(fileName, event);
}
}
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();
}
if (strcasecmp_P(Command, PSTR("notify")) == 0)
{
success = true;
String message = "";
if (GetArgv(Line, TmpStr1, 3))
message = TmpStr1;
if (Par1 > 0)
{
if (Settings.NotificationEnabled[Par1 - 1] && Settings.Notification[Par1 - 1] != 0)
{
byte NotificationProtocolIndex = getNotificationIndex(Settings.Notification[Par1 - 1]);
struct EventStruct TempEvent;
TempEvent.NotificationProtocolIndex = Par1 - 1;
if (NPlugin_id[NotificationProtocolIndex] != 0)
NPlugin_ptr[NotificationProtocolIndex](NPLUGIN_NOTIFY, &TempEvent, message);
}
}
}
if (strcasecmp_P(Command, PSTR("resetFlashWriteCounter")) == 0)
{
success = true;
RTC.flashDayCounter = 0;
}
if (strcasecmp_P(Command, PSTR("udptest")) == 0)
{
success = true;
for (byte x = 0; x < Par2; x++)
{
String event = "Test ";
event += x;
SendUDPCommand(Par1, (char*)event.c_str(), event.length());
}
}
if (strcasecmp_P(Command, PSTR("sdcard")) == 0)
{
success = true;
File root = SD.open("/");
root.rewindDirectory();
printDirectory(root, 0);
root.close();
}
if (strcasecmp_P(Command, PSTR("sdremove")) == 0)
{
success = true;
String fname = Line;
fname = fname.substring(9);
Serial.print(F("Removing:"));
Serial.println(fname.c_str());
SD.remove((char*)fname.c_str());
}
if (strcasecmp_P(Command, PSTR("lowmem")) == 0)
{
Serial.print(lowestRAM);
Serial.print(F(" : "));
Serial.println(lowestRAMid);
success = true;
}
if (strcasecmp_P(Command, PSTR("malloc")) == 0)
{
ramtest = (char *)malloc(Par1);
success = true;
}
if (strcasecmp_P(Command, PSTR("sysload")) == 0)
{
success = true;
@@ -190,8 +45,6 @@ void ExecuteCommand(byte source, const char *Line)
Serial.println(sizeof(Settings));
Serial.print(F("ExtraTaskSettingsStruct: "));
Serial.println(sizeof(ExtraTaskSettings));
Serial.print(F("DeviceStruct: "));
Serial.println(sizeof(Device));
}
if (strcasecmp_P(Command, PSTR("TaskClear")) == 0)
@@ -238,39 +91,11 @@ void ExecuteCommand(byte source, const char *Line)
Settings.deepSleep = 0;
}
if (strcasecmp_P(Command, PSTR("i2cscanner")) == 0)
{
success = true;
byte error, address;
for (address = 1; address <= 127; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print(F("I2C : Found 0x"));
Serial.println(String(address, HEX));
}
else if (error == 4)
{
Serial.print(F("I2C : Error at 0x"));
Serial.println(String(address, HEX));
}
}
}
// ****************************************
// commands for rules
// ****************************************
if (strcasecmp_P(Command, PSTR("deepSleep")) == 0)
{
success = true;
if (Par1 > 0)
deepSleep(Par1);
}
if (strcasecmp_P(Command, PSTR("TaskValueSet")) == 0)
{
success = true;
@@ -290,26 +115,14 @@ void ExecuteCommand(byte source, const char *Line)
if (strcasecmp_P(Command, PSTR("TimerSet")) == 0)
{
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
{
success = true;
if (Par2)
//start new timer
RulesTimer[Par1 - 1] = millis() + (1000 * Par2);
else
//disable existing timer
RulesTimer[Par1 - 1] = 0L;
}
else
{
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
}
success = true;
RulesTimer[Par1 - 1] = millis() + (1000 * Par2);
}
if (strcasecmp_P(Command, PSTR("Delay")) == 0)
{
success = true;
delayBackground(Par1);
delayMillis(Par1);
}
if (strcasecmp_P(Command, PSTR("Rules")) == 0)
@@ -394,12 +207,8 @@ void ExecuteCommand(byte source, const char *Line)
delay(1);
while (client.available()) {
// String line = client.readStringUntil('\n');
String line;
safeReadStringUntil(client, line, '\n');
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
String line = client.readStringUntil('\n');
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
addLog(LOG_LEVEL_DEBUG, line);
delay(1);
}
@@ -408,6 +217,38 @@ void ExecuteCommand(byte source, const char *Line)
}
}
#ifdef PLUGIN_BUILD_TESTING
// ****************************************
// special commands for Blynk
// ****************************************
if (strcasecmp(Command, "BlynkGet") == 0)
{
String event = Line;
event = event.substring(9);
int index = event.indexOf(',');
if (index > 0)
{
int index = event.lastIndexOf(',');
String blynkcommand = event.substring(index+1);
float value = 0;
if (Blynk_get(blynkcommand, &value))
{
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = value;
}
else
status = F("Error getting data");
}
else
{
if (!Blynk_get(event))
{
status = F("Error getting data");
}
}
}
#endif
// ****************************************
// configure settings commands
@@ -424,18 +265,6 @@ void ExecuteCommand(byte source, const char *Line)
strcpy(SecuritySettings.WifiKey, Line + 8);
}
if (strcasecmp_P(Command, PSTR("WifiSSID2")) == 0)
{
success = true;
strcpy(SecuritySettings.WifiSSID2, Line + 10);
}
if (strcasecmp_P(Command, PSTR("WifiKey2")) == 0)
{
success = true;
strcpy(SecuritySettings.WifiKey2, Line + 9);
}
if (strcasecmp_P(Command, PSTR("WifiScan")) == 0)
{
success = true;
@@ -445,7 +274,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)
@@ -471,6 +300,9 @@ void ExecuteCommand(byte source, const char *Line)
if (strcasecmp_P(Command, PSTR("Erase")) == 0)
{
success = true;
EraseFlash();
ZeroFillFlash();
saveToRTC(0);
WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
WiFi.disconnect(); // this will store empty ssid/wpa into sdk storage
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
@@ -494,6 +326,34 @@ void ExecuteCommand(byte source, const char *Line)
LoadSettings();
}
if (strcasecmp_P(Command, PSTR("FlashDump")) == 0)
{
success = true;
uint32_t _sectorStart = ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE;
uint32_t _sectorEnd = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
Serial.print(F("Sketch size : "));
Serial.println(ESP.getSketchSize());
Serial.print(F("Sketch free space : "));
Serial.println(ESP.getFreeSketchSpace());
Serial.print(F("Flash size : "));
Serial.println(ESP.getFlashChipRealSize());
Serial.print(F("SPIFFS start sector: "));
Serial.println(_sectorStart);
Serial.print(F("SPIFFS end sector : "));
Serial.println(_sectorEnd);
char data[80];
if (Par2 == 0) Par2 = Par1;
for (int x = Par1; x <= Par2; x++)
{
LoadFromFlash(x * 1024, (byte*)&data, sizeof(data));
Serial.print(F("Offset: "));
Serial.print(x);
Serial.print(" : ");
Serial.println(data);
}
}
if (strcasecmp_P(Command, PSTR("Debug")) == 0)
{
success = true;
@@ -522,8 +382,6 @@ void ExecuteCommand(byte source, const char *Line)
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);
Serial.print(F(" WifiSSID2 : ")); Serial.println(SecuritySettings.WifiSSID2);
Serial.print(F(" WifiKey2 : ")); Serial.println(SecuritySettings.WifiKey2);
Serial.print(F(" Free mem : ")); Serial.println(FreeMem());
}
@@ -536,27 +394,3 @@ void ExecuteCommand(byte source, const char *Line)
SendStatus(source, status);
yield();
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
+37 -64
View File
@@ -10,8 +10,8 @@ boolean sendData(struct EventStruct *event)
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
// if (!Settings.TaskDeviceSendData[event->TaskIndex])
// return false;
if (!Settings.TaskDeviceSendData[event->TaskIndex])
return false;
if (Settings.MessageDelay != 0)
{
@@ -19,30 +19,22 @@ boolean sendData(struct EventStruct *event)
if (dif < Settings.MessageDelay)
{
uint16_t delayms = Settings.MessageDelay - dif;
//this is logged nowhere else, so might as well disable it here also:
// addLog(LOG_LEVEL_DEBUG_MORE, String(F("CTRL : Message delay (ms): "))+delayms);
delayBackground(delayms);
// unsigned long timer = millis() + delayms;
// while (millis() < timer)
// backgroundtasks();
char log[30];
sprintf_P(log, PSTR("HTTP : Delay %u ms"), delayms);
addLog(LOG_LEVEL_DEBUG_MORE, log);
unsigned long timer = millis() + delayms;
while (millis() < timer)
backgroundtasks();
}
}
LoadTaskSettings(event->TaskIndex); // could have changed during background tasks.
for (byte x=0; x < CONTROLLER_MAX; x++)
if (Settings.Protocol)
{
event->ControllerIndex = x;
event->idx = Settings.TaskDeviceID[x][event->TaskIndex];
if (Settings.TaskDeviceSendData[event->ControllerIndex][event->TaskIndex] && Settings.ControllerEnabled[event->ControllerIndex] && Settings.Protocol[event->ControllerIndex])
{
event->ProtocolIndex = getProtocolIndex(Settings.Protocol[event->ControllerIndex]);
CPlugin_ptr[event->ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString);
}
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString);
}
PluginCall(PLUGIN_EVENT_OUT, event, dummyString);
lastSend = millis();
}
@@ -53,38 +45,21 @@ boolean sendData(struct EventStruct *event)
\*********************************************************************************************/
// handle MQTT messages
void callback(char* c_topic, byte* b_payload, unsigned int length) {
// char log[256];
char log[256];
char c_payload[256];
statusLED(true);
if (length>sizeof(c_payload)-1)
{
addLog(LOG_LEVEL_ERROR, F("MQTT : Ignored too big message"));
}
//convert payload to string, and 0 terminate
strncpy(c_payload,(char*)b_payload,length);
c_payload[length] = 0;
statusLED(true);
String log;
log=F("MQTT : Topic: ");
log+=c_topic;
sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic);
addLog(LOG_LEVEL_DEBUG, log);
log=F("MQTT : Payload: ");
log+=c_payload;
sprintf_P(log, PSTR("%s%s"), "MQTT : Payload: ", c_payload);
addLog(LOG_LEVEL_DEBUG, log);
// sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic);
// addLog(LOG_LEVEL_DEBUG, log);
// sprintf_P(log, PSTR("%s%s"), "MQTT : Payload: ", c_payload);
// addLog(LOG_LEVEL_DEBUG, log);
struct EventStruct TempEvent;
TempEvent.String1 = c_topic;
TempEvent.String2 = c_payload;
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString);
}
@@ -94,11 +69,8 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
\*********************************************************************************************/
void MQTTConnect()
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0
IPAddress MQTTBrokerIP(ControllerSettings.IP);
MQTTclient.setServer(MQTTBrokerIP, ControllerSettings.Port);
IPAddress MQTTBrokerIP(Settings.Controller_IP);
MQTTclient.setServer(MQTTBrokerIP, Settings.ControllerPort);
MQTTclient.setCallback(callback);
// MQTT needs a unique clientname to subscribe to broker
@@ -106,17 +78,22 @@ void MQTTConnect()
clientid += Settings.Unit;
String subscribeTo = "";
String LWTTopic = ControllerSettings.Subscribe;
LWTTopic.replace(F("/#"), F("/status"));
LWTTopic.replace(F("%sysname%"), Settings.Name);
String LWTTopic = Settings.MQTTsubscribe;
LWTTopic.replace("/#", "/status");
LWTTopic.replace("%sysname%", Settings.Name);
for (byte x = 1; x < 3; x++)
{
String log = "";
boolean MQTTresult = false;
//boolean connect(const char* id);
//boolean connect(const char* id, const char* user, const char* pass);
//boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
//boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[0], SecuritySettings.ControllerPassword[0], LWTTopic.c_str(), 0, 0, "Connection Lost");
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser, SecuritySettings.ControllerPassword, LWTTopic.c_str(), 0, 0, "Connection Lost");
else
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, "Connection Lost");
@@ -124,16 +101,12 @@ void MQTTConnect()
{
log = F("MQTT : Connected to broker");
addLog(LOG_LEVEL_INFO, log);
subscribeTo = ControllerSettings.Subscribe;
subscribeTo.replace(F("%sysname%"), Settings.Name);
subscribeTo = Settings.MQTTsubscribe;
subscribeTo.replace("%sysname%", Settings.Name);
MQTTclient.subscribe(subscribeTo.c_str());
log = F("Subscribed to: ");
log += subscribeTo;
addLog(LOG_LEVEL_INFO, log);
MQTTclient.publish(LWTTopic.c_str(), "Connected");
statusLED(true);
break; // end loop if succesfull
}
else
@@ -152,7 +125,7 @@ void MQTTConnect()
\*********************************************************************************************/
void MQTTCheck()
{
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
if (Protocol[ProtocolIndex].usesMQTT)
if (!MQTTclient.connected())
{
@@ -195,11 +168,11 @@ void SendStatus(byte source, String status)
\*********************************************************************************************/
void MQTTStatus(String& status)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0
String pubname = ControllerSettings.Subscribe;
pubname.replace(F("/#"), F("/status"));
pubname.replace(F("%sysname%"), Settings.Name);
String pubname = Settings.MQTTsubscribe;
pubname.replace("/#", "/status");
pubname.replace("%sysname%", Settings.Name);
MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
}
File diff suppressed because it is too large Load Diff
+78 -95
View File
@@ -1,95 +1,78 @@
/********************************************************************************************\
* Initialize specific hardware setings (only global ones, others are set through devices)
\*********************************************************************************************/
void hardwareInit()
{
// set GPIO pins state if not set to default
for (byte x=0; x < 17; x++)
if (Settings.PinBootStates[x] != 0)
switch(Settings.PinBootStates[x])
{
case 1:
pinMode(x,OUTPUT);
digitalWrite(x,LOW);
setPinState(1, x, PIN_MODE_OUTPUT, LOW);
break;
case 2:
pinMode(x,OUTPUT);
digitalWrite(x,HIGH);
setPinState(1, x, PIN_MODE_OUTPUT, HIGH);
break;
case 3:
pinMode(x,INPUT_PULLUP);
setPinState(1, x, PIN_MODE_INPUT, 0);
break;
}
// configure hardware pins according to eeprom settings.
if (Settings.Pin_i2c_sda != -1)
{
String log = F("INIT : I2C");
addLog(LOG_LEVEL_INFO, log);
Wire.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl);
if(Settings.WireClockStretchLimit)
{
String log = F("INIT : I2C custom clockstretchlimit:");
log += Settings.WireClockStretchLimit;
addLog(LOG_LEVEL_INFO, log);
Wire.setClockStretchLimit(Settings.WireClockStretchLimit);
}
}
// I2C Watchdog boot status check
if (Settings.WDI2CAddress != 0)
{
delay(500);
Wire.beginTransmission(Settings.WDI2CAddress);
Wire.write(0x83); // command to set pointer
Wire.write(17); // pointer value to status byte
Wire.endTransmission();
Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1);
if (Wire.available())
{
byte status = Wire.read();
if (status & 0x1)
{
String log = F("INIT : Reset by WD!");
addLog(LOG_LEVEL_ERROR, log);
lastBootCause = BOOT_CAUSE_EXT_WD;
}
}
}
// SPI Init
if (Settings.InitSPI)
{
SPI.setHwCs(false);
SPI.begin();
String log = F("INIT : SPI Init (without CS)");
addLog(LOG_LEVEL_INFO, log);
}
else
{
String log = F("INIT : SPI not enabled");
addLog(LOG_LEVEL_INFO, log);
}
if (Settings.Pin_sd_cs > 0)
{
if (SD.begin(Settings.Pin_sd_cs))
{
String log = F("SD : Init OK");
addLog(LOG_LEVEL_INFO, log);
}
else
{
String log = F("SD : Init failed");
addLog(LOG_LEVEL_ERROR, log);
}
}
}
/********************************************************************************************\
* Initialize specific hardware setings (only global ones, others are set through devices)
\*********************************************************************************************/
void hardwareInit()
{
// set GPIO pins state if not set to default
for (byte x=0; x < 17; x++)
if (Settings.PinBootStates[x] != 0)
switch(Settings.PinBootStates[x])
{
case 1:
pinMode(x,OUTPUT);
digitalWrite(x,LOW);
setPinState(1, x, PIN_MODE_OUTPUT, LOW);
break;
case 2:
pinMode(x,OUTPUT);
digitalWrite(x,HIGH);
setPinState(1, x, PIN_MODE_OUTPUT, HIGH);
break;
case 3:
pinMode(x,INPUT_PULLUP);
setPinState(1, x, PIN_MODE_INPUT, 0);
break;
}
// configure hardware pins according to eeprom settings.
if (Settings.Pin_i2c_sda != -1)
{
String log = F("INIT : I2C");
addLog(LOG_LEVEL_INFO, log);
Wire.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl);
if(Settings.WireClockStretchLimit)
{
String log = F("INIT : I2C custom clockstretchlimit:");
log += Settings.WireClockStretchLimit;
addLog(LOG_LEVEL_INFO, log);
Wire.setClockStretchLimit(Settings.WireClockStretchLimit);
}
}
// I2C Watchdog boot status check
if (Settings.WDI2CAddress != 0)
{
delay(500);
Wire.beginTransmission(Settings.WDI2CAddress);
Wire.write(0x83); // command to set pointer
Wire.write(17); // pointer value to status byte
Wire.endTransmission();
Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1);
if (Wire.available())
{
byte status = Wire.read();
if (status & 0x1)
{
String log = F("INIT : Reset by WD!");
addLog(LOG_LEVEL_ERROR, log);
lastBootCause = BOOT_CAUSE_EXT_WD;
}
}
}
// SPI Init
if (Settings.InitSPI)
{
SPI.setHwCs(false);
SPI.begin();
addLog(LOG_LEVEL_INFO, (char*)"INIT : SPI Init (without CS)");
}
else
{
addLog(LOG_LEVEL_INFO, (char*)"INIT : SPI not enabled");
}
}
+452 -734
View File
File diff suppressed because it is too large Load Diff
+12 -24
View File
@@ -48,10 +48,8 @@ struct dataStruct
float Values[VARS_PER_TASK];
};
//TODO: add sysinfoStruct
/*********************************************************************************************\
Check UDP messages (ESPEasy propiertary protocol)
Check UDP messages
\*********************************************************************************************/
void checkUDP()
{
@@ -100,8 +98,6 @@ void checkUDP()
// binary data!
switch (packetBuffer[1])
{
//TODO: use a nice struct for it
case 1: // sysinfo message
{
byte mac[6];
@@ -157,8 +153,7 @@ void checkUDP()
{
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
for (byte x=0; x < CONTROLLER_MAX; x++)
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
Settings.TaskDeviceSendData[infoReply.destTaskIndex] = false;
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
@@ -283,7 +278,7 @@ void SendUDPCommand(byte destUnit, char* data, byte dataLength)
firstUnit = destUnit;
lastUnit = destUnit;
}
for (int x = firstUnit; x <= lastUnit; x++)
for (byte x = firstUnit; x <= lastUnit; x++)
{
sendUDP(x, (byte*)data, dataLength);
delay(10);
@@ -293,24 +288,19 @@ void SendUDPCommand(byte destUnit, char* data, byte dataLength)
/*********************************************************************************************\
Send UDP message (unit 255=broadcast)
Send UDP message
\*********************************************************************************************/
void sendUDP(byte unit, byte* data, byte size)
{
if (unit != 255)
if (Nodes[unit].ip[0] == 0)
return;
if (Nodes[unit].ip[0] == 0)
return;
String log = "UDP : Send UDP message to ";
log += unit;
addLog(LOG_LEVEL_DEBUG_MORE, log);
statusLED(true);
IPAddress remoteNodeIP;
if (unit == 255)
remoteNodeIP = {255,255,255,255};
else
remoteNodeIP = Nodes[unit].ip;
IPAddress remoteNodeIP(Nodes[unit].ip[0], Nodes[unit].ip[1], Nodes[unit].ip[2], Nodes[unit].ip[3]);
portUDP.beginPacket(remoteNodeIP, Settings.UDPPort);
portUDP.write(data, size);
portUDP.endPacket();
@@ -334,16 +324,12 @@ void refreshNodeList()
}
}
/*********************************************************************************************\
Broadcast system info to other nodes. (to update node lists)
\*********************************************************************************************/
void sendSysInfoUDP(byte repeats)
{
char log[80];
if (Settings.UDPPort == 0)
return;
// TODO: make a nice struct of it and clean up
// 1 byte 'binary token 255'
// 1 byte id '1'
// 6 byte mac
@@ -352,7 +338,7 @@ void sendSysInfoUDP(byte repeats)
// 2 byte build
// 25 char name
// 1 byte node type id
// send my info to the world...
strcpy_P(log, PSTR("UDP : Send Sysinfo message"));
addLog(LOG_LEVEL_DEBUG_MORE, log);
@@ -396,6 +382,7 @@ void sendSysInfoUDP(byte repeats)
}
#if FEATURE_SSDP
/********************************************************************************************\
Respond to HTTP XML requests for SSDP information
\*********************************************************************************************/
@@ -437,7 +424,7 @@ void SSDP_schema(WiFiClient client) {
ssdp_schema += F("</serialNumber>"
"<modelName>ESP Easy</modelName>"
"<modelNumber>");
ssdp_schema += BUILD_GIT;
ssdp_schema += Settings.Build;
ssdp_schema += F("</modelNumber>"
"<modelURL>http://www.letscontrolit.com</modelURL>"
"<manufacturer>http://www.letscontrolit.com</manufacturer>"
@@ -575,7 +562,6 @@ void SSDP_send(byte method) {
remotePort = SSDP_PORT;
}
_server->send(&remoteAddr, remotePort);
statusLED(true);
}
@@ -713,3 +699,5 @@ void SSDP_update() {
}
}
#endif
+5 -40
View File
@@ -1,45 +1,10 @@
# ESPEasy (mega branch)
# ESPEasy legacy branch
Build status: [![Build Status](https://travis-ci.org/letscontrolit/ESPEasy.svg?branch=mega)](https://travis-ci.org/letscontrolit/ESPEasy)
**MASTER**
:warning:This is the ESPEasy legacy branch which isn't developed anymore.:warning:
Introduction and wiki: https://www.letscontrolit.com/wiki/index.php/ESPEasy#Introduction
Current development branch: https://github.com/letscontrolit/ESPEasy/tree/mega (new features + fixes from v2.0 )
This is the development branch for the next upcoming release (2.0.0). This is also known as ESPEasyMega.
Next stable version: https://github.com/letscontrolit/ESPEasy/tree/v2.0 (fixes only)
Check here to learn how to use this branch and help us improving ESPEasy: http://www.letscontrolit.com/wiki/index.php/ESPEasy#Source_code_development
## Versions
* 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.
## Firmware binary releases
Binary development releases are here: https://github.com/letscontrolit/ESPEasy/releases
Depending on your needs, we release different types of files.
For version 2.0.0-dev9 and higer:
Firmware name | Hardware | Included plugins |
-------------------------------------|-------------------------|-----------------------------|
ESPEasy_v2.0.0-dev9_dev_1024.bin | ESP8266 with 1Mb flash | Stable + Test + Development |
ESPEasy_v2.0.0-dev9_test_1024.bin | ESP8266 with 1Mb flash | Stable + Test |
ESPEasy_v2.0.0-dev9_normal_1024.bin | ESP8266 with 1Mb flash | Stable |
ESPEasy_v2.0.0-dev9_dev_4096.bin | ESP8266 with 4Mb flash | Stable + Test + Development |
ESPEasy_v2.0.0-dev9_test_4096.bin | ESP8266 with 4Mb flash | Stable + Test |
ESPEasy_v2.0.0-dev9_normal_4096.bin | ESP8266 with 4Mb flash | Stable |
ESPEasy_v2.0.0-dev9_dev_8285.bin | ESP8285 | Stable + Test + Development |
ESPEasy_v2.0.0-dev9_test_8285.bin | ESP8285 | Stable + Test |
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
We're also on IRC: #ESPEasy @freenode
+1 -1
View File
@@ -41,4 +41,4 @@ void serial()
}
}
}
+2
View File
@@ -0,0 +1,2 @@
#define BUILD_GIT "v1.1.0-beta8-0-g7ade851"
+2710
View File
File diff suppressed because it is too large Load Diff
+6 -24
View File
@@ -36,7 +36,7 @@ void WifiAPMode(boolean state)
//********************************************************************************
// Connect to Wifi AP
//********************************************************************************
boolean WifiConnect(boolean primary, byte connectAttempts)
boolean WifiConnect(byte connectAttempts)
{
String log = "";
@@ -73,21 +73,15 @@ boolean WifiConnect(boolean primary, byte connectAttempts)
addLog(LOG_LEVEL_INFO, log);
if (tryConnect == 1)
{
if (primary)
WiFi.begin(SecuritySettings.WifiSSID, SecuritySettings.WifiKey);
else
WiFi.begin(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2);
}
WiFi.begin(SecuritySettings.WifiSSID, SecuritySettings.WifiKey);
else
WiFi.begin();
for (byte x = 0; x < 200; x++)
for (byte x = 0; x < 20; x++)
{
if (WiFi.status() != WL_CONNECTED)
{
statusLED(false);
delay(50);
delay(500);
}
else
break;
@@ -100,7 +94,6 @@ boolean WifiConnect(boolean primary, byte connectAttempts)
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
@@ -110,11 +103,7 @@ boolean WifiConnect(boolean primary, byte connectAttempts)
ETS_UART_INTR_DISABLE();
wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
for (byte x = 0; x < 20; x++)
{
statusLED(true);
delay(50);
}
delay(1000);
}
}
@@ -139,11 +128,6 @@ boolean WifiConnect(boolean primary, byte connectAttempts)
WifiAPMode(true);
}
}
if (WiFi.status() == WL_CONNECTED)
return true;
return false;
}
@@ -205,9 +189,7 @@ void WifiCheck()
NC_Count++;
if (NC_Count > 2)
{
if (!WifiConnect(true,2))
WifiConnect(false,2);
WifiConnect(2);
C_Count=0;
if (WiFi.status() != WL_CONNECTED)
WifiAPMode(true);
+197
View File
@@ -0,0 +1,197 @@
//#######################################################################################################
//########################### Controller Plugin 001: Domoticz HTTP ######################################
//#######################################################################################################
#define CPLUGIN_001
#define CPLUGIN_ID_001 1
#define CPLUGIN_NAME_001 "Domoticz HTTP"
boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_001;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 8080;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_001);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
String authHeader = "";
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
{
base64 encoder;
String auth = SecuritySettings.ControllerUser;
auth += ":";
auth += SecuritySettings.ControllerPassword;
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
}
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
return false;
}
statusLED(true);
if (connectionFailures)
connectionFailures--;
// We now create a URI for the request
String url = F("/json.htm?type=command&param=udevice&idx=");
url += event->idx;
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
url += F("&svalue=");
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
url += F("&svalue=");
url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
break;
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
url += F("&svalue=");
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
url += ";";
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
break;
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
url += F("&svalue=");
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
url += ";";
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
url += ";";
url += humStat(UserVar[event->BaseVarIndex + 1]);
break;
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
url += F("&svalue=");
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
url += ";0;0;";
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
url += ";0";
break;
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
url += F("&svalue=");
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
url += ";";
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
url += ";";
url += humStat(UserVar[event->BaseVarIndex + 1]);
url += ";";
url += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
url += ";0";
break;
case SENSOR_TYPE_SWITCH:
url = F("/json.htm?type=command&param=switchlight&idx=");
url += event->idx;
url += F("&switchcmd=");
if (UserVar[event->BaseVarIndex] == 0)
url += "Off";
else
url += "On";
break;
case SENSOR_TYPE_DIMMER:
url = F("/json.htm?type=command&param=switchlight&idx=");
url += event->idx;
url += F("&switchcmd=");
if (UserVar[event->BaseVarIndex] == 0)
url += "Off";
else
{
url += F("Set%20Level&level=");
url += UserVar[event->BaseVarIndex];
}
break;
#ifdef PLUGIN_186
case (SENSOR_TYPE_WIND):
url += F("&svalue=");
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
char* bearing[] = {";N;",";NNE;",";NE;",";ENE;",";E;",";ESE;",";SE;",";SSE;",";S;",";SSW;",";SW;",";WSW;",";W;",";WNW;",";NW;",";NNW;" };
url += bearing[int(UserVar[event->BaseVarIndex] / 22.5)];
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
url += ";";
url += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
url += ";0";
break;
#endif
}
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" + authHeader +
"Connection: close\r\n\r\n");
unsigned long timer = millis() + 200;
while (!client.available() && millis() < timer)
delay(1);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
strcpy_P(log, PSTR("HTTP : Success"));
addLog(LOG_LEVEL_DEBUG, log);
success = true;
}
delay(1);
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
break;
}
}
return success;
}
int humStat(int hum){
int lHumStat;
if(hum<30){
lHumStat = 2;
}else if(hum<40){
lHumStat = 0;
}else if(hum<59){
lHumStat = 1;
}else{
lHumStat = 3;
}
return lHumStat;
}
+239
View File
@@ -0,0 +1,239 @@
//#######################################################################################################
//########################### Controller Plugin 002: Domoticz MQTT ######################################
//#######################################################################################################
#define CPLUGIN_002
#define CPLUGIN_ID_002 2
#define CPLUGIN_NAME_002 "Domoticz MQTT"
boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_002;
Protocol[protocolCount].usesMQTT = true;
Protocol[protocolCount].usesTemplate = true;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 1883;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_002);
break;
}
case CPLUGIN_PROTOCOL_TEMPLATE:
{
strcpy_P(Settings.MQTTsubscribe, PSTR("domoticz/out"));
strcpy_P(Settings.MQTTpublish, PSTR("domoticz/in"));
break;
}
case CPLUGIN_PROTOCOL_RECV:
{
char json[512];
json[0] = 0;
event->String2.toCharArray(json, 512);
StaticJsonBuffer<512> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
if (root.success())
{
long idx = root["idx"];
float nvalue = root["nvalue"];
long nvaluealt = root["nvalue"];
//const char* name = root["name"]; // Not used
//const char* svalue = root["svalue"]; // Not used
const char* svalue1 = root["svalue1"];
//const char* svalue2 = root["svalue2"]; // Not used
//const char* svalue3 = root["svalue3"]; // Not used
const char* switchtype = root["switchType"]; // Expect "On/Off" or "dimmer"
if (nvalue == 0)
nvalue = nvaluealt;
if ((int)switchtype == 0)
switchtype = "?";
for (byte x = 0; x < TASKS_MAX; x++)
{
if (Settings.TaskDeviceID[x] == idx)
{
if (Settings.TaskDeviceNumber[x] == 1) // temp solution, if input switch, update state
{
String action = F("inputSwitchState,");
action += x;
action += ",";
action += nvalue;
struct EventStruct TempEvent;
parseCommandString(&TempEvent, action);
PluginCall(PLUGIN_WRITE, &TempEvent, action);
}
if (Settings.TaskDeviceNumber[x] == 29) // temp solution, if plugin 029, set gpio
{
String action = "";
int baseVar = x * VARS_PER_TASK;
struct EventStruct TempEvent;
if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0)
{
int pwmValue = UserVar[baseVar];
action = F("pwm,");
action += Settings.TaskDevicePin1[x];
action += ",";
switch ((int)nvalue)
{
case 0:
pwmValue = 0;
break;
case 1:
pwmValue = UserVar[baseVar];
break;
case 2:
pwmValue = 10 * atol(svalue1);
UserVar[baseVar] = pwmValue;
break;
}
action += pwmValue;
}
else
{
UserVar[baseVar] = nvalue;
action = F("gpio,");
action += Settings.TaskDevicePin1[x];
action += ",";
action += nvalue;
}
parseCommandString(&TempEvent, action);
PluginCall(PLUGIN_WRITE, &TempEvent, action);
}
}
}
}
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["idx"] = event->idx;
String values;
char str[80];
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
root["nvalue"] = 0;
values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
root["nvalue"] = 0;
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
root["nvalue"] = 0;
values = toString(UserVar[event->BaseVarIndex ],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
values += ";";
values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
root["nvalue"] = 0;
values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
values += ";";
values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";0";
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
root["nvalue"] = 0;
values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
values += ";0;0;";
values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";0";
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
root["nvalue"] = 0;
values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
values += ";";
values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";0;";
values += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
values += ";0";
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case SENSOR_TYPE_SWITCH:
root["command"] = "switchlight";
if (UserVar[event->BaseVarIndex] == 0)
root["switchcmd"] = "Off";
else
root["switchcmd"] = "On";
break;
case SENSOR_TYPE_DIMMER:
root["command"] = "switchlight";
if (UserVar[event->BaseVarIndex] == 0)
root["switchcmd"] = "Off";
else
root["Set%20Level"] = UserVar[event->BaseVarIndex];
break;
#ifdef PLUGIN_186
case SENSOR_TYPE_WIND:
values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
char* bearing[] = {";N;",";NNE;",";NE;",";ENE;",";E;",";ESE;",";SE;",";SSE;",";S;",";SSW;",";SW;",";WSW;",";W;",";WNW;",";NW;",";NNW;" };
values += bearing[int(UserVar[event->BaseVarIndex] / 22.5)];
values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";";
values += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
values += ";0;0";
values.toCharArray(str, 80);
root["svalue"] = str;
break;
#endif
}
char json[256];
root.printTo(json, sizeof(json));
String log = F("MQTT : ");
log += json;
addLog(LOG_LEVEL_DEBUG, json);
String pubname = Settings.MQTTpublish;
pubname.replace("%sysname%", Settings.Name);
pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName);
pubname.replace("%id%", String(event->idx));
if (!MQTTclient.publish(pubname.c_str(), json, Settings.MQTTRetainFlag))
{
log = F("MQTT publish failed");
addLog(LOG_LEVEL_DEBUG, json);
MQTTConnect();
connectionFailures++;
}
else if (connectionFailures)
connectionFailures--;
break;
}
}
return success;
}
+8 -15
View File
@@ -19,7 +19,6 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 23;
Protocol[protocolCount].usesID = true;
break;
}
@@ -28,23 +27,20 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
string = F(CPLUGIN_NAME_003);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]);
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "TELNT: connecting to ", host,ControllerSettings.Port);
sprintf_P(log, PSTR("%s%s using port %u"), "TELNT: connecting to ", host,Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, ControllerSettings.Port))
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("TELNT: connection failed"));
@@ -73,12 +69,8 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
timer = millis() + 1000;
while (client.available() && millis() < timer && !success)
{
// String line = client.readStringUntil('\n');
String line;
safeReadStringUntil(client, line, '\n');
if (line.startsWith(F("Enter your password:")))
String line = client.readStringUntil('\n');
if (line.substring(0, 20) == "Enter your password:")
{
success = true;
strcpy_P(log, PSTR("TELNT: Password request ok"));
@@ -89,7 +81,7 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
strcpy_P(log, PSTR("TELNT: Sending pw"));
addLog(LOG_LEVEL_ERROR, log);
client.println(SecuritySettings.ControllerPassword[event->ControllerIndex]);
client.println(SecuritySettings.ControllerPassword);
delay(100);
while (client.available())
client.read();
@@ -112,3 +104,4 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
}
return success;
}
+10 -16
View File
@@ -19,7 +19,6 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
Protocol[protocolCount].usesID = true;
break;
}
@@ -28,23 +27,20 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
string = F(CPLUGIN_NAME_004);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]);
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,ControllerSettings.Port);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, ControllerSettings.Port))
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
@@ -56,7 +52,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
connectionFailures--;
String postDataStr = F("api_key=");
postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // used for API key
postDataStr += SecuritySettings.ControllerPassword; // used for API key
byte valueCount = getValueCountFromSensorType(event->sensorType);
for (byte x = 0; x < valueCount; x++)
@@ -67,8 +63,8 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
postDataStr += toString(UserVar[event->BaseVarIndex + x],ExtraTaskSettings.TaskDeviceValueDecimals[x]);
}
String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers.
if (ControllerSettings.UseDNS)
hostName = ControllerSettings.HostName;
if (Settings.UseDNS)
hostName = Settings.ControllerHostName;
String postStr = F("POST /update HTTP/1.1\r\n");
postStr += F("Host: ");
@@ -91,13 +87,10 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
// String line = client.readStringUntil('\n');
String line;
safeReadStringUntil(client, line, '\n');
String line = client.readStringUntil('\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
strcpy_P(log, PSTR("HTTP : Succes!"));
addLog(LOG_LEVEL_DEBUG, log);
@@ -116,3 +109,4 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
}
return success;
}
+11 -22
View File
@@ -20,7 +20,6 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 1883;
Protocol[protocolCount].usesID = false;
break;
}
@@ -32,8 +31,8 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_TEMPLATE:
{
event->String1 = F("/%sysname%/#");
event->String2 = F("/%sysname%/%tskname%/%valname%");
strcpy_P(Settings.MQTTsubscribe, PSTR("/%sysname%/#"));
strcpy_P(Settings.MQTTpublish, PSTR("/%sysname%/%tskname%/%valname%"));
break;
}
@@ -56,7 +55,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
String cmd = "";
struct EventStruct TempEvent;
if (topicSplit[count] == F("cmd"))
if (topicSplit[count] == "cmd")
{
cmd = event->String2;
parseCommandString(&TempEvent, cmd);
@@ -67,34 +66,28 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
cmd = topicSplit[count - 1];
TempEvent.Par1 = topicSplit[count].toInt();
TempEvent.Par2 = event->String2.toFloat();
TempEvent.Par3 = 0;
TempEvent.Par3 = 0;
}
// in case of event, store to buffer and return...
String command = parseString(cmd, 1);
if (command == F("event"))
eventBuffer = cmd.substring(6);
else if
(PluginCall(PLUGIN_WRITE, &TempEvent, cmd));
else
remoteConfig(&TempEvent, cmd);
PluginCall(PLUGIN_WRITE, &TempEvent, cmd);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
statusLED(true);
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String pubname = ControllerSettings.Publish;
pubname.replace(F("%sysname%"), Settings.Name);
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
pubname.replace(F("%id%"), String(event->idx));
String pubname = Settings.MQTTpublish;
pubname.replace("%sysname%", Settings.Name);
pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName);
pubname.replace("%id%", String(event->idx));
String value = "";
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
@@ -102,20 +95,16 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
for (byte x = 0; x < valueCount; x++)
{
String tmppubname = pubname;
tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]);
tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[x]);
if (event->sensorType == SENSOR_TYPE_LONG)
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
else
value = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]);
MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
String log = F("MQTT : ");
log += tmppubname;
log += " ";
log += value;
addLog(LOG_LEVEL_DEBUG, log);
}
break;
}
return success;
}
}
+9 -13
View File
@@ -20,7 +20,6 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = false;
Protocol[protocolCount].defaultPort = 1883;
Protocol[protocolCount].usesID = false;
break;
}
@@ -32,8 +31,8 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_TEMPLATE:
{
event->String1 = F("/Home/#");
event->String2 = F("/hooks/devices/%id%/SensorData/%valname%");
strcpy_P(Settings.MQTTsubscribe, PSTR("/Home/#"));
strcpy_P(Settings.MQTTpublish, PSTR("/hooks/devices/%id%/SensorData/%valname%"));
break;
}
@@ -60,9 +59,9 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
TempEvent.Par1 = topicSplit[6].toInt();
TempEvent.Par2 = 0;
TempEvent.Par3 = 0;
if (event->String2 == F("false") || event->String2 == F("true"))
if (event->String2 == "false" || event->String2 == "true")
{
if (event->String2 == F("true"))
if (event->String2 == "true")
TempEvent.Par2 = 1;
}
else
@@ -76,18 +75,15 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_SEND:
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
statusLED(true);
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String pubname = ControllerSettings.Publish;
pubname.replace(F("%sysname%"), Settings.Name);
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
pubname.replace(F("%id%"), String(event->idx));
String pubname = Settings.MQTTpublish;
pubname.replace("%sysname%", Settings.Name);
pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName);
pubname.replace("%id%", String(event->idx));
String value = "";
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
@@ -95,7 +91,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
for (byte x = 0; x < valueCount; x++)
{
String tmppubname = pubname;
tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]);
tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[x]);
if (event->sensorType == SENSOR_TYPE_LONG)
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
else
+13 -19
View File
@@ -19,7 +19,6 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
Protocol[protocolCount].usesID = true;
break;
}
@@ -28,38 +27,35 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
string = F(CPLUGIN_NAME_007);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]);
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,ControllerSettings.Port);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, ControllerSettings.Port))
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
return false;
}
statusLED(true);
statusLED(true);
if (connectionFailures)
connectionFailures--;
String postDataStr = F("GET /emoncms/input/post.json?node=");
postDataStr += Settings.Unit;
postDataStr += F("&json=");
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
@@ -102,11 +98,11 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
break;
}
postDataStr += F("&apikey=");
postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // "0UDNN17RW6XAS2E5" // api key
postDataStr += SecuritySettings.ControllerPassword; // "0UDNN17RW6XAS2E5" // api key
String hostName = host;
if (ControllerSettings.UseDNS)
hostName = ControllerSettings.HostName;
if (Settings.UseDNS)
hostName = Settings.ControllerHostName;
String postStr = F(" HTTP/1.1\r\n");
postStr += F("Host: ");
@@ -129,13 +125,10 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
// String line = client.readStringUntil('\n');
String line;
safeReadStringUntil(client, line, '\n');
String line = client.readStringUntil('\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
strcpy_P(log, PSTR("HTTP : Succes!"));
addLog(LOG_LEVEL_DEBUG, log);
@@ -154,3 +147,4 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
}
return success;
}
+146
View File
@@ -0,0 +1,146 @@
//#######################################################################################################
//########################### Controller Plugin 008: Generic HTTP #######################################
//#######################################################################################################
#define CPLUGIN_008
#define CPLUGIN_ID_008 8
#define CPLUGIN_NAME_008 "Generic HTTP"
boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_008;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesTemplate = true;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_008);
break;
}
case CPLUGIN_PROTOCOL_TEMPLATE:
{
strcpy_P(Settings.MQTTpublish, PSTR("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%"));
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
byte valueCount = getValueCountFromSensorType(event->sensorType);
for (byte x = 0; x < valueCount; x++)
{
if (event->sensorType == SENSOR_TYPE_LONG)
HTTPSend(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
else
HTTPSend(event, x, UserVar[event->BaseVarIndex + x], 0);
if (valueCount > 1)
{
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
}
}
break;
}
}
return success;
}
//********************************************************************************
// Generic HTTP get request
//********************************************************************************
boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
String authHeader = "";
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
{
base64 encoder;
String auth = SecuritySettings.ControllerUser;
auth += ":";
auth += SecuritySettings.ControllerPassword;
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
}
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host, Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
return false;
}
statusLED(true);
if (connectionFailures)
connectionFailures--;
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String url = "/";
url += Settings.MQTTpublish;
url.replace("%sysname%", URLEncode(Settings.Name));
url.replace("%tskname%", URLEncode(ExtraTaskSettings.TaskDeviceName));
url.replace("%id%", String(event->idx));
url.replace("%valname%", URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
if (longValue)
url.replace("%value%", String(longValue));
else
url.replace("%value%", toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
String hostName = host;
if (Settings.UseDNS)
hostName = Settings.ControllerHostName;
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + hostName + "\r\n" + authHeader +
"Connection: close\r\n\r\n");
unsigned long timer = millis() + 200;
while (!client.available() && millis() < timer)
delay(1);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
strcpy_P(log, PSTR("HTTP : Succes!"));
addLog(LOG_LEVEL_DEBUG, log);
success = true;
}
delay(1);
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
}
+200
View File
@@ -0,0 +1,200 @@
//#######################################################################################################
//########################### Controller Plugin 009: FHEM HTTP ##########################################
//#######################################################################################################
/*******************************************************************************
* Modified version of "Domoticz HTTP CPLUGIN"
* Copyright 2016 dev0 (https://forum.fhem.de/index.php?action=profile;u=7465)
* Release notes:
- v1.0
- changed switch and dimmer setreading cmds
- v1.01
- added json content to http requests
- v1.02
- some optimizations as requested by mvdbro
- fixed JSON TaskDeviceValueDecimals handling
- ArduinoJson Library v5.6.4 required (as used by stable R120)
- parse for HTTP errors 400, 401
- moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module
/******************************************************************************/
#define CPLUGIN_009
#define CPLUGIN_ID_009 9
#define CPLUGIN_NAME_009 "FHEM HTTP"
boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_009;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesTemplate = false;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 8383;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_009);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
// We now create a URI for the request
String url = F("/fhem?cmd=");
// Create json root object
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["module"] = "ESPEasy";
root["version"] = "1.02";
// Create nested objects
JsonObject& data = root.createNestedObject("data");
JsonObject& ESP = data.createNestedObject("ESP");
ESP["name"] = Settings.Name;
ESP["unit"] = Settings.Unit;
ESP["version"] = Settings.Version;
ESP["build"] = Settings.Build;
ESP["sleep"] = Settings.deepSleep;
// embed IP, important if there is NAT/PAT
char ipStr[20];
IPAddress ip = WiFi.localIP();
sprintf(ipStr, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
ESP["ip"] = ipStr;
// Create nested SENSOR json object
JsonObject& SENSOR = data.createNestedObject("SENSOR");
byte valueCount = getValueCountFromSensorType(event->sensorType);
char itemNames[valueCount][2];
for (byte x = 0; x < valueCount; x++)
{
String s;
url += F("setreading%20");
url += Settings.Name;
url += F("%20");
url += ExtraTaskSettings.TaskDeviceValueNames[x];
url += F("%20");
// Each sensor value get an own object (0..n)
sprintf(itemNames[x],"%d",x);
JsonObject& val = SENSOR.createNestedObject(itemNames[x]);
val["deviceName"] = ExtraTaskSettings.TaskDeviceName;
val["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[x];
val["type"] = event->sensorType;
if (event->sensorType == SENSOR_TYPE_LONG) {
s = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
url += s;
val["value"] = s;
} else { // All other sensor types
s = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]);
url += s;
val["value"] = s;
}
// Split FHEM commands by ";"
if (x < valueCount-1)
url += F("%3B");
}
// Create json buffer
char buffer[root.measureLength() +1];
root.printTo(buffer, sizeof(buffer));
// Push data to server
FHEMHTTPsend(url, buffer);
break;
}
}
return success;
}
//********************************************************************************
// FHEM HTTP request
//********************************************************************************
boolean FHEMHTTPsend(String url, char* buffer)
{
boolean success = false;
String authHeader = "";
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) {
base64 encoder;
String auth = SecuritySettings.ControllerUser;
auth += ":";
auth += SecuritySettings.ControllerPassword;
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
}
char log[80];
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Settings.ControllerPort)) {
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
return false;
}
statusLED(true);
if (connectionFailures)
connectionFailures--;
// This will send the request to the server
int len = strlen(buffer);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Content-Length: "+ len + "\r\n" +
"Host: " + host + "\r\n" + authHeader +
"Connection: close\r\n\r\n"
+ buffer);
unsigned long timer = millis() + 200;
while (!client.available() && millis() < timer)
delay(1);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
String helper = line;
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == "HTTP/1.1 200 OK") {
strcpy_P(log, PSTR("HTTP : Success"));
success = true;
}
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
addLog(LOG_LEVEL_DEBUG, log);
delay(1);
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
}
+16 -21
View File
@@ -20,7 +20,6 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = false;
Protocol[protocolCount].defaultPort = 514;
Protocol[protocolCount].usesID = false;
break;
}
@@ -32,8 +31,7 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_TEMPLATE:
{
event->String1 = "";
event->String2 = F("%sysname%_%tskname%_%valname%=%value%");
strcpy_P(Settings.MQTTpublish, PSTR("%sysname%_%tskname%_%valname%=%value%"));
break;
}
@@ -48,10 +46,9 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
C010_Send(event, x, UserVar[event->BaseVarIndex + x], 0);
if (valueCount > 1)
{
delayBackground(Settings.MessageDelay);
// unsigned long timer = millis() + Settings.MessageDelay;
// while (millis() < timer)
// backgroundtasks();
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
}
}
break;
@@ -67,15 +64,12 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
//********************************************************************************
boolean C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]);
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "UDP : sending to ", host, ControllerSettings.Port);
sprintf_P(log, PSTR("%s%s using port %u"), "UDP : sending to ", host, Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
statusLED(true);
@@ -84,18 +78,18 @@ boolean C010_Send(struct EventStruct *event, byte varIndex, float value, unsigne
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String msg = "";
msg += ControllerSettings.Publish;
msg.replace(F("%sysname%"), Settings.Name);
msg.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
msg.replace(F("%id%"), String(event->idx));
msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
msg += Settings.MQTTpublish;
msg.replace("%sysname%", Settings.Name);
msg.replace("%tskname%", ExtraTaskSettings.TaskDeviceName);
msg.replace("%id%", String(event->idx));
msg.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
if (longValue)
msg.replace(F("%value%"), String(longValue));
msg.replace("%value%", String(longValue));
else
msg.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
msg.replace("%value%", toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
IPAddress IP(ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]);
portUDP.beginPacket(IP, ControllerSettings.Port);
IPAddress IP(Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
portUDP.beginPacket(IP, Settings.ControllerPort);
portUDP.write(msg.c_str());
portUDP.endPacket();
@@ -103,3 +97,4 @@ boolean C010_Send(struct EventStruct *event, byte varIndex, float value, unsigne
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
+185
View File
@@ -0,0 +1,185 @@
#ifdef PLUGIN_BUILD_TESTING
//#######################################################################################################
//########################### Controller Plugin 011: Blynk #############################################
//#######################################################################################################
#define CPLUGIN_011
#define CPLUGIN_ID_011 11
#define CPLUGIN_NAME_011 "Blynk HTTP [TESTING]"
boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_011;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 8443;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_011);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
String postDataStr = "";
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
postDataStr = F("update/V") ;
postDataStr += event->idx;
postDataStr += F("?value=");
postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
Blynk_get(postDataStr );
break;
case SENSOR_TYPE_TEMP_HUM: // dual value
case SENSOR_TYPE_TEMP_BARO:
case SENSOR_TYPE_DUAL:
postDataStr = F("update/V") ;
postDataStr += event->idx;
postDataStr += F("?value=");
postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
Blynk_get(postDataStr );
postDataStr = F("update/V") ;
postDataStr += event->idx + 1;
postDataStr += F("?value=");
postDataStr += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
Blynk_get(postDataStr );
break;
case SENSOR_TYPE_TEMP_HUM_BARO:
case SENSOR_TYPE_TRIPLE:
postDataStr = F("update/V") ;
postDataStr += event->idx;
postDataStr += F("?value=");
postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
Blynk_get(postDataStr );
postDataStr = F("update/V") ;
postDataStr += event->idx + 1;
postDataStr += F("?value=");
postDataStr += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
Blynk_get(postDataStr );
postDataStr = F("update/V") ;
postDataStr += event->idx + 2;
postDataStr += F("?value=");
postDataStr += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
Blynk_get(postDataStr );
break;
case SENSOR_TYPE_SWITCH:
break;
}
break;
}
}
return success;
}
boolean Blynk_get(String command,float *data )
{
boolean success = false;
char host[20];
char log[80];
char command_char[50];
command.toCharArray(command_char, 50);
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
return false;
}
if (connectionFailures)
connectionFailures--;
// We now create a URI for the request
char requete[300];
sprintf_P(requete, PSTR("GET /%s/%s HTTP/1.1\r\n Host: %s \r\n Connection: close\r\n\r\n"),SecuritySettings.ControllerPassword,command_char , host );
addLog(LOG_LEVEL_DEBUG, requete);
client.print(requete);
unsigned long timer = millis() + 200;
while (!client.available() && millis() < timer)
delay(1);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
// success ?
if (line.substring(0, 15) == "HTTP/1.1 200 OK") {
strcpy_P(log, PSTR("HTTP : Success"));
success = true;
}
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
addLog(LOG_LEVEL_DEBUG, log);
// data only
if (data && line.startsWith("["))
{
String strValue = line;
byte pos = strValue.indexOf('"',2);
strValue = strValue.substring(2, pos);
strValue.trim();
float value = strValue.toFloat();
*data = value;
success = true;
char value_char[5] ;
strValue.toCharArray(value_char, 5);
sprintf_P(log, PSTR("Blynk get - %s => %s"),command_char , value_char );
addLog(LOG_LEVEL_DEBUG, log);
}
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
// important - backgroudtasks - free mem
timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
return success;
}
#endif
+182
View File
@@ -0,0 +1,182 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//########################### Controller Plugin 022: Pimatic RestApi ####################################
//#######################################################################################################
/*******************************************************************************
* Release notes:
* V 1.0
- First version by deejaybeam, 7 July 2016
* V 1.01
- Update and rename _C009.ino to _C022.ino by Wutu due to new standard protocols, 21 September 2016
* V1.02
- Remove ">210" core statement to comply (and function) with new standard 230 core as of R114, 24 September 2016
*
/******************************************************************************/
#define CPLUGIN_022
#define CPLUGIN_ID_022 22
#define CPLUGIN_NAME_022 "Pimatic RestApi [DEVELOPMENT]"
boolean CPlugin_022(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_022;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_022);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
case SENSOR_TYPE_SWITCH:
case SENSOR_TYPE_DIMMER:
pimaticUpdateVariable(event, 0, UserVar[event->BaseVarIndex], 0);
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
pimaticUpdateVariable(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
break;
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
{
pimaticUpdateVariable(event, 0, UserVar[event->BaseVarIndex], 0);
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
pimaticUpdateVariable(event, 1, UserVar[event->BaseVarIndex + 1], 0);
break;
}
case SENSOR_TYPE_TEMP_HUM_BARO:
{
pimaticUpdateVariable(event, 0, UserVar[event->BaseVarIndex], 0);
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
pimaticUpdateVariable(event, 1, UserVar[event->BaseVarIndex + 1], 0);
timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
pimaticUpdateVariable(event, 2, UserVar[event->BaseVarIndex + 2], 0);
break;
}
}
break;
}
}
return success;
}
//********************************************************************************
// Pimatic updateVariable
//********************************************************************************
boolean pimaticUpdateVariable(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
String authHeader = "";
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
{
base64 encoder;
String auth = SecuritySettings.ControllerUser;
auth += ":";
auth += SecuritySettings.ControllerPassword;
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
}
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
return false;
}
statusLED(true);
if (connectionFailures)
connectionFailures--;
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String url = "/api/variables/";
url += URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
String data;
if (longValue)
data = String(longValue);
else
data = toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]);
String yourdata = "{\"type\": \"value\", \"valueOrExpression\": \"" + data + "\"}";
String hostName = host;
if (Settings.UseDNS)
hostName = Settings.ControllerHostName;
// This will send the request to the server
client.print(String("PATCH ") + url + " HTTP/1.1\r\n" +
authHeader +
"Host: " + hostName + "\r\n" +
"Content-Type:application/json\r\n" +
"Content-Length: " + yourdata.length() + "\r\n\r\n" +
yourdata);
unsigned long timer = millis() + 200;
while (!client.available() && millis() < timer)
delay(1);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
strcpy_P(log, PSTR("HTTP : Succes!"));
addLog(LOG_LEVEL_DEBUG, log);
success = true;
}
delay(1);
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
}
#endif
+239
View File
@@ -0,0 +1,239 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//########################### Controller Plugin 025: Generic HTTP #######################################
//#######################################################################################################
#define CPLUGIN_025
#define CPLUGIN_ID_025 25
#define CPLUGIN_NAME_025 "Generic HTTP TEST [DEVELOPMENT]"
#define P025_HTTP_METHOD_MAX_LEN 16
#define P025_HTTP_URI_MAX_LEN 240
#define P025_HTTP_HEADER_MAX_LEN 256
#define P025_HTTP_BODY_MAX_LEN 512
struct P025_ConfigStruct
{
char HttpMethod[P025_HTTP_METHOD_MAX_LEN];
char HttpUri[P025_HTTP_URI_MAX_LEN];
char HttpHeader[P025_HTTP_HEADER_MAX_LEN];
char HttpBody[P025_HTTP_BODY_MAX_LEN];
};
boolean CPlugin_025(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_025;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = false;
Protocol[protocolCount].defaultPort = 80;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_025);
break;
}
case CPLUGIN_WEBFORM_LOAD:
{
P025_ConfigStruct customConfig;
LoadCustomControllerSettings((byte*)&customConfig, sizeof(customConfig));
String methods[] = { F("GET"), F("POST"), F("PUT") };
string += F("<TR><TD>HTTP Method :<TD><select name='P025httpmethod'>");
for (int i = 0; i < 3; i++)
{
string += F("<option value='");
string += methods[i] + "'";
string += methods[i].equals(customConfig.HttpMethod) ? F(" selected='selected'") : F("");
string += F(">");
string += methods[i];
string += F("</option>");
}
string += F("</select>");
string += F("<TR><TD>HTTP URI:<TD><input type='text' name='P025httpuri' size=80 maxlength='");
string += P025_HTTP_URI_MAX_LEN-1;
string += F("' value='");
string += customConfig.HttpUri;
string += F("'>");
string += F("<TR><TD>HTTP Header:<TD><textarea name='P025httpheader' rows='4' cols='50' maxlength='");
string += P025_HTTP_HEADER_MAX_LEN-1;
string += F("'>");
string += customConfig.HttpHeader;
string += F("</textarea>");
string += F("<TR><TD>HTTP Body:<TD><textarea name='P025httpbody' rows='8' cols='50' maxlength='");
string += P025_HTTP_BODY_MAX_LEN-1;
string += F("'>");
string += customConfig.HttpBody;
string += F("</textarea>");
break;
}
case CPLUGIN_WEBFORM_SAVE:
{
P025_ConfigStruct customConfig;
String httpmethod = WebServer.arg("P025httpmethod");
String httpuri = WebServer.arg("P025httpuri");
String httpheader = WebServer.arg("P025httpheader");
String httpbody = WebServer.arg("P025httpbody");
strncpy(customConfig.HttpMethod, httpmethod.c_str(), sizeof(customConfig.HttpMethod));
strncpy(customConfig.HttpUri, httpuri.c_str(), sizeof(customConfig.HttpUri));
strncpy(customConfig.HttpHeader, httpheader.c_str(), sizeof(customConfig.HttpHeader));
strncpy(customConfig.HttpBody, httpbody.c_str(), sizeof(customConfig.HttpBody));
SaveCustomControllerSettings((byte*)&customConfig, sizeof(customConfig));
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
case SENSOR_TYPE_SWITCH:
case SENSOR_TYPE_DIMMER:
HTTPSend025(event, 0, UserVar[event->BaseVarIndex], 0);
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
HTTPSend025(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
break;
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
{
HTTPSend025(event, 0, UserVar[event->BaseVarIndex], 0);
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
HTTPSend025(event, 1, UserVar[event->BaseVarIndex + 1], 0);
break;
}
case SENSOR_TYPE_TEMP_HUM_BARO:
{
HTTPSend025(event, 0, UserVar[event->BaseVarIndex], 0);
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
HTTPSend025(event, 1, UserVar[event->BaseVarIndex + 1], 0);
timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
HTTPSend025(event, 2, UserVar[event->BaseVarIndex + 2], 0);
break;
}
}
break;
}
}
return success;
}
//********************************************************************************
// Generic HTTP get request
//********************************************************************************
boolean HTTPSend025(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
P025_ConfigStruct customConfig;
LoadCustomControllerSettings((byte*)&customConfig, sizeof(customConfig));
char log[80];
boolean success = false;
char host[20];
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host, Settings.ControllerPort);
addLog(LOG_LEVEL_DEBUG, log);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
return false;
}
statusLED(true);
if (connectionFailures)
connectionFailures--;
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String hostName = host;
if (Settings.UseDNS)
hostName = Settings.ControllerHostName;
String payload = String(customConfig.HttpMethod) + " /";
payload += customConfig.HttpUri;
payload += String(" HTTP/1.1\r\n") +
"Host: " + hostName + ":" + Settings.ControllerPort + "\r\n" +
"Connection: close\r\n";
if (strlen(customConfig.HttpHeader) > 0)
payload += customConfig.HttpHeader;
ReplaceTokenByValue(payload, event, varIndex, value, longValue);
if (strlen(customConfig.HttpBody) > 0)
{
String body = String(customConfig.HttpBody);
ReplaceTokenByValue(body, event, varIndex, value, longValue);
payload += "\r\nContent-Length: " + String(body.length());
payload += "\r\n\r\n" + body;
}
// This will send the request to the server
client.print(payload);
unsigned long timer = millis() + 200;
while (!client.available() && millis() < timer)
delay(1);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 10) == "HTTP/1.1 2")
{
strcpy_P(log, PSTR("HTTP : Succes!"));
addLog(LOG_LEVEL_DEBUG, log);
success = true;
}
delay(1);
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
}
//********************************************************************************
// Replace the token in a string by real value.
//********************************************************************************
void ReplaceTokenByValue(String& s, struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
s.replace("%sysname%", URLEncode(Settings.Name));
s.replace("%tskname%", URLEncode(ExtraTaskSettings.TaskDeviceName));
s.replace("%id%", String(event->idx));
s.replace("%valname%", URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
if (longValue)
s.replace("%value%", String(longValue));
else
s.replace("%value%", toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
}
#endif
+85 -56
View File
@@ -6,9 +6,6 @@
#define PLUGIN_ID_001 1
#define PLUGIN_NAME_001 "Switch input"
#define PLUGIN_VALUENAME1_001 "Switch"
Servo servo1;
Servo servo2;
boolean Plugin_001(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -52,8 +49,22 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
String options[2];
options[0] = F("Switch");
options[1] = F("Dimmer");
int optionValues[2] = { 1, 2 };
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, choice);
int optionValues[2];
optionValues[0] = 1;
optionValues[1] = 2;
string += F("<TR><TD>Switch Type:<TD><select name='plugin_001_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>");
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
@@ -67,10 +78,29 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
buttonOptions[0] = F("Normal Switch");
buttonOptions[1] = F("Push Button Active Low");
buttonOptions[2] = F("Push Button Active High");
addFormSelector(string, F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, NULL, choice);
int buttonOptionValues[3];
buttonOptionValues[0] = 0;
buttonOptionValues[1] = 1;
buttonOptionValues[2] = 2;
string += F("<TR><TD>Switch Button Type:<TD><select name='plugin_001_button'>");
for (byte x = 0; x < 3; x++)
{
string += F("<option value='");
string += buttonOptionValues[x];
string += "'";
if (choice == buttonOptionValues[x])
string += F(" selected");
string += ">";
string += buttonOptions[x];
string += F("</option>");
}
string += F("</select>");
addFormCheckBox(string, F("Send Boot state"),F("plugin_001_boot"),
Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
string += F("<TR><TD>Send Boot state:<TD>");
if (Settings.TaskDevicePluginConfig[event->TaskIndex][3])
string += F("<input type=checkbox name=plugin_001_boot checked>");
else
string += F("<input type=checkbox name=plugin_001_boot>");
success = true;
break;
@@ -78,15 +108,18 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_001_type"));
String plugin1 = WebServer.arg("plugin_001_type");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_001_dimvalue"));
String plugin2 = WebServer.arg("plugin_001_dimvalue");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
}
String plugin3 = WebServer.arg("plugin_001_button");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_001_button"));
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = isFormItemChecked(F("plugin_001_boot"));
String plugin4 = WebServer.arg("plugin_001_boot");
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = (plugin4 == "on");
success = true;
break;
@@ -191,6 +224,40 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
}
}
#ifdef PLUGIN_BUILD_TESTING
if (command == F("rtttl"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
{
pinMode(event->Par1, OUTPUT);
char sng[1024] ="";
string.replace("-","#");
string.toCharArray(sng, 1024);
play_rtttl(event->Par1, sng);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
log = String(F("SW : ")) + string;
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
}
}
if (command == F("tone"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
{
pinMode(event->Par1, OUTPUT);
tone(event->Par1, event->Par2, event->Par3);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
log = String(F("SW : ")) + string;
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
}
}
#endif
if (command == F("pwm"))
{
success = true;
@@ -208,11 +275,10 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
int32_t step_value = ((event->Par2 - prev_value) << 12) / event->Par3;
int32_t curr_value = prev_value << 12;
int16_t new_value;
int i = event->Par3;
while(i--){
curr_value += step_value;
int16_t new_value;
new_value = (uint16_t)(curr_value >> 12);
analogWrite(event->Par1, new_value);
delay(1);
@@ -265,14 +331,12 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
switch (event->Par1)
{
case 1:
//IRAM: doing servo stuff uses 740 bytes IRAM. (doesnt matter how many instances)
servo1.attach(event->Par2);
servo1.write(event->Par3);
myservo1.attach(event->Par2);
myservo1.write(event->Par3);
break;
case 2:
servo2.attach(event->Par2);
servo2.write(event->Par3);
myservo2.attach(event->Par2);
myservo2.write(event->Par3);
break;
}
setPinState(PLUGIN_ID_001, event->Par2, PIN_MODE_SERVO, event->Par3);
@@ -297,41 +361,6 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
outputstate[event->Par1] = event->Par2;
}
#ifdef PLUGIN_BUILD_TESTING
//play a tune via a RTTTL string, look at https://www.letscontrolit.com/forum/viewtopic.php?f=4&t=343&hilit=speaker&start=10 for more info.
if (command == F("rtttl"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
{
pinMode(event->Par1, OUTPUT);
char sng[1024] ="";
string.replace("-","#");
string.toCharArray(sng, 1024);
play_rtttl(event->Par1, sng);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
log = String(F("SW : ")) + string;
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
}
}
//play a tone on pin par1, with frequency par2 and duration par3.
if (command == F("tone"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
{
pinMode(event->Par1, OUTPUT);
tone(event->Par1, event->Par2, event->Par3);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
log = String(F("SW : ")) + string;
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
}
}
#endif
break;
}
+56
View File
@@ -0,0 +1,56 @@
//#######################################################################################################
//#################################### Plugin 002: Analog ###############################################
//#######################################################################################################
#define PLUGIN_002
#define PLUGIN_ID_002 2
#define PLUGIN_NAME_002 "Analog input"
#define PLUGIN_VALUENAME1_002 "Analog"
boolean Plugin_002(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_002;
Device[deviceCount].Type = DEVICE_TYPE_ANALOG;
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_002);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_002));
break;
}
case PLUGIN_READ:
{
int value = analogRead(A0);
UserVar[event->BaseVarIndex] = (float)value;
String log = F("ADC : Analog value: ");
log += value;
addLog(LOG_LEVEL_INFO,log);
success = true;
break;
}
}
return success;
}
+55 -58
View File
@@ -9,16 +9,14 @@
#define PLUGIN_VALUENAME2_003 "Total"
#define PLUGIN_VALUENAME3_003 "Time"
void Plugin_003_pulse_interrupt1() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt2() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt3() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt4() ICACHE_RAM_ATTR;
//this takes 20 bytes of IRAM per handler
// void Plugin_003_pulse_interrupt5() ICACHE_RAM_ATTR;
// void Plugin_003_pulse_interrupt6() ICACHE_RAM_ATTR;
// void Plugin_003_pulse_interrupt7() ICACHE_RAM_ATTR;
// void Plugin_003_pulse_interrupt8() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt5() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt6() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt7() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt8() ICACHE_RAM_ATTR;
unsigned long Plugin_003_pulseCounter[TASKS_MAX];
unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX];
@@ -64,39 +62,46 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("Debounce Time (mSec)"), F("plugin_003")
, Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Debounce Time (mSec):<TD><input type='text' name='plugin_003' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += tmpString;
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
String options[4] = { F("Delta"), F("Delta/Total/Time"), F("Total"), F("Delta/Total") };
addFormSelector(string, F("Counter Type"), F("plugin_003_countertype"), 4, options, NULL, choice );
String options[3];
options[0] = F("Delta");
options[1] = F("Delta/Total/Time");
options[2] = F("Total");
int optionValues[3];
optionValues[0] = 0;
optionValues[1] = 1;
optionValues[2] = 2;
string += F("<TR><TD>Counter Type:<TD><select name='plugin_003_countertype'>");
for (byte x = 0; x < 3; 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>");
if (choice !=0)
string += F("<span style=\"color:red\">Total count is not persistent!</span>");
String modeRaise[4];
modeRaise[0] = F("LOW");
modeRaise[1] = F("CHANGE");
modeRaise[2] = F("RISING");
modeRaise[3] = F("FALLING");
int modeValues[4];
modeValues[0] = LOW;
modeValues[1] = CHANGE;
modeValues[2] = RISING;
modeValues[3] = FALLING;
addFormSelector(string, F("Mode Type"), F("plugin_003_raisetype"), 4, modeRaise, modeValues, choice2 );
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_003"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_003_countertype"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_003_raisetype"));
String plugin1 = WebServer.arg("plugin_003");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg("plugin_003_countertype");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
success = true;
break;
}
@@ -126,7 +131,8 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
log += Settings.TaskDevicePin1[event->TaskIndex];
addLog(LOG_LEVEL_INFO,log);
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
success = Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex,Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex);
success = true;
break;
}
@@ -158,13 +164,6 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex];
break;
}
case 3:
{
event->sensorType = SENSOR_TYPE_DUAL;
UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex];
UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
break;
}
}
Plugin_003_pulseCounter[event->TaskIndex] = 0;
success = true;
@@ -231,39 +230,37 @@ void Plugin_003_pulse_interrupt8()
/*********************************************************************************************\
* Init Pulse Counters
\*********************************************************************************************/
bool Plugin_003_pulseinit(byte Par1, byte Index, byte Mode)
void Plugin_003_pulseinit(byte Par1, byte Index)
{
// Init IO pins
String log = F("PULSE: Init");
addLog(LOG_LEVEL_INFO,log);
switch (Index)
{
case 0:
attachInterrupt(Par1, Plugin_003_pulse_interrupt1, Mode);
attachInterrupt(Par1, Plugin_003_pulse_interrupt1, FALLING);
break;
case 1:
attachInterrupt(Par1, Plugin_003_pulse_interrupt2, Mode);
attachInterrupt(Par1, Plugin_003_pulse_interrupt2, FALLING);
break;
case 2:
attachInterrupt(Par1, Plugin_003_pulse_interrupt3, Mode);
attachInterrupt(Par1, Plugin_003_pulse_interrupt3, FALLING);
break;
case 3:
attachInterrupt(Par1, Plugin_003_pulse_interrupt4, Mode);
attachInterrupt(Par1, Plugin_003_pulse_interrupt4, FALLING);
break;
case 4:
attachInterrupt(Par1, Plugin_003_pulse_interrupt5, FALLING);
break;
case 5:
attachInterrupt(Par1, Plugin_003_pulse_interrupt6, FALLING);
break;
case 6:
attachInterrupt(Par1, Plugin_003_pulse_interrupt7, FALLING);
break;
case 7:
attachInterrupt(Par1, Plugin_003_pulse_interrupt8, FALLING);
break;
// case 4:
// attachInterrupt(Par1, Plugin_003_pulse_interrupt5, Mode);
// break;
// case 5:
// attachInterrupt(Par1, Plugin_003_pulse_interrupt6, Mode);
// break;
// case 6:
// attachInterrupt(Par1, Plugin_003_pulse_interrupt7, Mode);
// break;
// case 7:
// attachInterrupt(Par1, Plugin_003_pulse_interrupt8, Mode);
// break;
default:
addLog(LOG_LEVEL_ERROR,F("PULSE: Error, only the first 4 tasks can be pulse counters."));
return(false);
}
return(true);
}
+471
View File
@@ -0,0 +1,471 @@
//#######################################################################################################
//#################################### Plugin 004: TempSensor Dallas DS18B20 ###########################
//#######################################################################################################
#define PLUGIN_004
#define PLUGIN_ID_004 4
#define PLUGIN_NAME_004 "Temperature - DS18b20"
#define PLUGIN_VALUENAME1_004 "Temperature"
uint8_t Plugin_004_DallasPin;
boolean Plugin_004(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_004;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
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_004);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_004));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
uint8_t addr[8];
// Scan the onewire bus and fill dropdown list with devicecount on this GPIO.
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
byte devCount = Plugin_004_DS_scan(choice, addr);
string += F("<TR><TD>Device Nr:<TD><select name='plugin_004_dev'>");
for (byte x = 0; x < devCount; x++)
{
string += F("<option value='");
string += x;
string += "'";
if (choice == x)
string += F(" selected");
string += ">";
string += x + 1;
string += F("</option>");
}
string += F("</select> ROM: ");
if (devCount)
{
for (byte i = 0; i < 8; i++)
{
string += String(addr[i], HEX);
if (i < 7) string += "-";
}
}
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
uint8_t addr[8];
String plugin1 = WebServer.arg("plugin_004_dev");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
// find the address for selected device and store into extra tasksettings
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
byte devCount = Plugin_004_DS_scan(Settings.TaskDevicePluginConfig[event->TaskIndex][0], addr);
for (byte x = 0; x < 8; x++)
ExtraTaskSettings.TaskDevicePluginConfigLong[x] = addr[x];
success = true;
break;
}
case PLUGIN_WEBFORM_SHOW_CONFIG:
{
for (byte x = 0; x < 8; x++)
{
if (x != 0)
string += "-";
string += String(ExtraTaskSettings.TaskDevicePluginConfigLong[x], HEX);
}
success = true;
break;
}
case PLUGIN_READ:
{
uint8_t addr[8];
// Load ROM address from tasksettings
LoadTaskSettings(event->TaskIndex);
for (byte x = 0; x < 8; x++)
addr[x] = ExtraTaskSettings.TaskDevicePluginConfigLong[x];
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
float value = 0;
String log = F("DS : Temperature: ");
if (Plugin_004_DS_readTemp(addr, &value))
{
UserVar[event->BaseVarIndex] = value;
log += UserVar[event->BaseVarIndex];
success = true;
}
else
{
UserVar[event->BaseVarIndex] = NAN;
log += F("Error!");
}
log += (" (");
for (byte x = 0; x < 8; x++)
{
if (x != 0)
log += "-";
log += String(ExtraTaskSettings.TaskDevicePluginConfigLong[x], HEX);
}
log += ')';
addLog(LOG_LEVEL_INFO, log);
break;
}
}
return success;
}
/*********************************************************************************************\
Dallas Scan bus
\*********************************************************************************************/
byte Plugin_004_DS_scan(byte getDeviceROM, uint8_t* ROM)
{
byte tmpaddr[8];
byte devCount = 0;
Plugin_004_DS_reset();
Plugin_004_DS_reset_search();
while (Plugin_004_DS_search(tmpaddr))
{
if (getDeviceROM == devCount)
for (byte i = 0; i < 8; i++)
ROM[i] = tmpaddr[i];
devCount++;
}
return devCount;
}
/*********************************************************************************************\
Dallas Read temperature
\*********************************************************************************************/
boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float *value)
{
int16_t DSTemp;
byte ScratchPad[12];
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
Plugin_004_DS_write(ROM[i]);
Plugin_004_DS_write(0x44);
delay(800);
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
Plugin_004_DS_write(ROM[i]);
Plugin_004_DS_write(0xBE); // Read scratchpad
for (byte i = 0; i < 9; i++) // copy 8 bytes
ScratchPad[i] = Plugin_004_DS_read();
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
{
*value = 0;
return false;
}
if ((ROM[0] == 0x28 ) || (ROM[0] == 0x3b)) //DS18B20 or DS1825
{
DSTemp = (ScratchPad[1] << 8) + ScratchPad[0];
*value = (float(DSTemp) * 0.0625);
}
else if (ROM[0] == 0x10 ) //DS1820 DS18S20
{
DSTemp = (ScratchPad[1] << 11) | ScratchPad[0] << 3;
DSTemp = ((DSTemp & 0xfff0) << 3) - 16 +
(
((ScratchPad[7] - ScratchPad[6]) << 7) /
ScratchPad[7]
);
*value = float(DSTemp) * 0.0078125;
}
return true;
}
/*********************************************************************************************\
Dallas Reset
\*********************************************************************************************/
uint8_t Plugin_004_DS_reset()
{
uint8_t r;
uint8_t retries = 125;
//noInterrupts();
pinMode(Plugin_004_DallasPin, INPUT);
do { // wait until the wire is high... just in case
if (--retries == 0) return 0;
delayMicroseconds(2);
} while ( !digitalRead(Plugin_004_DallasPin));
pinMode(Plugin_004_DallasPin, OUTPUT); digitalWrite(Plugin_004_DallasPin, LOW);
delayMicroseconds(492); // Dallas spec. = Min. 480uSec. Arduino 500uSec.
pinMode(Plugin_004_DallasPin, INPUT); //Float
delayMicroseconds(40);
r = !digitalRead(Plugin_004_DallasPin);
delayMicroseconds(420);
//interrupts();
return r;
}
#define FALSE 0
#define TRUE 1
unsigned char ROM_NO[8];
uint8_t LastDiscrepancy;
uint8_t LastFamilyDiscrepancy;
uint8_t LastDeviceFlag;
/*********************************************************************************************\
Dallas Reset Search
\*********************************************************************************************/
void Plugin_004_DS_reset_search()
{
// reset the search state
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
for (byte i = 0; i < 8; i++)
ROM_NO[i] = 0;
}
/*********************************************************************************************\
Dallas Search bus
\*********************************************************************************************/
uint8_t Plugin_004_DS_search(uint8_t *newAddr)
{
uint8_t id_bit_number;
uint8_t last_zero, rom_byte_number, search_result;
uint8_t id_bit, cmp_id_bit;
unsigned char rom_byte_mask, search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
// if the last call was not the last one
if (!LastDeviceFlag)
{
// 1-Wire reset
if (!Plugin_004_DS_reset())
{
// reset the search
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
return FALSE;
}
// issue the search command
Plugin_004_DS_write(0xF0);
// loop to do the search
do
{
// read a bit and its complement
id_bit = Plugin_004_DS_read_bit();
cmp_id_bit = Plugin_004_DS_read_bit();
// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else
{
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit; // bit write value for search
else
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < LastDiscrepancy)
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == LastDiscrepancy);
// if 0 was picked then record its position in LastZero
if (search_direction == 0)
{
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy = last_zero;
}
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == 1)
ROM_NO[rom_byte_number] |= rom_byte_mask;
else
ROM_NO[rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
Plugin_004_DS_write_bit(search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0)
{
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65))
{
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
LastDiscrepancy = last_zero;
// check for last device
if (LastDiscrepancy == 0)
LastDeviceFlag = TRUE;
search_result = TRUE;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[0])
{
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
search_result = FALSE;
}
for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
return search_result;
}
/*********************************************************************************************\
Dallas Read byte
\*********************************************************************************************/
uint8_t Plugin_004_DS_read(void)
{
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1)
if (Plugin_004_DS_read_bit())
r |= bitMask;
return r;
}
/*********************************************************************************************\
Dallas Write byte
\*********************************************************************************************/
void Plugin_004_DS_write(uint8_t ByteToWrite)
{
uint8_t bitMask;
for (bitMask = 0x01; bitMask; bitMask <<= 1)
Plugin_004_DS_write_bit( (bitMask & ByteToWrite) ? 1 : 0);
}
/*********************************************************************************************\
Dallas Read bit
\*********************************************************************************************/
uint8_t Plugin_004_DS_read_bit(void)
{
uint8_t r;
//noInterrupts();
pinMode(Plugin_004_DallasPin, OUTPUT);
digitalWrite(Plugin_004_DallasPin, LOW);
delayMicroseconds(3);
pinMode(Plugin_004_DallasPin, INPUT); // let pin float, pull up will raise
delayMicroseconds(10);
r = digitalRead(Plugin_004_DallasPin);
//interrupts();
delayMicroseconds(53);
return r;
}
/*********************************************************************************************\
Dallas Write bit
\*********************************************************************************************/
void Plugin_004_DS_write_bit(uint8_t v)
{
if (v & 1) {
//noInterrupts();
digitalWrite(Plugin_004_DallasPin, LOW);
pinMode(Plugin_004_DallasPin, OUTPUT);
delayMicroseconds(10);
digitalWrite(Plugin_004_DallasPin, HIGH);
//interrupts();
delayMicroseconds(55);
} else {
//noInterrupts();
digitalWrite(Plugin_004_DallasPin, LOW);
pinMode(Plugin_004_DallasPin, OUTPUT);
delayMicroseconds(65);
digitalWrite(Plugin_004_DallasPin, HIGH);
//interrupts();
delayMicroseconds(5);
}
}
uint8_t Plugin_004_DS_crc8( uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
+30 -10
View File
@@ -4,7 +4,7 @@
#define PLUGIN_005
#define PLUGIN_ID_005 5
#define PLUGIN_NAME_005 "Environment - DHT11/12/22"
#define PLUGIN_NAME_005 "Temperature & Humidity - DHT"
#define PLUGIN_VALUENAME1_005 "Temperature"
#define PLUGIN_VALUENAME2_005 "Humidity"
@@ -47,10 +47,28 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
const String options[] = { F("DHT 11"), F("DHT 22"), F("DHT 12") };
int indices[] = { 11, 22, 12 };
addFormSelector(string, F("DHT Type"), F("plugin_005_dhttype"), 3, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[3];
options[0] = F("DHT 11");
options[1] = F("DHT 22");
options[2] = F("DHT 12");
int optionValues[3];
optionValues[0] = 11;
optionValues[1] = 22;
optionValues[2] = 12;
string += F("<TR><TD>DHT Type:<TD><select name='plugin_005_dhttype'>");
for (byte x = 0; x < 3; 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;
@@ -58,8 +76,8 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_005_dhttype"));
String plugin1 = WebServer.arg("plugin_005_dhttype");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
@@ -99,7 +117,7 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
dht_dat[i] = data;
else
{
addLog(LOG_LEVEL_ERROR, F("DHT : protocol timeout!"));
addLog(LOG_LEVEL_ERROR, (char*)"DHT : protocol timeout!");
error = true;
}
}
@@ -114,7 +132,7 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
{
float temperature = NAN;
float humidity = NAN;
if (Par3 == 11)
{
temperature = float(dht_dat[2]); // Temperature
@@ -153,7 +171,8 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
} // !dht
if(!success)
{
addLog(LOG_LEVEL_INFO, F("DHT : No reading!"));
String log = F("DHT : No reading!");
addLog(LOG_LEVEL_INFO, log);
UserVar[event->BaseVarIndex] = NAN;
UserVar[event->BaseVarIndex + 1] = NAN;
}
@@ -203,3 +222,4 @@ int Plugin_005_read_dht_dat(void)
//interrupts();
return result;
}
+7 -5
View File
@@ -4,12 +4,10 @@
#define PLUGIN_006
#define PLUGIN_ID_006 6
#define PLUGIN_NAME_006 "Environment - BMP085/180"
#define PLUGIN_NAME_006 "Temperature & Pressure - BMP085"
#define PLUGIN_VALUENAME1_006 "Temperature"
#define PLUGIN_VALUENAME2_006 "Pressure"
// TODO this will not work if we have more than one of this task!
boolean Plugin_006_init = false;
boolean Plugin_006(byte function, struct EventStruct *event, String& string)
@@ -49,14 +47,18 @@ boolean Plugin_006(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("Altitude [m]"), F("_p006_bmp085_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
string += F("<TR><TD>Altitude [m]:<TD><input type='text' title='Set Altitude to 0 to get measurement without altitude adjustment' name='");
string += F("_p006_bmp085_elev' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][1];
string += F("'>");
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("_p006_bmp085_elev"));
String elev = WebServer.arg("_p006_bmp085_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
}
@@ -2,6 +2,20 @@
//#################################### Plugin 007: ExtWiredAnalog #######################################
//#######################################################################################################
/*********************************************************************************************\
* This plugin provides support for 4 extra analog inputs, using the PCF8591 (NXP/Philips)
* Support : www.esp8266.nu
* Date : Apr 2015
* Compatibility : R004
* Syntax : "ExtWiredAnalog <Par1:Port>, <Par2:Variable>"
*********************************************************************************************
* Technical description:
*
* The PCF8591 is a IO Expander chip that connects through the I2C bus
* Basic I2C address = 0x48
* Each chip has 4 analog inputs
* This commando reads the analog input and stores the result into a variable
\*********************************************************************************************/
#define PLUGIN_007
#define PLUGIN_ID_007 7
#define PLUGIN_NAME_007 "Analog input - PCF8591"
+1 -1
View File
@@ -115,4 +115,4 @@ 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
}
+9 -3
View File
@@ -46,7 +46,11 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormCheckBox(string, F("Send Boot state") ,F("plugin_009_boot"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += F("<TR><TD>Send Boot state:<TD>");
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
string += F("<input type=checkbox name=plugin_009_boot checked>");
else
string += F("<input type=checkbox name=plugin_009_boot>");
success = true;
break;
@@ -54,7 +58,9 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = isFormItemChecked(F("plugin_009_boot"));
String plugin1 = WebServer.arg("plugin_009_boot");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = (plugin1 == "on");
success = true;
break;
@@ -305,4 +311,4 @@ boolean Plugin_009_Config(byte Par1, byte Par2)
Wire.endTransmission();
}
}
+133
View File
@@ -0,0 +1,133 @@
//#######################################################################################################
//#################################### Plugin-010: LuxRead ############################################
//#######################################################################################################
#define PLUGIN_010
#define PLUGIN_ID_010 10
#define PLUGIN_NAME_010 "Luminosity - BH1750"
#define PLUGIN_VALUENAME1_010 "Lux"
#define BH1750_ADDRESS_1 0x23
#define BH1750_ADDRESS_2 0x5c
boolean Plugin_010_init_1 = false;
boolean Plugin_010_init_2 = false;
boolean Plugin_010(byte function, struct EventStruct *event, String& string)
{
boolean success=false;
switch(function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_010;
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_010);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_010));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2];
options[0] = F("0x23 - default settings (ADDR Low)");
options[1] = F("0x5c - alternate settings (ADDR High)");
int optionValues[2];
optionValues[0] = 0;
optionValues[1] = 1;
string += F("<TR><TD>I2C Address:<TD><select name='plugin_010'>");
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("plugin_010");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
case PLUGIN_READ:
{
uint8_t address = -1;
boolean *Plugin_010_init;
if(Settings.TaskDevicePluginConfig[event->TaskIndex][0]==0)
{
address = BH1750_ADDRESS_1;
Plugin_010_init = &Plugin_010_init_1;
}
else
{
address = BH1750_ADDRESS_2;
Plugin_010_init = &Plugin_010_init_2;
}
if (!*Plugin_010_init)
{
*Plugin_010_init = Plugin_010_setResolution(address);
}
if (Wire.requestFrom(address, (uint8_t)2) == 2)
{
byte b1 = Wire.read();
byte b2 = Wire.read();
float val = 0xffff; //pm-cz: Maximum obtainable value
if (b1 != 0xff || b2 != 0xff) { //pm-cz: Add maximum range check
val=((b1<<8)|b2)/1.2;
}
UserVar[event->BaseVarIndex] = val;
String log = F("LUX 0x");
log += String(address,HEX);
log += F(" : Light intensity: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO,log);
success=true;
}
break;
}
}
return success;
}
boolean Plugin_010_setResolution(uint8_t address){
Wire.beginTransmission(address);
Wire.write(0x10); // 1 lx resolution
Wire.endTransmission();
return true;
}
+22 -3
View File
@@ -46,8 +46,25 @@ boolean Plugin_011(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2] = { F("Digital"), F("Analog") };
addFormSelector(string, F("Port Type"), F("plugin_011"), 2, options, NULL, choice);
String options[2];
options[0] = F("Digital");
options[1] = F("Analog");
int optionValues[2];
optionValues[0] = 0;
optionValues[1] = 1;
string += F("<TR><TD>Port Type:<TD><select name='plugin_011'>");
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;
@@ -55,7 +72,8 @@ boolean Plugin_011(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_011"));
String plugin1 = WebServer.arg("plugin_011");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
@@ -211,3 +229,4 @@ boolean Plugin_011_Write(byte Par1, byte Par2)
Wire.write((Par2 >> 8));
Wire.endTransmission();
}
+39 -14
View File
@@ -8,8 +8,6 @@
// Lux:[Lux#Lux#R]
// Baro:[Baro#Pressure#R]
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd;
#define PLUGIN_012
@@ -55,25 +53,47 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
//String options[16];
int optionValues[16];
for (byte x = 0; x < 16; x++)
{
for (byte x = 0; x < 17; x++)
if (x < 8)
optionValues[x] = 0x20 + x;
else
optionValues[x] = 0x30 + x;
//options[x] = F("0x");
//options[x] += String(optionValues[x], HEX);
string += F("<TR><TD>I2C Address:<TD><select name='plugin_012_adr'>");
for (byte x = 0; x < 16; x++)
{
string += F("<option value='");
string += optionValues[x];
string += "'";
if (choice == optionValues[x])
string += F(" selected");
string += ">";
string += String(optionValues[x], HEX);
string += F("</option>");
}
addFormSelectorI2C(string, F("plugin_012_adr"), 16, optionValues, choice);
string += F("</select>");
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options2[2];
options2[0] = F("2 x 16");
options2[1] = F("4 x 20");
int optionValues2[2] = { 1, 2 };
addFormSelector(string, F("Display Size"), F("plugin_012_size"), 2, options2, optionValues2, choice2);
int optionValues2[2];
optionValues2[0] = 1;
optionValues2[1] = 2;
string += F("<TR><TD>Display Size:<TD><select name='plugin_012_size'>");
for (byte x = 0; x < 2; x++)
{
string += F("<option value='");
string += optionValues2[x];
string += "'";
if (choice2 == optionValues2[x])
string += F(" selected");
string += ">";
string += options2[x];
string += F("</option>");
}
string += F("</select>");
char deviceTemplate[4][80];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
@@ -102,9 +122,12 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_012_adr"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_012_size"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_12_timer"));
String plugin1 = WebServer.arg("plugin_012_adr");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg("plugin_012_size");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
String plugin3 = WebServer.arg("plugin_12_timer");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
char deviceTemplate[4][80];
for (byte varNr = 0; varNr < 4; varNr++)
@@ -117,6 +140,8 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr]));
}
Settings.TaskDeviceID[event->TaskIndex] = 1; // temp fix, needs a dummy value
SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
success = true;
break;
@@ -228,4 +253,4 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
}
return success;
}
}
+25 -6
View File
@@ -49,7 +49,7 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_013));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
@@ -57,12 +57,28 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
String options[2];
options[0] = F("Value");
options[1] = F("State");
int optionValues[2] = { 1, 2 };
addFormSelector(string, F("Mode"), F("plugin_013_mode"), 2, options, optionValues, choice);
int optionValues[2];
optionValues[0] = 1;
optionValues[1] = 2;
string += F("<TR><TD>Mode:<TD><select name='plugin_013_mode'>");
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>");
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
addFormNumericBox(string, F("Threshold"), F("plugin_013_threshold"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Threshold:<TD><input type='text' name='plugin_013_threshold' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
string += tmpString;
}
success = true;
break;
@@ -70,10 +86,12 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_013_mode"));
String plugin1 = WebServer.arg("plugin_013_mode");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_013_threshold"));
String plugin2 = WebServer.arg("plugin_013_threshold");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
}
success = true;
break;
@@ -180,3 +198,4 @@ void Plugin_013_interrupt()
Plugin_013_timer = micros() - Plugin_013_timer;
}
}
+52 -35
View File
@@ -5,14 +5,14 @@
#define PLUGIN_014
#define PLUGIN_ID_014 14
#define PLUGIN_NAME_014 "Environment - SI7021/HTU21D"
#define PLUGIN_NAME_014 "Temperature & Humidity - SI7021"
#define PLUGIN_VALUENAME1_014 "Temperature"
#define PLUGIN_VALUENAME2_014 "Humidity"
boolean Plugin_014_init = false;
// ======================================
// SI7021 sensor
// SI7021 sensor
// ======================================
#define SI7021_I2C_ADDRESS 0x40 // I2C address for the sensor
#define SI7021_MEASURE_TEMP_HUM 0xE0 // Measure Temp only after a RH conversion done
@@ -85,8 +85,20 @@ boolean Plugin_014(byte function, struct EventStruct *event, String& string)
options[2] = F("Temp 12 bits / RH 8 bits");
optionValues[3] = SI7021_RESOLUTION_11T_11RH;
options[3] = F("Temp 11 bits / RH 11 bits");
addFormSelector(string, F("Resolution"), F("plugin_014_res"), SI7021_RESOLUTION_OPTION, options, optionValues, choice);
//addUnit(string, F("bits"));
string += F("<TR><TD>Resolution (bits):<TD><select name='plugin_014_res'>");
for (byte x = 0; x < SI7021_RESOLUTION_OPTION; 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;
@@ -94,7 +106,8 @@ boolean Plugin_014(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_014_res"));
String plugin1 = WebServer.arg("plugin_014_res");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
Plugin_014_init = false; // Force device setup next time
success = true;
break;
@@ -123,7 +136,8 @@ boolean Plugin_014(byte function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_INFO,log);
*/
} else {
addLog(LOG_LEVEL_INFO,F("SI7021 : Read Error!"));
String log = F("SI7021 : Read Error!");
addLog(LOG_LEVEL_INFO,log);
}
break;
@@ -157,7 +171,7 @@ boolean Plugin_014_si7021_begin(uint8_t resolution)
ret = false;
}
return ret;
return ret;
}
/* ======================================================================
@@ -172,7 +186,7 @@ uint8_t Plugin_014_si7021_checkCRC(uint16_t data, uint8_t check)
uint32_t remainder, divisor;
//Pad with 8 bits because we have to add in the check value
remainder = (uint32_t)data << 8;
remainder = (uint32_t)data << 8;
// From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html
// POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks
@@ -180,17 +194,17 @@ uint8_t Plugin_014_si7021_checkCRC(uint16_t data, uint8_t check)
divisor = (uint32_t) 0x988000;
// Add the check value
remainder |= check;
remainder |= check;
// Operate on only 16 positions of max 24.
// Operate on only 16 positions of max 24.
// The remaining 8 are our remainder and should be zero when we're done.
for (uint8_t i = 0 ; i < 16 ; i++) {
//Check if there is a one in the left position
if( remainder & (uint32_t)1<<(23 - i) )
if( remainder & (uint32_t)1<<(23 - i) )
remainder ^= divisor;
//Rotate the divisor max 16 times so that we have 8 bits left of a remainder
divisor >>= 1;
divisor >>= 1;
}
return ((uint8_t) remainder);
}
@@ -204,25 +218,26 @@ Comments: -
====================================================================== */
int8_t Plugin_014_si7021_readRegister(uint8_t * value)
{
uint8_t error ;
// Request user register
Wire.beginTransmission(SI7021_I2C_ADDRESS);
Wire.write(SI7021_READ_REG);
Wire.write(SI7021_READ_REG);
Wire.endTransmission();
// request 1 byte result
// request 1 byte result
Wire.requestFrom(SI7021_I2C_ADDRESS, 1);
if (Wire.available()>=1) {
*value = Wire.read();
return 0;
}
return 1;
return 1;
}
/* ======================================================================
Function: Plugin_014_si7021_startConv
Purpose : return temperature or humidity measured
Purpose : return temperature or humidity measured
Input : data type SI7021_READ_HUM or SI7021_READ_TEMP
current config resolution
Output : 0 if okay
@@ -233,8 +248,9 @@ int8_t Plugin_014_si7021_startConv(uint8_t datatype, uint8_t resolution)
long data;
uint16_t raw ;
uint8_t checksum,tmp;
uint8_t error;
//Request a reading
//Request a reading
Wire.beginTransmission(SI7021_I2C_ADDRESS);
Wire.write(datatype);
Wire.endTransmission();
@@ -251,19 +267,19 @@ int8_t Plugin_014_si7021_startConv(uint8_t datatype, uint8_t resolution)
// So to be more safe, we add 5 ms to each and use 8,10,13,21 ms
// But for ESP Easy, I think it does not matter at all...
// Martinus is correct there was a bug Mesasure HUM need
// Martinus is correct there was a bug Mesasure HUM need
// hum+temp delay because it also measure temp
if (resolution == SI7021_RESOLUTION_11T_11RH)
tmp = 7;
else if (resolution == SI7021_RESOLUTION_12T_08RH)
tmp = 13;
else if (resolution == SI7021_RESOLUTION_13T_10RH)
tmp = 25;
else
else
tmp = 50;
// Humidity fire also temp measurment so delay
// Humidity fire also temp measurment so delay
// need to be increased by 2 if no Hold Master
if (datatype == SI7021_MEASURE_HUM)
tmp *=2;
@@ -273,14 +289,14 @@ int8_t Plugin_014_si7021_startConv(uint8_t datatype, uint8_t resolution)
/*
// Wait for data to become available, device will NACK during conversion
tmp = 0;
do
do
{
// Request device
Wire.beginTransmission(SI7021_I2C_ADDRESS);
//Wire.write(SI7021_READ_REG);
//Wire.write(SI7021_READ_REG);
error = Wire.endTransmission(true);
delay(1);
}
}
// always use time out in loop to avoid potential lockup (here 12ms max)
// https://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021-A20.pdf page 5
while(error!=0 && tmp++<=12 );
@@ -296,13 +312,14 @@ int8_t Plugin_014_si7021_startConv(uint8_t datatype, uint8_t resolution)
// Check CRC of data received
if(Plugin_014_si7021_checkCRC(raw, checksum) != 0) {
addLog(LOG_LEVEL_INFO,F("SI7021 : checksum error!"));
return -1;
String log = F("SI7021 : checksum error!");
addLog(LOG_LEVEL_INFO,log);
return -1;
}
// Humidity
// Humidity
if (datatype == SI7021_MEASURE_HUM || datatype == SI7021_MEASURE_HUM_HM) {
// Convert value to Himidity percent
// Convert value to Himidity percent
// pm-cz: it is possible to enable decimal places for humidity as well by multiplying the value in formula by 100
data = ((1250 * (long)raw) >> 16) - 60;
@@ -366,7 +383,7 @@ int8_t Plugin_014_si7021_readValues(uint8_t resolution)
/* ======================================================================
Function: Plugin_014_si7021_setResolution
Purpose : Sets the sensor resolution to one of four levels
Purpose : Sets the sensor resolution to one of four levels
Input : see #define default is SI7021_RESOLUTION_14T_12RH
Output : 0 if okay
Comments: -
@@ -380,16 +397,16 @@ int8_t Plugin_014_si7021_setResolution(uint8_t res)
error = Plugin_014_si7021_readRegister(&reg);
if ( error == 0) {
// remove resolution bits
reg &= SI7021_RESOLUTION_MASK ;
reg &= SI7021_RESOLUTION_MASK ;
// Prepare to write to the register value
Wire.beginTransmission(SI7021_I2C_ADDRESS);
Wire.write(SI7021_WRITE_REG);
Wire.write(SI7021_WRITE_REG);
// Write the new resolution bits but clear unused before
Wire.write(reg | ( res &= ~SI7021_RESOLUTION_MASK) );
Wire.write(reg | ( res &= ~SI7021_RESOLUTION_MASK) );
return (int8_t) Wire.endTransmission();
}
}
return error;
}
+360
View File
@@ -0,0 +1,360 @@
//#######################################################################################################
//######################## Plugin 015 TSL2561 I2C Lux Sensor ############################################
//#######################################################################################################
// 13-10-2015 Charles-Henri Hallard, see my projects and blog at https://hallard.me
#define PLUGIN_015
#define PLUGIN_ID_015 15
#define PLUGIN_NAME_015 "Luminosity - TLS2561"
#define PLUGIN_VALUENAME1_015 "Lux"
boolean Plugin_015_init = false;
// ======================================
// TSL2561 luminosity sensor
// ======================================
#define TSL2561_I2C_ADDRESS 0x39 // I2C address for the sensor
#define TSL2561_CONTROL 0x80
#define TSL2561_TIMING 0x81
#define TSL2561_INTERRUPT 0x86
#define TSL2561_CHANNEL_0L 0x8C
#define TSL2561_CHANNEL_0H 0x8D
#define TSL2561_CHANNEL_1L 0x8E
#define TSL2561_CHANNEL_1H 0x8F
// Control register bits
#define TSL2561_POWER_UP 0x03
#define TSL2561_POWER_DOWN 0x00
// Timing register bits
#define TSL2561_TIMING_13MS 0x00
#define TSL2561_TIMING_101MS 0x01
#define TSL2561_TIMING_402MS 0x02
#define TSL2561_TIMING_CUSTOM_STOP 0x03
#define TSL2561_TIMING_CUSTOM_START 0x0B
#define TSL2561_LUX_SCALE 14 // scale by 2^14
#define TSL2561_RATIO_SCALE 9 // scale ratio by 2^9
#define TSL2561_CH_SCALE 10 // scale channel values by 2^10
#define TSL2561_CHSCALE_TINT_13MS 0x7517 // 322/11 * 2^CH_SCALE (13ms)
#define TSL2561_CHSCALE_TINT_60MS 0x1800 // 322/48 * 2^CH_SCALE (60ms)
#define TSL2561_CHSCALE_TINT_101MS 0x0fe7 // 322/81 * 2^CH_SCALE (101ms)
#define TSL2561_CHSCALE_TINT_120MS 0x0D6B // 322/96 * 2^CH_SCALE (120ms)
#define TSL2561_CHSCALE_TINT_402MS (1 << TSL2561_CH_SCALE) // default No scaling
// Clipping thresholds
#define TSL2561_CLIPPING_13MS (4900)
#define TSL2561_CLIPPING_101MS (37000)
#define TSL2561_CLIPPING_402MS (65000)
#define TSL2561_K1T 0x0040 // 0.125 * 2^RATIO_SCALE
#define TSL2561_B1T 0x01f2 // 0.0304 * 2^LUX_SCALE
#define TSL2561_M1T 0x01be // 0.0272 * 2^LUX_SCALE
#define TSL2561_K2T 0x0080 // 0.250 * 2^RATIO_SCA
#define TSL2561_B2T 0x0214 // 0.0325 * 2^LUX_SCALE
#define TSL2561_M2T 0x02d1 // 0.0440 * 2^LUX_SCALE
#define TSL2561_K3T 0x00c0 // 0.375 * 2^RATIO_SCALE
#define TSL2561_B3T 0x023f // 0.0351 * 2^LUX_SCALE
#define TSL2561_M3T 0x037b // 0.0544 * 2^LUX_SCALE
#define TSL2561_K4T 0x0100 // 0.50 * 2^RATIO_SCALE
#define TSL2561_B4T 0x0270 // 0.0381 * 2^LUX_SCALE
#define TSL2561_M4T 0x03fe // 0.0624 * 2^LUX_SCALE
#define TSL2561_K5T 0x0138 // 0.61 * 2^RATIO_SCALE
#define TSL2561_B5T 0x016f // 0.0224 * 2^LUX_SCALE
#define TSL2561_M5T 0x01fc // 0.0310 * 2^LUX_SCALE
#define TSL2561_K6T 0x019a // 0.80 * 2^RATIO_SCALE
#define TSL2561_B6T 0x00d2 // 0.0128 * 2^LUX_SCALE
#define TSL2561_M6T 0x00fb // 0.0153 * 2^LUX_SCALE
#define TSL2561_K7T 0x029a // 1.3 * 2^RATIO_SCALE
#define TSL2561_B7T 0x0018 // 0.00146 * 2^LUX_SCALE
#define TSL2561_M7T 0x0012 // 0.00112 * 2^LUX_SCALE
#define TSL2561_K8T 0x029a // 1.3 * 2^RATIO_SCALE
#define TSL2561_B8T 0x0000 // 0.000 * 2^LUX_SCALE
#define TSL2561_M8T 0x0000 // 0.000 * 2^LUX_SCALE
uint16_t tsl2561_lux; // latest lux value read
boolean Plugin_015(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_015;
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_015);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_015));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
#define TLS2561_INTEGRATION_OPTION 3
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[TLS2561_INTEGRATION_OPTION];
int optionValues[TLS2561_INTEGRATION_OPTION];
optionValues[0] = TSL2561_TIMING_13MS;
options[0] = F("13 ms");
optionValues[1] = TSL2561_TIMING_101MS;
options[1] = F("101 ms");
optionValues[2] = TSL2561_TIMING_402MS;
options[2] = F("402 ms");
string += F("<TR><TD>Integration time:<TD><select name='plugin_015_integration'>");
for (byte x = 0; x < TLS2561_INTEGRATION_OPTION; 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("plugin_015_integration");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
Plugin_015_init = false; // Force device setup next time
success = true;
break;
}
case PLUGIN_READ:
{
// Get sensor resolution configuration
uint8_t integration = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
uint8_t ret;
if (!Plugin_015_init) {
Plugin_015_init = Plugin_015_tls2561_begin(integration);
}
// Read values if init ok
if (Plugin_015_init) {
ret = Plugin_015_tsl2561_calcLux(integration);
if (ret == 0) {
UserVar[event->BaseVarIndex] = tsl2561_lux;
success = true;
String log = F("TLS2561 : Lux: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO,log);
} else {
String log = F("TLS2561 : Read Error #");
log += String(ret,DEC);
addLog(LOG_LEVEL_INFO,log);
}
}
break;
}
}
return success;
}
/* ======================================================================
Function: Plugin_015_tls2561_begin
Purpose : read the user register from the sensor
Input : integration time
Output : true if okay
Comments: -
====================================================================== */
boolean Plugin_015_tls2561_begin(uint8_t integration)
{
uint8_t ret;
// Power UP device
ret = Plugin_015_tsl2561_writeRegister(TSL2561_CONTROL, TSL2561_POWER_UP);
if ( ret == 0 )
{
// I noticed 1st calculation after power up could be hazardous; so
// do a 1st dummy reading, with speed integration time, here 13ms
Plugin_015_tsl2561_writeRegister(TSL2561_TIMING, TSL2561_TIMING_13MS);
delay(15);
ret = true;
} else {
String log = F("TLS2561 : integration=0x");
log += String(integration,HEX);
log += F(" => Error 0x");
log += String(ret,HEX);
addLog(LOG_LEVEL_INFO,log);
ret = false;
}
return ret;
}
/* ======================================================================
Function: Plugin_015_tsl2561_readRegister
Purpose : read a register from the sensor
Input : register address
register value filled by function
Output : 0 if okay
Comments: -
====================================================================== */
uint8_t Plugin_015_tsl2561_readRegister(uint8_t reg, uint8_t * value)
{
Wire.beginTransmission(TSL2561_I2C_ADDRESS);
Wire.write(reg);
// all was fine ?
if ( Wire.endTransmission()==0 ) {
// request 1 byte and have it ?
if (Wire.requestFrom(TSL2561_I2C_ADDRESS, 1)==1) {
// return value
*value = Wire.read();
return 0;
}
}
return 1;
}
/* ======================================================================
Function: Plugin_015_tsl2561_writeRegister
Purpose : read a register from the sensor
Input : register address
Output : register value
Comments: 0 if okay
====================================================================== */
uint8_t Plugin_015_tsl2561_writeRegister(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(TSL2561_I2C_ADDRESS);
Wire.write(reg);
Wire.write(value);
return (Wire.endTransmission());
}
/* ======================================================================
Function: Plugin_015_tsl2561_calcLux
Purpose : start a conversion and return calculated lux
Input : integration time
Output : 0 if calculated value ok and updated
Comments: global lux value is updated
====================================================================== */
int8_t Plugin_015_tsl2561_calcLux(uint8_t integration)
{
unsigned long chScale;
unsigned long channel0, channel1;
unsigned long ratio, ratio1;
unsigned long lux;
unsigned int b, m;
uint16_t ch0,ch1;
uint16_t clipThreshold;
uint8_t msb, lsb;
uint8_t err = 0;
// do start calculation with speed integration time,
Plugin_015_tsl2561_writeRegister(TSL2561_TIMING, integration);
if (integration == TSL2561_TIMING_402MS ) {
chScale = TSL2561_CHSCALE_TINT_402MS ;
clipThreshold = TSL2561_CLIPPING_402MS ;
delay(405);
} else if (integration == TSL2561_TIMING_101MS ) {
chScale = TSL2561_CHSCALE_TINT_101MS ;
clipThreshold = TSL2561_CLIPPING_101MS ;
delay(103);
} else {
chScale = TSL2561_CHSCALE_TINT_13MS ;
clipThreshold = TSL2561_CLIPPING_13MS ;
delay(15);
}
// don't try to change reading order of LOW/HIGH, it will not work !!!!
// you must read LOW then HIGH
err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_0L, &lsb);
err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_0H, &msb);
ch0 = word(msb,lsb);
err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_1L, &lsb);
err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_1H, &msb);
ch1 = word(msb,lsb);;
// I2C error ?
if( err )
return -2;
/* Sensor saturated the lux is not valid in this situation */
if ((ch0 > clipThreshold) || (ch1 > clipThreshold))
{
return -1;
}
// gain is 1 so put it to 16X
chScale <<= 4;
// scale the channel values
channel0 = (ch0 * chScale) >> TSL2561_CH_SCALE;
channel1 = (ch1 * chScale) >> TSL2561_CH_SCALE;
ratio1 = 0;
if (channel0!= 0)
ratio1 = (channel1 << (TSL2561_RATIO_SCALE+1))/channel0;
// round the ratio value
ratio = (ratio1 + 1) >> 1;
// ULPNode have T package
// Adjust constant depending on calculated ratio
if ((ratio >= 0) && (ratio <= TSL2561_K1T))
{b=TSL2561_B1T; m=TSL2561_M1T;}
else if (ratio <= TSL2561_K2T)
{b=TSL2561_B2T; m=TSL2561_M2T;}
else if (ratio <= TSL2561_K3T)
{b=TSL2561_B3T; m=TSL2561_M3T;}
else if (ratio <= TSL2561_K4T)
{b=TSL2561_B4T; m=TSL2561_M4T;}
else if (ratio <= TSL2561_K5T)
{b=TSL2561_B5T; m=TSL2561_M5T;}
else if (ratio <= TSL2561_K6T)
{b=TSL2561_B6T; m=TSL2561_M6T;}
else if (ratio <= TSL2561_K7T)
{b=TSL2561_B7T; m=TSL2561_M7T;}
else if (ratio > TSL2561_K8T)
{b=TSL2561_B8T; m=TSL2561_M8T;}
// datasheet formula
lux=((channel0*b)-(channel1*m));
// do not allow negative lux value
if(lux<0)
lux=0;
// round lsb (2^(LUX_SCALE1))
lux += (1<<(TSL2561_LUX_SCALE-1));
// strip off fractional portion
lux >>= TSL2561_LUX_SCALE;
// strip off fractional portion
tsl2561_lux = (uint16_t) (lux);
return 0;
}
-8
View File
@@ -2,9 +2,6 @@
//#################################### Plugin 016: Input IR #############################################
//#######################################################################################################
#ifdef PLUGIN_BUILD_NORMAL
#include <IRremoteESP8266.h>
IRrecv *irReceiver;
decode_results results;
@@ -78,10 +75,6 @@ boolean Plugin_016(byte function, struct EventStruct *event, String& string)
UserVar[event->BaseVarIndex + 1] = ((IRcode >> 16) & 0xFFFF);
String log = F("IR : Code ");
log += String(IRcode, HEX);
log += F(" - Type: ");
log += results.decode_type;
log += F(" - Bits: ");
log += results.bits;
addLog(LOG_LEVEL_INFO, log);
sendData(event);
}
@@ -92,4 +85,3 @@ boolean Plugin_016(byte function, struct EventStruct *event, String& string)
return success;
}
#endif
+13 -14
View File
@@ -33,7 +33,7 @@ uint8_t Plugin_017_command;
boolean Plugin_017(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
@@ -66,18 +66,14 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormPinSelect(string, F("Reset Pin"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
string += F("<TR><TD>Reset Pin:<TD>");
addPinSelect(false, string, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]);
success = true;
break;
}
case PLUGIN_INIT:
{
//set clock stretch to 2000, if its not set via advanced settings yet
//something that Martinus figured out and added: https://github.com/esp8266/Arduino/issues/1541
// if (!Settings.WireClockStretchLimit)
// Wire.setClockStretchLimit(2000);
for(byte x=0; x < 3; x++)
{
if(Plugin_017_Init(Settings.TaskDevicePin3[event->TaskIndex]))
@@ -86,21 +82,22 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
}
break;
}
case PLUGIN_TEN_PER_SECOND:
{
static unsigned long tempcounter = 0;
static byte counter;
static byte errorCount=0;
counter++;
if (counter == 3)
{
if (digitalRead(4) == 0 || digitalRead(5) == 0)
{
addLog(LOG_LEVEL_ERROR, F("PN532: BUS error"));
String log = F("PN532: BUS error");
addLog(LOG_LEVEL_ERROR, log);
Plugin_017_Init(Settings.TaskDevicePin3[event->TaskIndex]);
// delay(1000);
delay(1000);
}
counter = 0;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
@@ -116,7 +113,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
}
else
errorCount=0;
if (errorCount > 2) // if three consecutive I2C errors, reset PN532
{
Plugin_017_Init(Settings.TaskDevicePin3[event->TaskIndex]);
@@ -180,7 +177,7 @@ boolean Plugin_017_Init(int8_t resetPin)
}
else
return false;
Plugin_017_pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
Plugin_017_pn532_packetbuffer[1] = 0x01; // normal mode;
Plugin_017_pn532_packetbuffer[2] = 0x2; // timeout 50ms * 2 = 100 mS
@@ -188,7 +185,7 @@ boolean Plugin_017_Init(int8_t resetPin)
if (Plugin_017_writeCommand(Plugin_017_pn532_packetbuffer, 4))
return false;
// to prevent nack on next read
Wire.beginTransmission(PN532_I2C_ADDRESS);
Wire.endTransmission();
@@ -401,3 +398,5 @@ int8_t Plugin_017_readAckFrame()
return 0;
}
+8 -2
View File
@@ -46,7 +46,11 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormCheckBox(string, F("Send Boot state"), F("plugin_019_boot"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += F("<TR><TD>Send Boot state:<TD>");
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
string += F("<input type=checkbox name=plugin_019_boot checked>");
else
string += F("<input type=checkbox name=plugin_019_boot>");
success = true;
break;
@@ -54,7 +58,9 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = isFormItemChecked(F("plugin_019_boot"));
String plugin1 = WebServer.arg("plugin_019_boot");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = (plugin1 == "on");
success = true;
break;
+81 -31
View File
@@ -7,7 +7,7 @@
#define PLUGIN_NAME_020 "Serial Server"
#define PLUGIN_VALUENAME1_020 "Ser2Net"
#define P020_BUFFER_SIZE 128
#define BUFFER_SIZE 128
boolean Plugin_020_init = false;
byte Plugin_020_SerialProcessing = 0;
@@ -45,9 +45,13 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("TCP Port"), F("plugin_020_port"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
addFormNumericBox(string, F("Baud Rate"), F("plugin_020_baud"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
addFormNumericBox(string, F("Data bits"), F("plugin_020_data"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>TCP Port:<TD><input type='text' name='plugin_020_port' value='%u'>"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
string += tmpString;
sprintf_P(tmpString, PSTR("<TR><TD>Baud Rate:<TD><input type='text' name='plugin_020_baud' value='%u'>"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
string += tmpString;
sprintf_P(tmpString, PSTR("<TR><TD>Data bits:<TD><input type='text' name='plugin_020_data' value='%u'>"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
string += tmpString;
byte choice = ExtraTaskSettings.TaskDevicePluginConfigLong[3];
String options[3];
@@ -58,21 +62,51 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
optionValues[0] = 0;
optionValues[1] = 2;
optionValues[2] = 3;
addFormSelector(string, F("Parity"), F("plugin_020_parity"), 3, options, optionValues, choice);
string += F("<TR><TD>Parity:<TD><select name='plugin_020_parity'>");
for (byte x = 0; x < 3; 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>");
addFormNumericBox(string, F("Stop bits"), F("plugin_020_stop"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
sprintf_P(tmpString, PSTR("<TR><TD>Stop bits:<TD><input type='text' name='plugin_020_stop' value='%u'>"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
string += tmpString;
addFormPinSelect(string, F("Reset target after boot"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormNumericBox(string, F("RX Receive Timeout (mSec)"), F("plugin_020_rxwait"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += F("<TR><TD>Reset target after boot:<TD>");
addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]);
sprintf_P(tmpString, PSTR("<TR><TD>RX Receive Timeout (mSec):<TD><input type='text' name='plugin_020_rxwait' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += tmpString;
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options2[3];
options2[0] = F("None");
options2[1] = F("Generic");
options2[2] = F("RFLink");
addFormSelector(string, F("Event processing"), F("plugin_020_events"), 3, options2, NULL, choice2);
int optionValues2[3];
optionValues2[0] = 0;
optionValues2[1] = 1;
optionValues2[2] = 2;
string += F("<TR><TD>Event processing:<TD><select name='plugin_020_events'>");
for (byte x = 0; x < 3; x++)
{
string += F("<option value='");
string += optionValues2[x];
string += "'";
if (choice2 == optionValues2[x])
string += F(" selected");
string += ">";
string += options2[x];
string += F("</option>");
}
string += F("</select>");
success = true;
break;
@@ -80,13 +114,20 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
ExtraTaskSettings.TaskDevicePluginConfigLong[0] = getFormItemInt(F("plugin_020_port"));
ExtraTaskSettings.TaskDevicePluginConfigLong[1] = getFormItemInt(F("plugin_020_baud"));
ExtraTaskSettings.TaskDevicePluginConfigLong[2] = getFormItemInt(F("plugin_020_data"));
ExtraTaskSettings.TaskDevicePluginConfigLong[3] = getFormItemInt(F("plugin_020_parity"));
ExtraTaskSettings.TaskDevicePluginConfigLong[4] = getFormItemInt(F("plugin_020_stop"));
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_020_rxwait"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_020_events"));
String plugin1 = WebServer.arg("plugin_020_port");
ExtraTaskSettings.TaskDevicePluginConfigLong[0] = plugin1.toInt();
String plugin2 = WebServer.arg("plugin_020_baud");
ExtraTaskSettings.TaskDevicePluginConfigLong[1] = plugin2.toInt();
String plugin3 = WebServer.arg("plugin_020_data");
ExtraTaskSettings.TaskDevicePluginConfigLong[2] = plugin3.toInt();
String plugin4 = WebServer.arg("plugin_020_parity");
ExtraTaskSettings.TaskDevicePluginConfigLong[3] = plugin4.toInt();
String plugin5 = WebServer.arg("plugin_020_stop");
ExtraTaskSettings.TaskDevicePluginConfigLong[4] = plugin5.toInt();
String plugin6 = WebServer.arg("plugin_020_rxwait");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin6.toInt();
String plugin7 = WebServer.arg("plugin_020_events");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin7.toInt();
success = true;
break;
}
@@ -130,29 +171,33 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
{
if (ser2netClient) ser2netClient.stop();
ser2netClient = ser2netServer->available();
addLog(LOG_LEVEL_ERROR, F("Ser2N: Client connected!"));
char log[40];
strcpy_P(log, PSTR("Ser2N: Client connected!"));
addLog(LOG_LEVEL_ERROR, log);
}
if (ser2netClient.connected())
{
connectionState = 1;
uint8_t net_buf[P020_BUFFER_SIZE];
uint8_t net_buf[BUFFER_SIZE];
int count = ser2netClient.available();
if (count > 0)
{
if (count > P020_BUFFER_SIZE)
count = P020_BUFFER_SIZE;
if (count > BUFFER_SIZE)
count = BUFFER_SIZE;
bytes_read = ser2netClient.read(net_buf, count);
Serial.write(net_buf, bytes_read);
Serial.flush(); // Waits for the transmission of outgoing serial data to complete
if (count == P020_BUFFER_SIZE) // if we have a full buffer, drop the last position to stuff with string end marker
if (count == BUFFER_SIZE) // if we have a full buffer, drop the last position to stuff with string end marker
{
count--;
addLog(LOG_LEVEL_ERROR, F("Ser2N: network buffer full!"));
char log[40];
strcpy_P(log, PSTR("Ser2N: network buffer full!")); // and log buffer full situation
addLog(LOG_LEVEL_ERROR, log);
}
net_buf[count] = 0; // before logging as a char array, zero terminate the last position to be safe.
char log[P020_BUFFER_SIZE + 40];
char log[BUFFER_SIZE + 40];
sprintf_P(log, PSTR("Ser2N: N>: %s"), (char*)net_buf);
addLog(LOG_LEVEL_DEBUG, log);
}
@@ -162,7 +207,9 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
if (connectionState == 1) // there was a client connected before...
{
connectionState = 0;
addLog(LOG_LEVEL_ERROR, F("Ser2N: Client disconnected!"));
char log[40];
strcpy_P(log, PSTR("Ser2N: Client disconnected!"));
addLog(LOG_LEVEL_ERROR, log);
}
while (Serial.available())
@@ -176,7 +223,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
case PLUGIN_SERIAL_IN:
{
uint8_t serial_buf[P020_BUFFER_SIZE];
uint8_t serial_buf[BUFFER_SIZE];
int RXWait = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
if (RXWait == 0)
RXWait = 1;
@@ -185,7 +232,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
while (timeOut > 0)
{
while (Serial.available()) {
if (bytes_read < P020_BUFFER_SIZE) {
if (bytes_read < BUFFER_SIZE) {
serial_buf[bytes_read] = Serial.read();
bytes_read++;
}
@@ -198,7 +245,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
timeOut--;
}
if (bytes_read != P020_BUFFER_SIZE)
if (bytes_read != BUFFER_SIZE)
{
if (bytes_read > 0) {
if (Plugin_020_init && ser2netClient.connected())
@@ -213,11 +260,12 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
while (Serial.available()) // read possible remaining data to avoid sending rubbish...
Serial.read();
bytes_read--;
// and log buffer full situation
addLog(LOG_LEVEL_ERROR, F("Ser2N: serial buffer full!"));
char log[40];
strcpy_P(log, PSTR("Ser2N: serial buffer full!")); // and log buffer full situation
addLog(LOG_LEVEL_ERROR, log);
}
serial_buf[bytes_read] = 0; // before logging as a char array, zero terminate the last position to be safe.
char log[P020_BUFFER_SIZE + 40];
char log[BUFFER_SIZE + 40];
sprintf_P(log, PSTR("Ser2N: S>: %s"), (char*)serial_buf);
addLog(LOG_LEVEL_DEBUG, log);
@@ -247,6 +295,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
case 2: // RFLink
{
message = message.substring(6); // RFLink, strip 20;xx; from incoming message
//message.replace("\r\n", "");
if (message.startsWith("ESPEASY")) // Special treatment for gpio values, strip unneeded parts...
{
message = message.substring(8); // Strip "ESPEASY;"
@@ -282,3 +331,4 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
}
return success;
}
+14 -23
View File
@@ -53,9 +53,12 @@ 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("Hysteresis"), F("plugin_021_hyst"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]), 8);
string += F("<TR><TD>Set Value:<TD><input type='text' name='plugin_021_setvalue' value='");
string += Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0];
string += F("'>");
string += F("<TR><TD>Hysteresis:<TD><input type='text' name='plugin_021_hyst' value='");
string += Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1];
string += F("'>");
LoadTaskSettings(event->TaskIndex); // we need to restore our original taskvalues!
success = true;
@@ -64,30 +67,18 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_021_task"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_021_value"));
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = getFormItemFloat(F("plugin_021_setvalue"));
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = getFormItemFloat(F("plugin_021_hyst"));
String plugin1 = WebServer.arg("plugin_021_task");
String plugin2 = WebServer.arg("plugin_021_value");
String plugin3 = WebServer.arg("plugin_021_setvalue");
String plugin4 = WebServer.arg("plugin_021_hyst");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = plugin3.toFloat();
Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = plugin4.toFloat();
success = true;
break;
}
case PLUGIN_REMOTE_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);
SaveSettings();
success = true;
}
break;
}
case PLUGIN_INIT:
{
Serial.print(F("INIT : Output "));
+10 -9
View File
@@ -7,9 +7,9 @@
#define PLUGIN_NAME_022 "PWM - PCA9685"
#define PLUGIN_VALUENAME1_022 "PWM"
#define PLUGIN_022_PCA9685_MODE1 0x00 // location for Mode1 register address
#define PCA9685_MODE2 0x01 // location for Mode2 reigster address
#define PCA9685_LED0 0x06 // location for start of LED0 registers
#define PCA9685_MODE1 0x00 // location for Mode1 register address
#define PCA9685_MODE2 0x01 // location for Mode2 reigster address
#define PCA9685_LED0 0x06 // location for start of LED0 registers
#define PCA9685_ADDRESS 0x40 // I2C address
boolean Plugin_022_init = false;
@@ -110,10 +110,11 @@ boolean Plugin_022_Write(byte Par1, int Par2)
void Plugin_022_initialize()
{
// default mode is open drain ouput, drive leds connected to VCC
Plugin_022_writeRegister(PLUGIN_022_PCA9685_MODE1, (byte)0x01); // reset the device
delay(1);
Plugin_022_writeRegister(PLUGIN_022_PCA9685_MODE1, (byte)B10100000); // set up for auto increment
Plugin_022_writeRegister(PCA9685_MODE2, (byte)0x10); // set to output
Plugin_022_init = true;
// default mode is open drain ouput, drive leds connected to VCC
Plugin_022_writeRegister(PCA9685_MODE1, (byte)0x01); // reset the device
delay(1);
Plugin_022_writeRegister(PCA9685_MODE1, (byte)B10100000); // set up for auto increment
Plugin_022_writeRegister(PCA9685_MODE2, (byte)0x10); // set to output
Plugin_022_init = true;
}
+87 -21
View File
@@ -60,30 +60,88 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*String options[2] = { F("3C"), F("3D") };*/
int optionValues[2] = { 0x3C, 0x3D };
addFormSelectorI2C(string, F("plugin_023_adr"), 2, optionValues, choice);
String options[2];
options[0] = F("3C");
options[1] = F("3D");
int optionValues[2];
optionValues[0] = 0x3C;
optionValues[1] = 0x3D;
string += F("<TR><TD>I2C Address:<TD><select name='plugin_023_adr'>");
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>");
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options2[2] = { F("Normal"), F("Rotated") };
int optionValues2[2] = { 1, 2 };
addFormSelector(string, F("Rotation"), F("plugin_023_rotate"), 2, options2, optionValues2, choice2);
String options2[2];
options2[0] = F("Normal");
options2[1] = F("Rotated");
int optionValues2[2];
optionValues2[0] = 1;
optionValues2[1] = 2;
string += F("<TR><TD>Rotation:<TD><select name='plugin_023_rotate'>");
for (byte x = 0; x < 2; x++)
{
string += F("<option value='");
string += optionValues2[x];
string += "'";
if (choice2 == optionValues2[x])
string += F(" selected");
string += ">";
string += options2[x];
string += F("</option>");
}
string += F("</select>");
byte choice3 = Settings.TaskDevicePluginConfig[event->TaskIndex][3];
String options3[2] = { F("128x64"), F("64x48") };
int optionValues3[2] = { 1, 2 };
addFormSelector(string, F("Display Size"), F("plugin_023_size"), 2, options3, optionValues3, choice3);
String options3[2];
options3[0] = F("128x64");
options3[1] = F("64x48");
int optionValues3[2];
optionValues3[0] = 1;
optionValues3[1] = 2;
string += F("<TR><TD>Display Size:<TD><select name='plugin_023_size'>");
for (byte x = 0; x < 2; x++)
{
string += F("<option value='");
string += optionValues3[x];
string += "'";
if (choice3 == optionValues3[x])
string += F(" selected");
string += ">";
string += options3[x];
string += F("</option>");
}
string += F("</select>");
char deviceTemplate[8][64];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
for (byte varNr = 0; varNr < 8; varNr++)
{
addFormTextBox(string, String(F("Line ")) + (varNr + 1), String(F("Plugin_023_template")) + (varNr + 1), deviceTemplate[varNr], 64);
string += F("<TR><TD>Line ");
string += varNr + 1;
string += F(":<TD><input type='text' size='64' maxlength='64' name='Plugin_023_template");
string += varNr + 1;
string += F("' value='");
string += deviceTemplate[varNr];
string += F("'>");
}
addFormPinSelect(string, F("Display button"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
string += F("<TR><TD>Display button:<TD>");
addPinSelect(false, string, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]);
addFormNumericBox(string, F("Display Timeout"), F("plugin_23_timer"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Display Timeout:<TD><input type='text' name='plugin_23_timer' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
string += tmpString;
success = true;
break;
@@ -91,21 +149,28 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_023_adr"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_023_rotate"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_23_timer"));
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("plugin_023_size"));
String plugin1 = WebServer.arg("plugin_023_adr");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg("plugin_023_rotate");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
String plugin3 = WebServer.arg("plugin_23_timer");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
String plugin4 = WebServer.arg("plugin_023_size");
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = plugin4.toInt();
char deviceTemplate[8][64];
for (byte varNr = 0; varNr < 8; varNr++)
{
char argc[25];
String arg = F("Plugin_023_template");
arg += varNr + 1;
String tmpString = WebServer.arg(arg);
strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])-1);
deviceTemplate[varNr][63]=0;
arg.toCharArray(argc, 25);
String tmpString = WebServer.arg(argc);
strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr]));
}
Settings.TaskDeviceID[event->TaskIndex] = 1; // temp fix, needs a dummy value
SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
success = true;
break;
@@ -420,7 +485,7 @@ static void Plugin_023_sendStr(unsigned char *string)
{
Plugin_023_SendChar(pgm_read_byte(Plugin_023_myFont[*string - 0x20] + i));
}
string++;
*string++;
}
}
@@ -437,7 +502,7 @@ static void Plugin_023_sendStrXY(const char *string, int X, int Y)
{
Plugin_023_SendChar(pgm_read_byte(Plugin_023_myFont[*string - 0x20] + i));
}
string++;
*string++;
}
}
@@ -476,3 +541,4 @@ static void Plugin_023_init_OLED(void)
Plugin_023_sendcommand(0x20); //Set Memory Addressing Mode
Plugin_023_sendcommand(0x00); //Set Memory Addressing Mode ab Horizontal addressing mode
}
+18 -5
View File
@@ -6,7 +6,7 @@
#define PLUGIN_024
#define PLUGIN_ID_024 24
#define PLUGIN_NAME_024 "Digital IR Thermometer - MLX90614"
#define PLUGIN_NAME_024 "Temperature IR + ambient - MLX90614"
#define PLUGIN_VALUENAME1_024 "Temperature"
boolean Plugin_024_init = false;
@@ -20,7 +20,7 @@ uint16_t readRegister024(uint8_t i2cAddress, uint8_t reg) {
ret = Wire.read(); // receive DATA
ret |= Wire.read() << 8; // receive DATA
uint8_t pec = Wire.read();
return ret;
return ret;
}
float readTemp024(uint8_t i2c_addr, uint8_t i2c_reg)
@@ -72,12 +72,24 @@ boolean Plugin_024(byte function, struct EventStruct *event, String& string)
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[MLX90614_OPTION];
int optionValues[MLX90614_OPTION];
uint optionValues[MLX90614_OPTION];
optionValues[0] = (0x07);
options[0] = F("IR object temperature");
optionValues[1] = (0x06);
options[1] = F("Ambient temperature");
addFormSelector(string, F("Option"), F("plugin_024_option"), MLX90614_OPTION, options, optionValues, choice);
string += F("<TR><TD>Option:<TD><select name='plugin_024_option'>");
for (byte x = 0; x < MLX90614_OPTION; 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;
@@ -85,7 +97,8 @@ boolean Plugin_024(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_024_option"));
String plugin1 = WebServer.arg("plugin_024_option");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
Plugin_024_init = false; // Force device setup next time
success = true;
break;
+185
View File
@@ -0,0 +1,185 @@
//#######################################################################################################
//#################################### Plugin 025: ADS1115 I2C 0x48) ###############################################
//#######################################################################################################
#define PLUGIN_025
#define PLUGIN_ID_025 25
#define PLUGIN_NAME_025 "Analog input - ADS1115"
#define PLUGIN_VALUENAME1_025 "Analog"
boolean Plugin_025_init = false;
static uint16_t readRegister025(uint8_t i2cAddress, uint8_t reg) {
Wire.beginTransmission(i2cAddress);
Wire.write((0x00));
Wire.endTransmission();
Wire.requestFrom(i2cAddress, (uint8_t)2);
return ((Wire.read() << 8) | Wire.read());
}
boolean Plugin_025(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
static byte portValue = 0;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_025;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].Ports = 4;
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_025);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_025));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
#define ADS1115_GAIN_OPTION 6
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[ADS1115_GAIN_OPTION];
uint optionValues[ADS1115_GAIN_OPTION];
optionValues[0] = (0x00);
options[0] = F("2/3x gain 6.144V 0.1875mV");
optionValues[1] = (0x02);
options[1] = F("1x gain 4.096V 0.125mV");
optionValues[2] = (0x04);
options[2] = F("2x gain 2.048V 0.0625mV");
optionValues[3] = (0x06);
options[3] = F("4x gain 1.024V 0.03125mV");
optionValues[4] = (0x08);
options[4] = F("8x gain 0.512V 0.015625mV");
optionValues[5] = (0x0A);
options[5] = F("16x gain 0.256V 0.0078125mV");
string += F("<TR><TD>Gain:<TD><select name='plugin_025_gain'>");
for (byte x = 0; x < ADS1115_GAIN_OPTION; 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("plugin_025_gain");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
Plugin_025_init = false; // Force device setup next time
success = true;
break;
}
case PLUGIN_INIT:
{
Plugin_025_init = true;
success = true;
break;
}
case PLUGIN_READ:
{
uint8_t m_gain = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
int value;
value = 0;
byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4;
byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4);
uint8_t address = 0x48 + unit;
// get the current pin value
uint16_t config = (0x0003) | // Disable the comparator (default val)
(0x0000) | // Non-latching (default val)
(0x0000) | // Alert/Rdy active low (default val)
(0x0000) | // Traditional comparator (default val)
(0x0080) | // 1600 samples per second (default)
(0x0100) ; // Single-shot mode (default)
// m_Gain = (0x0000); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
// m_Gain = (0x0200); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// m_Gain = (0x0400); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// m_Gain = (0x0600); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
// m_Gain = (0x0800); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
// m_Gain = (0x0A00); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
// config |= m_gain;
// config |= (0x0000);
switch (m_gain)
{
case (0x00):
config |= (0x0000);
break;
case (0x02):
config |= (0x0200);
break;
case (0x04):
config |= (0x0400);
break;
case (0x06):
config |= (0x0600);
break;
case (0x08):
config |= (0x0800);
break;
case (0x0A):
config |= (0x0A00);
break;
}
switch (port)
{
case (1):
config |= (0x4000);
break;
case (2):
config |= (0x5000);
break;
case (3):
config |= (0x6000);
break;
case (4):
config |= (0x7000);
break;
}
config |= (0x8000);
Wire.beginTransmission(address);
Wire.write((uint8_t)(0x01));
Wire.write((uint8_t)(config>>8));
Wire.write((uint8_t)(config & 0xFF));
Wire.endTransmission();
delay(8);
UserVar[event->BaseVarIndex] = (float) readRegister025((address), (0x00)) ;
String log = F("ADS1115 : Analog value: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO,log);
success = true;
break;
}
}
return success;
}
+22 -3
View File
@@ -46,7 +46,25 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
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);
int optionValues[5];
optionValues[0] = 0;
optionValues[1] = 1;
optionValues[2] = 2;
optionValues[3] = 3;
optionValues[4] = 4;
string += F("<TR><TD>Indicator:<TD><select name='plugin_026'>");
for (byte x = 0; x < 5; 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;
@@ -54,11 +72,12 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_026"));
String plugin1 = WebServer.arg("plugin_026");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
case PLUGIN_READ:
{
float value = 0;
+21 -23
View File
@@ -8,9 +8,6 @@
#define PLUGIN_VALUENAME1_027 "Voltage"
#define INA219_ADDRESS (0x40) // 1000000 (A0+A1=GND)
#define INA219_ADDRESS2 (0x41) // 1000000 (A0+A1=GND)
#define INA219_ADDRESS3 (0x44) // 1000000 (A0+A1=GND)
#define INA219_ADDRESS4 (0x45) // 1000000 (A0+A1=GND)
#define INA219_READ (0x01)
#define INA219_REG_CONFIG (0x00)
#define INA219_CONFIG_RESET (0x8000) // Reset Bit
@@ -108,22 +105,23 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
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 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;
optionValues2[2] = INA219_ADDRESS3;
optionValues2[3] = INA219_ADDRESS4;
addFormSelectorI2C(string, F("plugin_027_i2c"), 4, optionValues2, choice2);
int optionValues[3];
optionValues[0] = 0;
optionValues[1] = 1;
optionValues[2] = 2;
string += F("<TR><TD>Report:<TD><select name='plugin_027_value'>");
for (byte x = 0; x < 3; 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;
@@ -131,16 +129,14 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_027_value"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_027_i2c"));
String plugin1 = WebServer.arg("plugin_027_value");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
case PLUGIN_INIT:
{
ina219_i2caddr = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
Plugin_027_begin();
success = true;
break;
@@ -284,6 +280,7 @@ void Plugin_027_setCalibration_16V_400mA(void) {
//**************************************************************************/
void Plugin_027_begin(void) {
ina219_i2caddr = INA219_ADDRESS;
ina219_currentDivider_mA = 0;
// Set chip to large range config values to start
@@ -354,3 +351,4 @@ float Plugin_027_getCurrent_mA() {
valueDec /= ina219_currentDivider_mA;
return valueDec;
}
+28 -29
View File
@@ -4,7 +4,7 @@
#define PLUGIN_028
#define PLUGIN_ID_028 28
#define PLUGIN_NAME_028 "Environment - BME280"
#define PLUGIN_NAME_028 "Temperature & Humidity & Pressure - BME280"
#define PLUGIN_VALUENAME1_028 "Temperature"
#define PLUGIN_VALUENAME2_028 "Humidity"
#define PLUGIN_VALUENAME3_028 "Pressure"
@@ -39,16 +39,13 @@ enum
BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0
BME280_REGISTER_CONTROLHUMID = 0xF2,
BME280_REGISTER_STATUS = 0xF3,
BME280_REGISTER_CONTROL = 0xF4,
BME280_REGISTER_CONFIG = 0xF5,
BME280_REGISTER_PRESSUREDATA = 0xF7,
BME280_REGISTER_TEMPDATA = 0xFA,
BME280_REGISTER_HUMIDDATA = 0xFD,
BME280_CONTROL_SETTING = 0x25, // Oversampling: 1x P, 1x T, forced
BME280_CONTROL_SETTING_HUMIDITY = 0x01, // Oversampling: 1x H
BME280_CONFIG_SETTING = 0xA0, // Tstandby 1000ms, filter off, 3-wire SPI Disable
BME280_CONTROL_SETTING = 0x57, // Oversampling: 16x P, 2x T, normal mode
};
typedef struct
@@ -124,17 +121,29 @@ boolean Plugin_028(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*
String options[2];
options[0] = F("0x76 - default settings (SDO Low)");
options[1] = F("0x77 - alternate settings (SDO HIGH)");
*/
int optionValues[2] = { 0x76, 0x77 };
addFormSelectorI2C(string, F("plugin_028_bme280_i2c"), 2, optionValues, choice);
addFormNote(string, F("SDO Low=0x76, High=0x77"));
addFormNumericBox(string, F("Altitude"), F("plugin_028_bme280_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(string, F("m"));
int optionValues[2];
optionValues[0] = 0x76;
optionValues[1] = 0x77;
string += F("<TR><TD>I2C Address:<TD><select name='plugin_028_bme280_i2c'>");
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>");
string += F("<TR><TD>Altitude [m]:<TD><input type='text' title='Set Altitude to 0 to get measurement without altitude adjustment' name='");
string += F("plugin_028_bme280_elev' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][1];
string += F("'>");
success = true;
break;
@@ -142,8 +151,10 @@ boolean Plugin_028(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_028_bme280_i2c"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_028_bme280_elev"));
String plugin1 = WebServer.arg("plugin_028_bme280_i2c");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String elev = WebServer.arg("plugin_028_bme280_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
}
@@ -214,14 +225,8 @@ bool Plugin_028_begin(uint8_t a) {
return false;
Plugin_028_readCoefficients(_i2caddr & 0x01);
// Set the Sensor in sleep to be make sure that the following configs will be stored
Plugin_028_write8(BME280_REGISTER_CONTROL, 0x00);
Plugin_028_write8(BME280_REGISTER_CONFIG, BME280_CONFIG_SETTING);
Plugin_028_write8(BME280_REGISTER_CONTROLHUMID, BME280_CONTROL_SETTING_HUMIDITY);
Plugin_028_write8(BME280_REGISTER_CONTROLHUMID, 0x03);
Plugin_028_write8(BME280_REGISTER_CONTROL, BME280_CONTROL_SETTING);
return true;
}
@@ -345,13 +350,6 @@ float Plugin_028_readTemperature(uint8_t idx)
{
int32_t var1, var2;
// set to forced mode, i.e. "take next measurement"
Plugin_028_write8(BME280_REGISTER_CONTROL, BME280_CONTROL_SETTING);
// wait until measurement has been completed, otherwise we would read
// the values from the last measurement
while (Plugin_028_read8(BME280_REGISTER_STATUS) & 0x08)
delay(1);
int32_t adc_T = Plugin_028_read24(BME280_REGISTER_TEMPDATA);
adc_T >>= 4;
@@ -448,3 +446,4 @@ float Plugin_028_readAltitude(float seaLevel)
float Plugin_028_pressureElevation(float atmospheric, int altitude) {
return atmospheric / pow(1.0 - (altitude/44330.0), 5.255);
}
+29 -12
View File
@@ -4,7 +4,7 @@
#define PLUGIN_030
#define PLUGIN_ID_030 30
#define PLUGIN_NAME_030 "Environment - BMP280"
#define PLUGIN_NAME_030 "Temperature & Pressure - BMP280"
#define PLUGIN_VALUENAME1_030 "Temperature"
#define PLUGIN_VALUENAME2_030 "Pressure"
@@ -36,7 +36,6 @@ enum
BMP280_REGISTER_TEMPDATA = 0xFA,
BMP280_CONTROL_SETTING = 0x57, // Oversampling: 16x P, 2x T, normal mode
BMP280_CONFIG_SETTING = 0xE0, // Tstandby 1000ms, filter 16, 3-wire SPI Disable
};
typedef struct
@@ -103,13 +102,29 @@ boolean Plugin_030(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*String options[2] = { F("0x76 - default settings (SDO Low)"), F("0x77 - alternate settings (SDO HIGH)") };*/
int optionValues[2] = { 0x76, 0x77 };
addFormSelectorI2C(string, F("plugin_030_bmp280_i2c"), 2, optionValues, choice);
addFormNote(string, F("SDO Low=0x76, High=0x77"));
addFormNumericBox(string, F("Altitude"), F("plugin_030_bmp280_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(string, F("m"));
String options[2];
options[0] = F("0x76 - default settings (SDO Low)");
options[1] = F("0x77 - alternate settings (SDO HIGH)");
int optionValues[2];
optionValues[0] = 0x76;
optionValues[1] = 0x77;
string += F("<TR><TD>I2C Address:<TD><select name='plugin_030_bmp280_i2c'>");
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>");
string += F("<TR><TD>Altitude [m]:<TD><input type='text' title='Set Altitude to 0 to get measurement without altitude adjustment' name='");
string += F("plugin_030_bmp280_elev' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][1];
string += F("'>");
success = true;
break;
@@ -117,8 +132,10 @@ boolean Plugin_030(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_030_bmp280_i2c"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_030_bmp280_elev"));
String plugin1 = WebServer.arg("plugin_030_bmp280_i2c");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String elev = WebServer.arg("plugin_030_bmp280_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
}
@@ -214,7 +231,6 @@ bool Plugin_030_begin(uint8_t a) {
Plugin_030_readCoefficients(a & 0x1);
Plugin_030_write8(BMP280_REGISTER_CONTROL, BMP280_CONTROL_SETTING);
Plugin_030_write8(BMP280_REGISTER_CONFIG, BMP280_CONFIG_SETTING);
return true;
}
@@ -394,3 +410,4 @@ float Plugin_030_readAltitude(float seaLevel)
float Plugin_030_pressureElevation(float atmospheric, int altitude) {
return atmospheric / pow(1.0 - (altitude/44330.0), 5.255);
}
+7 -4
View File
@@ -4,7 +4,7 @@
#define PLUGIN_031
#define PLUGIN_ID_031 31
#define PLUGIN_NAME_031 "Environment - SHT1X"
#define PLUGIN_NAME_031 "Temperature & Humidity - SHT1X"
#define PLUGIN_VALUENAME1_031 "Temperature"
#define PLUGIN_VALUENAME2_031 "Humidity"
@@ -89,7 +89,8 @@ boolean Plugin_031(byte function, struct EventStruct *event, String& string)
case PLUGIN_READ:
{
if (!Plugin_031_init) {
addLog(LOG_LEVEL_ERROR, F("SHT1X : not yet initialized!"));
String log = F("SHT1X : not yet initialized!");
addLog(LOG_LEVEL_ERROR, log);
break;
}
UserVar[event->BaseVarIndex] = Plugin_031_readTemperature();
@@ -200,7 +201,8 @@ void Plugin_031_sendCommand(const byte cmd)
}
if (ackerror) {
addLog(LOG_LEVEL_ERROR, F("SHT1X : Sensor did not ACK command"));
String log = F("SHT1X : Sensor did not ACK command");
addLog(LOG_LEVEL_ERROR, log);
}
}
@@ -212,7 +214,8 @@ void Plugin_031_awaitResult()
delay(20);
}
if (digitalRead(Plugin_031_DATA_Pin) != LOW) {
addLog(LOG_LEVEL_ERROR, F("SHT1X : Data not ready"));
String log = F("SHT1X : Data not ready");
addLog(LOG_LEVEL_ERROR, log);
}
}
+42 -21
View File
@@ -5,7 +5,7 @@
#define PLUGIN_032
#define PLUGIN_ID_032 32
#define PLUGIN_NAME_032 "Environment - MS5611 (GY-63)"
#define PLUGIN_NAME_032 "Temperature & Pressure - MS5611 (GY-63)"
#define PLUGIN_VALUENAME1_032 "Temperature"
#define PLUGIN_VALUENAME2_032 "Pressure"
@@ -70,11 +70,29 @@ boolean Plugin_032(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*String options[2] = { F("0x77 - default I2C address"), F("0x76 - alternate I2C address") };*/
int optionValues[2] = { 0x77, 0x76 };
addFormSelectorI2C(string, F("plugin_032_ms5611_i2c"), 2, optionValues, choice);
addFormNumericBox(string, F("Altitude [m]"), F("plugin_032_ms5611_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
String options[2];
options[0] = F("0x77 - default I2C address");
options[1] = F("0x76 - alternate I2C address");
int optionValues[2];
optionValues[0] = 0x77;
optionValues[1] = 0x76;
string += F("<TR><TD>I2C Address:<TD><select name='plugin_032_ms5611_i2c'>");
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>");
string += F("<TR><TD>Altitude [m]:<TD><input type='text' title='Set Altitude to 0 to get measurement without altitude adjustment' name='");
string += F("plugin_032_ms5611_elev' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][1];
string += F("'>");
success = true;
break;
@@ -82,8 +100,10 @@ boolean Plugin_032(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_032_ms5611_i2c"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_032_ms5611_elev"));
String plugin1 = WebServer.arg("plugin_032_ms5611_i2c");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String elev = WebServer.arg("plugin_032_ms5611_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
}
@@ -92,13 +112,13 @@ boolean Plugin_032(byte function, struct EventStruct *event, String& string)
{
if (!Plugin_032_init)
{
Plugin_032_init = Plugin_032_begin(Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
Plugin_032_init = Plugin_032_begin(Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
}
if (Plugin_032_init) {
Plugin_032_read_prom();
Plugin_032_readout();
UserVar[event->BaseVarIndex] = ms5611_temperature / 100;
int elev = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
if (elev)
@@ -147,9 +167,9 @@ byte Plugin_032_send_cmd(byte aCMD)
//**************************************************************************/
// Reads the PROM of MS5611
// There are in total 8 addresses resulting in a total memory of 128 bit.
// Address 0 contains factory data and the setup, addresses 1-6 calibration
// coefficients and address 7 contains the serial code and CRC.
// There are in total 8 addresses resulting in a total memory of 128 bit.
// Address 0 contains factory data and the setup, addresses 1-6 calibration
// coefficients and address 7 contains the serial code and CRC.
// The command sequence is 8 bits long with a 16 bit result which is
// clocked with the MSB first.
//**************************************************************************/
@@ -157,7 +177,7 @@ void Plugin_032_read_prom() {
Plugin_032_send_cmd(MS5xxx_CMD_RESET);
delay(3);
for(uint8_t i=0;i<8;i++)
for(uint8_t i=0;i<8;i++)
{
ms5611_prom[i]=0x0000;
Plugin_032_send_cmd(MS5xxx_CMD_PROM_RD+2*i);
@@ -168,7 +188,7 @@ void Plugin_032_read_prom() {
c = Wire.read();
ms5611_prom[i] += c;
Wire.endTransmission(true);
}
}
}
//**************************************************************************/
@@ -178,7 +198,7 @@ unsigned long Plugin_032_read_adc(unsigned char aCMD)
{
unsigned long value=0;
unsigned long c=0;
Plugin_032_send_cmd(MS5xxx_CMD_ADC_CONV+aCMD); // start DAQ and conversion of ADC data
switch (aCMD & 0x0f)
{
@@ -202,7 +222,7 @@ unsigned long Plugin_032_read_adc(unsigned char aCMD)
c = Wire.read();
value += c;
Wire.endTransmission(true);
return value;
}
@@ -213,7 +233,7 @@ unsigned long Plugin_032_read_adc(unsigned char aCMD)
void Plugin_032_readout() {
unsigned long D1=0, D2=0;
double dT;
double OFF;
double SENS;
@@ -227,7 +247,7 @@ void Plugin_032_readout() {
SENS=ms5611_prom[1]*pow(2,15)+dT*ms5611_prom[3]/pow(2,8);
ms5611_temperature=(2000+(dT*ms5611_prom[6])/pow(2,23));
ms5611_pressure=(((D1*SENS)/pow(2,21)-OFF)/pow(2,15));
// perform higher order corrections
double T2=0., OFF2=0., SENS2=0.;
if(ms5611_temperature<2000) {
@@ -239,11 +259,11 @@ void Plugin_032_readout() {
SENS2+=11*(ms5611_temperature+1500)*(ms5611_temperature+1500)/pow(2,1);
}
}
ms5611_temperature-=T2;
OFF-=OFF2;
SENS-=SENS2;
ms5611_pressure=(((D1*SENS)/pow(2,21)-OFF)/pow(2,15));
ms5611_pressure=(((D1*SENS)/pow(2,21)-OFF)/pow(2,15));
}
//**************************************************************************/
@@ -252,3 +272,4 @@ void Plugin_032_readout() {
double Plugin_032_pressureElevation(double atmospheric, int altitude) {
return atmospheric / pow(1.0 - (altitude/44330.0), 5.255);
}
+20 -11
View File
@@ -45,7 +45,7 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[11];
String options[9];
options[0] = F("SENSOR_TYPE_SINGLE");
options[1] = F("SENSOR_TYPE_TEMP_HUM");
options[2] = F("SENSOR_TYPE_TEMP_BARO");
@@ -55,9 +55,7 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
options[6] = F("SENSOR_TYPE_QUAD");
options[7] = F("SENSOR_TYPE_SWITCH");
options[8] = F("SENSOR_TYPE_DIMMER");
options[9] = F("SENSOR_TYPE_LONG");
options[10] = F("SENSOR_TYPE_WIND");
int optionValues[11];
int optionValues[9];
optionValues[0] = SENSOR_TYPE_SINGLE;
optionValues[1] = SENSOR_TYPE_TEMP_HUM;
optionValues[2] = SENSOR_TYPE_TEMP_BARO;
@@ -67,10 +65,19 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
optionValues[6] = SENSOR_TYPE_QUAD;
optionValues[7] = SENSOR_TYPE_SWITCH;
optionValues[8] = SENSOR_TYPE_DIMMER;
optionValues[9] = SENSOR_TYPE_LONG;
optionValues[10] = SENSOR_TYPE_WIND;
addFormSelector(string, F("Simulate Data Type"), F("plugin_033_sensortype"), 11, options, optionValues, choice );
string += F("<TR><TD>Simulate Data Type:<TD><select name='plugin_033_sensortype'>");
for (byte x = 0; x < 9; 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;
@@ -78,14 +85,15 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_033_sensortype"));
String plugin1 = WebServer.arg("plugin_033_sensortype");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
case PLUGIN_READ:
{
event->sensorType = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
event->sensorType =Settings.TaskDevicePluginConfig[event->TaskIndex][0];
for (byte x=0; x<4;x++)
{
String log = F("Dummy: value ");
@@ -100,3 +108,4 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
}
return success;
}
+3 -2
View File
@@ -4,7 +4,7 @@
#define PLUGIN_034
#define PLUGIN_ID_034 34
#define PLUGIN_NAME_034 "Environment - DHT12 (I2C)"
#define PLUGIN_NAME_034 "Temperature & Humidity - DHT12 (I2C)"
#define PLUGIN_VALUENAME1_034 "Temperature"
#define PLUGIN_VALUENAME2_034 "Humidity"
@@ -101,7 +101,8 @@ boolean Plugin_034(byte function, struct EventStruct *event, String& string)
} // error
if(!success)
{
addLog(LOG_LEVEL_INFO, F("DHT12: No reading!"));
String log = F("DHT12: No reading!");
addLog(LOG_LEVEL_INFO, log);
UserVar[event->BaseVarIndex] = NAN;
UserVar[event->BaseVarIndex + 1] = NAN;
}
+103
View File
@@ -0,0 +1,103 @@
//#######################################################################################################
//#################################### Plugin 035: Output IR ############################################
//#######################################################################################################
#include <IRremoteESP8266.h>
IRsend *Plugin_035_irSender;
#define PLUGIN_035
#define PLUGIN_ID_035 35
#define PLUGIN_NAME_035 "Infrared Transmit"
boolean Plugin_035(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_035;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
Device[deviceCount].SendDataOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_035);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
break;
}
case PLUGIN_INIT:
{
int irPin = Settings.TaskDevicePin1[event->TaskIndex];
if (Plugin_035_irSender == 0 && irPin != -1)
{
addLog(LOG_LEVEL_INFO, "INIT: IR TX");
Plugin_035_irSender = new IRsend(irPin);
Plugin_035_irSender->begin(); // Start the sender
}
if (Plugin_035_irSender != 0 && irPin == -1)
{
addLog(LOG_LEVEL_INFO, "INIT: IR TX Removed");
delete Plugin_035_irSender;
Plugin_035_irSender = 0;
}
success = true;
break;
}
case PLUGIN_WRITE:
{
String IrType;
unsigned long IrCode;
unsigned int IrBits;
char command[80];
command[0] = 0;
char TmpStr1[80];
TmpStr1[0] = 0;
string.toCharArray(command, 80);
String tmpString = string;
int argIndex = tmpString.indexOf(',');
if (argIndex) tmpString = tmpString.substring(0, argIndex);
if (GetArgv(command, TmpStr1, 2)) IrType = TmpStr1;
if (GetArgv(command, TmpStr1, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1
if (GetArgv(command, TmpStr1, 4)) IrBits = str2int(TmpStr1);
if (tmpString.equalsIgnoreCase("IRSEND") && Plugin_035_irSender != 0)
{
success = true;
if (irReceiver != 0) irReceiver->disableIRIn(); // Stop the receiver
if (IrType.equalsIgnoreCase("NEC")) Plugin_035_irSender->sendNEC(IrCode, IrBits);
if (IrType.equalsIgnoreCase("JVC")) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2);
if (IrType.equalsIgnoreCase("RC5")) Plugin_035_irSender->sendRC5(IrCode, IrBits);
if (IrType.equalsIgnoreCase("RC6")) Plugin_035_irSender->sendRC6(IrCode, IrBits);
if (IrType.equalsIgnoreCase("SAMSUNG")) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits);
if (IrType.equalsIgnoreCase("SONY")) Plugin_035_irSender->sendSony(IrCode, IrBits);
if (IrType.equalsIgnoreCase("PANASONIC")) Plugin_035_irSender->sendPanasonic(IrBits, IrCode);
addLog(LOG_LEVEL_INFO, "IR Code Sent");
if (printToWeb)
{
printWebString += F("IR Code Sent ");
printWebString += IrType;
printWebString += F("<BR>");
}
if (irReceiver != 0) irReceiver->enableIRIn(); // Start the receiver
}
break;
}
}
return success;
}
+222
View File
@@ -0,0 +1,222 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 036: MQ2 sensors ###############################################
//#######################################################################################################
#define PLUGIN_036
#define PLUGIN_ID_036 36
#define PLUGIN_NAME_036 "MQ2 smoke sensor [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_036 "LPG"
#define PLUGIN_VALUENAME2_036 "CO"
#define PLUGIN_VALUENAME3_036 "SMOKE"
/************************Hardware Related Macros************************************/
#define RL_VALUE (5) //define the load resistance on the board, in kilo ohms
#define RO_CLEAN_AIR_FACTOR (9.83) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
//which is derived from the chart in datasheet
/***********************Software Related Macros************************************/
#define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
//cablibration phase
#define READ_SAMPLE_INTERVAL (20) //define how many samples you are going to take in normal operation
#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
//normal operation
/**********************Application Related Macros**********************************/
#define GAS_LPG (0)
#define GAS_CO (1)
#define GAS_SMOKE (2)
/*****************************Globals***********************************************/
float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
//data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
//data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
//data format:{ x, y, slope}; point1: (lg200, 0.53), point2: (lg10000, -0.22)
float Ro = 10; //Ro is initialized to 10 kilo ohms
boolean Plugin_036(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_036;
Device[deviceCount].Type = DEVICE_TYPE_ANALOG;
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 = 3;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_036);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_036));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_036));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_036));
break;
}
case PLUGIN_INIT:
{
String log = F("MQ2 Calibrating...put it in fresh air");
addLog(LOG_LEVEL_INFO,log);
Ro = MQCalibration(); //Calibrating the sensor. Please make sure the sensor is in clean air
//when you perform the calibration
log = F("MQ2 Calibration is done...");
addLog(LOG_LEVEL_INFO,log);
log = F("Ro=");
log += Ro;
log += F("kohm");
addLog(LOG_LEVEL_INFO,log);
}
case PLUGIN_READ:
{
//Read LPG value
int value = MQGetGasPercentage(MQRead()/Ro,GAS_LPG);
UserVar[event->BaseVarIndex] = (float)value;
String log = F("MQ2 : LPG value: ");
log += value;
addLog(LOG_LEVEL_INFO,log);
//read CO value
value = MQGetGasPercentage(MQRead()/Ro,GAS_CO);
UserVar[event->BaseVarIndex +1] = (float)value;
log = F("MQ2 : CO value: ");
log += value;
addLog(LOG_LEVEL_INFO,log);
//Read SMOKE
value = MQGetGasPercentage(MQRead()/Ro,GAS_SMOKE);
UserVar[event->BaseVarIndex +2] = (float)value;
log = F("MQ2 : SMOKE value: ");
log += value;
addLog(LOG_LEVEL_INFO,log);
//affect result
success = true;
break;
}
}
return success;
}
/****************** MQResistanceCalculation ****************************************
Input: raw_adc - raw value read from adc, which represents the voltage
Output: the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
across the load resistor and its resistance, the resistance of the sensor
could be derived.
************************************************************************************/
float MQResistanceCalculation(int raw_adc)
{
return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}
/***************************** MQCalibration ****************************************
Input: mq_pin - analog channel
Output: Ro of the sensor
Remarks: This function assumes that the sensor is in clean air. It use
MQResistanceCalculation to calculates the sensor resistance in clean air
and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
10, which differs slightly between different sensors.
************************************************************************************/
float MQCalibration()
{
int i;
float val=0;
for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) { //take multiple samples
val += MQResistanceCalculation(analogRead(A0));
delay(CALIBRATION_SAMPLE_INTERVAL);
}
val = val/CALIBARAION_SAMPLE_TIMES; //calculate the average value
val = val/RO_CLEAN_AIR_FACTOR; //divided by RO_CLEAN_AIR_FACTOR yields the Ro
//according to the chart in the datasheet
return val;
}
/***************************** MQRead *********************************************
Input: mq_pin - analog channel
Output: Rs of the sensor
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
The Rs changes as the sensor is in the different consentration of the target
gas. The sample times and the time interval between samples could be configured
by changing the definition of the macros.
************************************************************************************/
float MQRead()
{
int i;
float rs=0;
for (i=0;i<READ_SAMPLE_TIMES;i++) {
rs += MQResistanceCalculation(analogRead(A0));
delay(READ_SAMPLE_INTERVAL);
}
rs = rs/READ_SAMPLE_TIMES;
return rs;
}
/***************************** MQGetGasPercentage **********************************
Input: rs_ro_ratio - Rs divided by Ro
gas_id - target gas type
Output: ppm of the target gas
Remarks: This function passes different curves to the MQGetPercentage function which
calculates the ppm (parts per million) of the target gas.
************************************************************************************/
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
{
if ( gas_id == GAS_LPG ) {
return MQGetPercentage(rs_ro_ratio,LPGCurve);
} else if ( gas_id == GAS_CO ) {
return MQGetPercentage(rs_ro_ratio,COCurve);
} else if ( gas_id == GAS_SMOKE ) {
return MQGetPercentage(rs_ro_ratio,SmokeCurve);
}
return 0;
}
/***************************** MQGetPercentage **********************************
Input: rs_ro_ratio - Rs divided by Ro
pcurve - pointer to the curve of the target gas
Output: ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
of the line could be derived if y(rs_ro_ratio) is provided. As it is a
logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
value.
************************************************************************************/
int MQGetPercentage(float rs_ro_ratio, float *pcurve)
{
return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}
#endif
+124
View File
@@ -0,0 +1,124 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################### Plugin 100 SRF01 Ultrasonic Distance Sensor ######################################
//#######################################################################################################
#include <SoftwareSerial.h>
#define PLUGIN_100
#define PLUGIN_ID_100 100
#define PLUGIN_NAME_100 "Ultrasonic Sensor - SRF01 [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_100 "Distance"
#define PLUGIN_100_srfAddress 0x01 // Address of the SFR01, default ist 0x01
#define PLUGIN_100_getSoft 0x5D // Byte to tell SRF01 we wish to read software version
#define PLUGIN_100_getRange 0x54 // Byte used to get range from SRF01 in cm
#define PLUGIN_100_getStatus 0x5F // Byte used to get the status of the transducer
SoftwareSerial *Plugin_100_SRF;
uint8_t Plugin_100_SRF_Pin;
boolean Plugin_100(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
byte timeout;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_100;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
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;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_100);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_100));
break;
}
case PLUGIN_INIT:
{
addLog(LOG_LEVEL_INFO, (char*)"INIT : SRF01");
Plugin_100_SRF_Pin = Settings.TaskDevicePin1[event->TaskIndex];
Plugin_100_SRF = new SoftwareSerial(Plugin_100_SRF_Pin, Plugin_100_SRF_Pin);
Plugin_100_SRF01_Cmd(PLUGIN_100_srfAddress, PLUGIN_100_getSoft);
for (timeout = 0; timeout < 10; timeout++) {
if (Plugin_100_SRF->available() < 1 ) {
delay(10);
} else {
int softVer = Plugin_100_SRF->read();
String log = F("SRF01 : Firmware-Version: ");
log += softVer;
addLog(LOG_LEVEL_INFO, log);
success = true;
return success;
};
};
addLog(LOG_LEVEL_ERROR, (char*)"SRF01-Init: protocol timeout!");
success = false;
break;
}
case PLUGIN_READ:
{
Plugin_100_SRF01_Cmd(PLUGIN_100_srfAddress, PLUGIN_100_getRange);
for (timeout = 0; timeout < 10; timeout++) {
if (Plugin_100_SRF->available() < 2 ) {
delay(10);
} else {
byte highByte = Plugin_100_SRF->read();
byte lowByte = Plugin_100_SRF->read();
int dist = ((highByte << 8) + lowByte);
UserVar[event->BaseVarIndex] = dist;
String log = F("SRF1 : Distance: ");
log += dist;
addLog(LOG_LEVEL_INFO, log);
success = true;
return success;
};
};
addLog(LOG_LEVEL_ERROR, (char*)"SRF01 : protocol timeout!");
UserVar[event->BaseVarIndex] = NAN;
success = false;
break;
}
}
return success;
}
//**************************************************************************/
// Send SRF01 Command
//**************************************************************************/
void Plugin_100_SRF01_Cmd(byte Address, byte cmd) {
Plugin_100_SRF->flush();
pinMode(Plugin_100_SRF_Pin, OUTPUT);
digitalWrite(Plugin_100_SRF_Pin, LOW);
delay(2);
digitalWrite(Plugin_100_SRF_Pin, HIGH);
delay(1);
Plugin_100_SRF->write(Address);
Plugin_100_SRF->write(cmd);
pinMode(Plugin_100_SRF_Pin, INPUT);
Plugin_100_SRF->flush();
}
#endif
+95
View File
@@ -0,0 +1,95 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 102: Nodo Event Bridge V2 #################################
//#######################################################################################################
#define PLUGIN_102
#define PLUGIN_ID_102 102
#define PLUGIN_NAME_102 "Nodo Event Bridge V2 [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_102 ""
boolean Plugin_102(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
static byte unicastTargetUnit = 0;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_102;
Device[deviceCount].Custom = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_102);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_102));
break;
}
case PLUGIN_UDP_IN:
{
// event->Data is pointer to UDP buffer
if (event->Data[0] == 255 && event->Data[1] == 254)
{
if (event->Data[11] == 0) // normal traffic, Nodo flags are 0
{
unicastTargetUnit = 0;
}
else
{
unicastTargetUnit = event->Data[9]; // remote source Nodo unit will be unicast target
}
for (byte x = 0; x < 16; x++)
Serial.write(event->Data[x]);
}
success = true;
break;
}
case PLUGIN_SERIAL_IN:
{
if (Serial.peek() == 255)
{
delay(20); // wait for message to complete
if (Serial.read() == 255 && Serial.read() == 254)
{
byte data[16];
data[0] = 255;
data[1] = 254;
byte count = 2;
while (Serial.available() && count < 16)
data[count++] = Serial.read();
IPAddress sendIP(255, 255, 255, 255);
if (data[11] != 0) // flags set, set to unicast mode
{
if ((unicastTargetUnit != 0) && (Nodes[unicastTargetUnit].ip[0] != 0))
for(byte x=0; x <4; x++)
sendIP[x] = Nodes[unicastTargetUnit].ip[x];
}
portUDP.beginPacket(sendIP, Settings.UDPPort);
portUDP.write(data, 16);
portUDP.endPacket();
}
success = true;
}
break;
}
}
return success;
}
#endif
+175
View File
@@ -0,0 +1,175 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//######################### Plugin 104: SRF02 Ultrasonic range finder sensor ############################
//#######################################################################################################
#define PLUGIN_104
#define PLUGIN_ID_104 104
#define PLUGIN_NAME_104 "Ultrasonic range finder - SRF02 [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_104 "Distance"
#define SRF02_ADDRESS (0x70) // default address (0x70 = datasheet address 0xE0)
#define SRF02_REG_COMMAND (0x00) // a read on this register returns the software revision
#define SRF02_REG_UNUSED (0x01)
#define SRF02_REG_RANGE_HIGH_BYTE (0x02)
#define SRF02_REG_RANGE_LOW_BYTE (0x03)
#define SRF02_REG_AUTOTUNE_MINIMUM_HIGH_BYTE (0x04)
#define SRF02_REG_AUTOTUNE_MINIMUM_LOW_BYTE (0x05)
#define SRF02_CMD_REAL_RANGING_MODE_INCH (0x50)
#define SRF02_CMD_REAL_RANGING_MODE_CM (0x51)
#define SRF02_CMD_REAL_RANGING_MODE_US (0x52)
#define SRF02_CMD_FAKE_RANGING_MODE_INCH (0x56)
#define SRF02_CMD_FAKE_RANGING_MODE_CM (0x57)
#define SRF02_CMD_FAKE_RANGING_MODE_US (0x58)
#define SRF02_CMD_FORCE_AUTOTUNE_RESTART (0x5C)
#define SRF02_CMD_I2C_CHANGE_SEQ_1 (0xA0)
#define SRF02_CMD_I2C_CHANGE_SEQ_2 (0xA5)
#define SRF02_CMD_I2C_CHANGE_SEQ_3 (0xAA)
uint8_t SRF02_i2caddr;
boolean Plugin_104(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_104;
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;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_104);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_104));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[1];
options[0] = F("Distance");
int optionValues[1];
optionValues[0] = 0;
string += F("<TR><TD>Report:<TD><select name='plugin_104_value'>");
string += F("<option value='");
string += optionValues[0];
string += "'";
if (choice == optionValues[0])
string += F(" selected");
string += ">";
string += options[0];
string += F("</option>");
string += F("</select>");
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg("plugin_104_value");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
case PLUGIN_INIT:
{
Plugin_104_begin();
success = true;
break;
}
case PLUGIN_READ:
{
float value;
value = Plugin_104_getDistance();
UserVar[event->BaseVarIndex] = value;
String log = F("SRF02 : value : ");
log += value;
log += F("mm");
addLog(LOG_LEVEL_INFO,log);
success = true;
break;
}
}
return success;
}
//**************************************************************************/
// I2C single byte write
//**************************************************************************/
void Plugin_104_wireWriteByte(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(SRF02_i2caddr);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}
//**************************************************************************/
// I2C two byte read
//**************************************************************************/
void Plugin_104_wireReadTwoBytes(uint8_t reg, uint16_t *value)
{
Wire.beginTransmission(SRF02_i2caddr);
Wire.write(reg);
Wire.endTransmission();
delayMicroseconds(10);
Wire.requestFrom(SRF02_i2caddr, (uint8_t)2);
*value = ((Wire.read() << 8) | Wire.read());
}
//**************************************************************************/
// Sensor setup
//**************************************************************************/
void Plugin_104_begin(void)
{
SRF02_i2caddr = SRF02_ADDRESS;
}
//**************************************************************************/
// Report distance
//**************************************************************************/
float Plugin_104_getDistance()
{
uint16_t value;
Plugin_104_wireWriteByte(SRF02_REG_COMMAND, SRF02_CMD_REAL_RANGING_MODE_US);
delay(70); // transmit -> receive turnaround time (up to 65ms)
Plugin_104_wireReadTwoBytes(SRF02_REG_RANGE_HIGH_BYTE, &value);
return (float)value/(float)5.82750583; // distance in [mm] (2*1000/343.2)
}
#endif
+136
View File
@@ -0,0 +1,136 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 108: WOL receiver #########################################
//#######################################################################################################
// This plugin receives Wake On Lan (WOL) messages that can be used to power on a connected device.
// Note that the ESP itself has no WOL feature. It must be active to receive this message.
// So you can't wake an ESP from deepsleep using WOL because Wifi is down during deepsleep.
#define PLUGIN_108
#define PLUGIN_ID_108 108
#define PLUGIN_NAME_108 "WOL Receiver [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_108 "WOL"
WiFiUDP *WOL;
boolean Plugin_108(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_108;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
Device[deviceCount].Custom = true;
Device[deviceCount].TimerOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_108);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_108));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
string += F("<TR><TD>Power control pin:<TD>");
addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]);
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2];
options[0] = F("Active Low");
options[1] = F("Active High");
int optionValues[2];
optionValues[0] = 0;
optionValues[1] = 1;
string += F("<TR><TD>Output state:<TD><select name='plugin_108_state'>");
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("plugin_108_state");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
case PLUGIN_INIT:
{
if (!WOL)
{
WOL = new WiFiUDP;
WOL->begin(7);
}
if (Settings.TaskDevicePin1[event->TaskIndex] != -1)
{
pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT);
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], !Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
}
}
success = true;
break;
case PLUGIN_ONCE_A_SECOND:
{
int packetSize = WOL->parsePacket();
if (packetSize)
{
statusLED(true);
char packetBuffer[128];
int len = WOL->read(packetBuffer, 128);
byte match = 0;
uint8_t mac[] = {0, 0, 0, 0, 0, 0};
uint8_t* macread = WiFi.macAddress(mac);
for (byte x = 0; x < 10; x++)
if (packetBuffer[x + 6] == macread[x])
match++;
if (match == 6)
{
String log = F("WOL : Magic packet received!");
addLog(LOG_LEVEL_INFO, log);
if (Settings.TaskDevicePin1[event->TaskIndex] != -1)
{
String log = F("WOL : Power cycle using pin: ");
log += Settings.TaskDevicePin1[event->TaskIndex];
addLog(LOG_LEVEL_INFO, log);
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
delay(500);
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], !Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
}
}
}
success = true;
break;
}
}
return success;
}
#endif
+260
View File
@@ -0,0 +1,260 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//################################## Plugin 109 RESOL DeltaSol Pro ######################################
//#######################################################################################################
#include <SoftwareSerial.h>
#define PLUGIN_109
#define PLUGIN_ID_109 109
#define PLUGIN_NAME_109 "RESOL DeltaSol Pro [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_109 "register"
// uart rx-buffer size
#define RXBUF_SIZE 32
// RESOL register options
#define REG_TEMP_SENSOR_1 0
#define REG_TEMP_SENSOR_2 1
#define REG_TEMP_SENSOR_3 2
#define REG_RELAIS_1 3
#define REG_RELAIS_2 4
// total number of selectable registers
#define RESOL_REGISTER_OPTIONS 5
uint8_t Plugin_109_UART_Pin;
boolean Plugin_109_init = false;
boolean valuesValid = false;
uint8_t RXbuf[RXBUF_SIZE];
uint8_t RXbuf_IDX;
int16_t T1, T2 ,T3;
uint8_t R1, R2;
SoftwareSerial *Plugin_109_UART;
// RESOL CRC check
uint8_t VBus_CalcCrc(uint8_t *buf, uint8_t len)
{
uint8_t crc;
crc = 0x7F;
for (uint8_t i = 0; i < len; i++)
crc = (crc - buf [i]) & 0x7F;
return crc;
}
boolean Plugin_109(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_109;
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
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].TimerOptional = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_109);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_109));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
int16_t choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[RESOL_REGISTER_OPTIONS];
uint optionValues[RESOL_REGISTER_OPTIONS];
optionValues[0] = REG_TEMP_SENSOR_1;
options[0] = F("Temperature sensor 1");
optionValues[1] = REG_TEMP_SENSOR_2;
options[1] = F("Temperature sensor 2");
optionValues[2] = REG_TEMP_SENSOR_3;
options[2] = F("Temperature sensor 3");
optionValues[3] = REG_RELAIS_1;
options[3] = F("Relais 1");
optionValues[4] = REG_RELAIS_2;
options[4] = F("Relais 2");
string += F("<TR><TD>Register:<TD><select name='plugin_109_register'>");
for (byte x = 0; x < RESOL_REGISTER_OPTIONS; 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("plugin_109_register");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
Plugin_109_init = false; // Force device setup next time
success = true;
break;
}
case PLUGIN_INIT:
{
addLog(LOG_LEVEL_INFO, (char*)"INIT : RESOL DeltaSol Pro");
Plugin_109_UART = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], false, (2 * RXBUF_SIZE)); // set RX und Tx Pin number, no invert, buffer
Plugin_109_init = true;
success = true;
break;
}
case PLUGIN_TEN_PER_SECOND:
{
if (Plugin_109_init == true)
{
// buffer filled with more than twize the frame size bytes? -> at least one complete frame should then be available
if (Plugin_109_UART->available() > (2 * 30))
{
// search for first appearance of SOF (0xAA)
while ((Plugin_109_UART->available()) && (Plugin_109_UART->read() != 0xAA));
RXbuf_IDX = 0;
RXbuf[RXbuf_IDX] = 0;
while ((Plugin_109_UART->available()) && (RXbuf[RXbuf_IDX] != 0xAA) && (RXbuf_IDX < (RXBUF_SIZE - 1)))
RXbuf[++RXbuf_IDX] = Plugin_109_UART->read();
if (RXbuf[RXbuf_IDX] == 0xAA)
{
// ********* DeltaSol Pro registers *********
// check CRC of first and second group
if ( (VBus_CalcCrc(&RXbuf[10], 5) == RXbuf[15]) && (VBus_CalcCrc(&RXbuf[16], 5) == RXbuf[21]) )
{
// Temperature sensor 1
T1 = RXbuf[10] + ((RXbuf[14] & (1 << 0)) << 7);
T1 += (RXbuf[11] + ((RXbuf[14] & (1 << 1)) << 6)) << 8;
// Temperature sensor 2
T2 = RXbuf[12] + ((RXbuf[14] & (1 << 2)) << 5);
T2 += (RXbuf[13] + ((RXbuf[14] & (1 << 3)) << 4)) << 8;
// Temperature sensor 3
T3 = RXbuf[16] + ((RXbuf[20] & (1 << 0)) << 7);
T3 += (RXbuf[17] + ((RXbuf[20] & (1 << 1)) << 6)) << 8;
// Relais/speed
R1 = RXbuf[18] + ((RXbuf[20] & (1 << 2)) << 5);
R2 = RXbuf[19] + ((RXbuf[20] & (1 << 3)) << 4);
valuesValid = true;
} else
valuesValid = false;
}
Plugin_109_UART->flush();
}
}
success = true;
break;
}
case PLUGIN_READ:
{
float regValue;
String log = F("RESOL : ");
if (valuesValid == true)
{
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
{
case REG_TEMP_SENSOR_1:
{
log += F("T1");
regValue = (float)T1 / 10;
break;
}
case REG_TEMP_SENSOR_2:
{
log += F("T2");
regValue = (float)T2 / 10;
break;
}
case REG_TEMP_SENSOR_3:
{
log += F("T3");
regValue = (float)T3 / 10;
break;
}
case REG_RELAIS_1:
{
log += F("R1");
regValue = R1;
break;
}
case REG_RELAIS_2:
{
log += F("R2");
regValue = R2;
break;
}
default:
{
log += F("unknown");
regValue = 0;
break;
}
}
log += F("=");
log += regValue;
addLog(LOG_LEVEL_INFO, log);
UserVar[event->BaseVarIndex] = regValue;
success = true;
break;
}
}
}
return success;
}
#endif
+121
View File
@@ -0,0 +1,121 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//############################# Plugin 111: SenseAir CO2 Sensors ########################################
//#######################################################################################################
/*
Plugin written by: Daniel Tedenljung info__AT__tedenljungconsulting.com
This plugin reads the co2 value of SenseAir Co2 Sensors. (S8 works, K30 is ongoing)
Datasheet can be found here for S8: http://www.senseair.com/products/oem-modules/senseair-s8/
Datasheet can be found here for K30: http://www.senseair.com/products/oem-modules/k30/
You can buy sensor from m.nu in Sweden:
S8 https://www.m.nu/co2matare-fran-senseair-p-1440.html
K30 https://www.m.nu/k30-co2matare-p-302.html
*/
#define PLUGIN_111
#define PLUGIN_ID_111 111
#define PLUGIN_NAME_111 "SenseAir CO2 Sensor [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_111 "PPM"
boolean Plugin_111_init = false;
#include <SoftwareSerial.h>
SoftwareSerial *Plugin_111_S8;
// 0xFE=Any address 0x04=Read input registers 0x0003=Starting address 0x0001=Number of registers to read 0xD5C5=CRC in reverse order
byte cmdReadPPM[] = {0xFE, 0x04, 0x00, 0x03, 0x00, 0x01, 0xD5, 0xC5};
byte ReciveBuffer[7];
byte Data[5];
byte co2[2];
long ppm;
boolean Plugin_111(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_111;
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
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_111);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_111));
break;
}
case PLUGIN_INIT:
{
Plugin_111_init = true;
Plugin_111_S8 = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]); // TODO: Explain this in plugin description RX=GPIO Setting 1, TX=GPIO Setting 2, Use 1kOhm in serie on datapins!
success = true;
break;
}
case PLUGIN_READ:
{
if (Plugin_111_init)
{
Plugin_111_S8->write(cmdReadPPM, sizeof(cmdReadPPM)); //Send the byte array
delay(50);
// Read answer from S8
int ByteCounter = 0;
while (Plugin_111_S8->available()) {
ReciveBuffer[ByteCounter] = Plugin_111_S8->read();
ByteCounter++;
}
// Divide recived chunk in different registers
for (int i = 0 ; i < sizeof(ReciveBuffer) - 2 ; i++)
{
Data[i] = ReciveBuffer[i];
}
co2[0] = Data[3];
co2[1] = Data[4];
ppm = (co2[0] << 8) | (co2[1]);
int value = ppm;
UserVar[event->BaseVarIndex] = (float)value;
String log = F("S8 : PPM value: "); //TODO: Different string if K30 is used.
log += value;
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
break;
}
}
return success;
}
#endif
+237
View File
@@ -0,0 +1,237 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 112: Power Counter ########################################
//#######################################################################################################
//This sketch is based on Plugin 003: Pulse
#define PLUGIN_112
#define PLUGIN_ID_112 112
#define PLUGIN_NAME_112 "Power Counter [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_112 "PowerWh"
#define PLUGIN_VALUENAME2_112 "PowerCountTotal"
unsigned long Plugin_112_pulseCounter[TASKS_MAX];
unsigned long Plugin_112_pulseTotalCounter[TASKS_MAX];
unsigned long Plugin_112_pulseTime[TASKS_MAX];
unsigned long Plugin_112_pulseTimePrevious[TASKS_MAX];
float Plugin_112_pulseUsage[TASKS_MAX];
boolean Plugin_112(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_112;
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].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_112);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_112));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_112));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Debounce Time (mSec):<TD><input type='text' name='plugin_112_debounce' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += tmpString;
sprintf_P(tmpString, PSTR("<TR><TD>Pulses per KWh:<TD><input type='text' name='plugin_112_pulsesperkwh' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
string += tmpString;
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg("plugin_112_debounce");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg("plugin_112_pulsesperkwh");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
success = true;
break;
}
case PLUGIN_WEBFORM_SHOW_VALUES:
{
string += ExtraTaskSettings.TaskDeviceValueNames[0];
string += F(":");
string += Plugin_112_pulseUsage[event->TaskIndex];
string += F("<BR>");
string += ExtraTaskSettings.TaskDeviceValueNames[1];
string += F(":");
string += Plugin_112_pulseTotalCounter[event->TaskIndex];
success = true;
break;
}
case PLUGIN_INIT:
{
String log = F("INIT : Power Counter ");
log += Settings.TaskDevicePin1[event->TaskIndex];
addLog(LOG_LEVEL_INFO,log);
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
Plugin_112_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex);
success = true;
break;
}
case PLUGIN_READ:
{
Plugin_112_idleusage(event->TaskIndex);
UserVar[event->BaseVarIndex] = Plugin_112_pulseUsage[event->TaskIndex];
UserVar[event->BaseVarIndex+1] = Plugin_112_pulseTotalCounter[event->TaskIndex];
Plugin_112_pulseCounter[event->TaskIndex] = 0;
success = true;
break;
}
}
return success;
}
/*********************************************************************************************\
* Update usage when no pulse has been received for some time, so it will decrease on every
* PLUGIN_READ event instead off keeping the last calculated usage value.
\*********************************************************************************************/
void Plugin_112_idleusage(byte Index)
{
unsigned long PulseTime=millis() - Plugin_112_pulseTimePrevious[Index];
if(PulseTime > (Settings.TaskDeviceTimer[Index] * 1000) && //More than $device_delay passed since last pulse
PulseTime > Plugin_112_pulseTime[Index] ) { //More than last pulse interval
// Let's prevent divison by zero
if(Settings.TaskDevicePluginConfig[Index][1]==0) {
Settings.TaskDevicePluginConfig[Index][1]=1000; // if not configged correctly prevent crashes and set it to 1000 as default value.
}
// WH = =3600000/[pulses per kwh]/[time since last pulse (ms)]
Plugin_112_pulseUsage[Index] = (3600000000./Settings.TaskDevicePluginConfig[Index][1])/PulseTime;
}
}
/*********************************************************************************************\
* Check Pulse Counters (called from irq handler)
\*********************************************************************************************/
void Plugin_112_pulsecheck(byte Index)
{
unsigned long PulseTime=millis() - Plugin_112_pulseTimePrevious[Index];
if(PulseTime > Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task
{
Plugin_112_pulseTimePrevious[Index]=millis(); // moved this up as the operations below might take some time
Plugin_112_pulseCounter[Index]++;
Plugin_112_pulseTotalCounter[Index]++;
Plugin_112_pulseTime[Index] = PulseTime;
// Let's prevent divison by zero
if(Settings.TaskDevicePluginConfig[Index][1]==0) {
Settings.TaskDevicePluginConfig[Index][1]=1000; // if not configged correctly prevent crashes and set it to 1000 as default value.
}
// WH = =3600000/[pulses per kwh]/[time since last pulse (ms)]
Plugin_112_pulseUsage[Index] = (3600000000./Settings.TaskDevicePluginConfig[Index][1])/PulseTime;
}
}
/*********************************************************************************************\
* Pulse Counter IRQ handlers
\*********************************************************************************************/
void Plugin_112_pulse_interrupt1()
{
Plugin_112_pulsecheck(0);
}
void Plugin_112_pulse_interrupt2()
{
Plugin_112_pulsecheck(1);
}
void Plugin_112_pulse_interrupt3()
{
Plugin_112_pulsecheck(2);
}
void Plugin_112_pulse_interrupt4()
{
Plugin_112_pulsecheck(3);
}
void Plugin_112_pulse_interrupt5()
{
Plugin_112_pulsecheck(4);
}
void Plugin_112_pulse_interrupt6()
{
Plugin_112_pulsecheck(5);
}
void Plugin_112_pulse_interrupt7()
{
Plugin_112_pulsecheck(6);
}
void Plugin_112_pulse_interrupt8()
{
Plugin_112_pulsecheck(7);
}
/*********************************************************************************************\
* Init Pulse Counters
\*********************************************************************************************/
void Plugin_112_pulseinit(byte Par1, byte Index)
{
// Init IO pins
String log = F("Power Counter: Init");
addLog(LOG_LEVEL_INFO,log);
switch (Index)
{
case 0:
attachInterrupt(Par1, Plugin_112_pulse_interrupt1, FALLING);
break;
case 1:
attachInterrupt(Par1, Plugin_112_pulse_interrupt2, FALLING);
break;
case 2:
attachInterrupt(Par1, Plugin_112_pulse_interrupt3, FALLING);
break;
case 3:
attachInterrupt(Par1, Plugin_112_pulse_interrupt4, FALLING);
break;
case 4:
attachInterrupt(Par1, Plugin_112_pulse_interrupt5, FALLING);
break;
case 5:
attachInterrupt(Par1, Plugin_112_pulse_interrupt6, FALLING);
break;
case 6:
attachInterrupt(Par1, Plugin_112_pulse_interrupt7, FALLING);
break;
case 7:
attachInterrupt(Par1, Plugin_112_pulse_interrupt8, FALLING);
break;
}
}
#endif
+352
View File
@@ -0,0 +1,352 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin-113: SI1145 - UV index / IR / visible ####################
//#######################################################################################################
//#include <Adafruit_SI1145.h>
#define PLUGIN_113
#define PLUGIN_ID_113 113
#define PLUGIN_NAME_113 "SI1145 UV index (Adafruit-QA) [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_113 "VISIBLE"
#define PLUGIN_VALUENAME2_113 "INFRA"
#define PLUGIN_VALUENAME3_113 "UV"
// ADAFRUIT SI1145 LIBRARY - Adafruit_SI1145.h
// =============================================
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
/* COMMANDS */
#define SI1145_PARAM_QUERY 0x80
#define SI1145_PARAM_SET 0xA0
#define SI1145_NOP 0x0
#define SI1145_RESET 0x01
#define SI1145_BUSADDR 0x02
#define SI1145_PS_FORCE 0x05
#define SI1145_ALS_FORCE 0x06
#define SI1145_PSALS_FORCE 0x07
#define SI1145_PS_PAUSE 0x09
#define SI1145_ALS_PAUSE 0x0A
#define SI1145_PSALS_PAUSE 0xB
#define SI1145_PS_AUTO 0x0D
#define SI1145_ALS_AUTO 0x0E
#define SI1145_PSALS_AUTO 0x0F
#define SI1145_GET_CAL 0x12
/* Parameters */
#define SI1145_PARAM_I2CADDR 0x00
#define SI1145_PARAM_CHLIST 0x01
#define SI1145_PARAM_CHLIST_ENUV 0x80
#define SI1145_PARAM_CHLIST_ENAUX 0x40
#define SI1145_PARAM_CHLIST_ENALSIR 0x20
#define SI1145_PARAM_CHLIST_ENALSVIS 0x10
#define SI1145_PARAM_CHLIST_ENPS1 0x01
#define SI1145_PARAM_CHLIST_ENPS2 0x02
#define SI1145_PARAM_CHLIST_ENPS3 0x04
#define SI1145_PARAM_PSLED12SEL 0x02
#define SI1145_PARAM_PSLED12SEL_PS2NONE 0x00
#define SI1145_PARAM_PSLED12SEL_PS2LED1 0x10
#define SI1145_PARAM_PSLED12SEL_PS2LED2 0x20
#define SI1145_PARAM_PSLED12SEL_PS2LED3 0x40
#define SI1145_PARAM_PSLED12SEL_PS1NONE 0x00
#define SI1145_PARAM_PSLED12SEL_PS1LED1 0x01
#define SI1145_PARAM_PSLED12SEL_PS1LED2 0x02
#define SI1145_PARAM_PSLED12SEL_PS1LED3 0x04
#define SI1145_PARAM_PSLED3SEL 0x03
#define SI1145_PARAM_PSENCODE 0x05
#define SI1145_PARAM_ALSENCODE 0x06
#define SI1145_PARAM_PS1ADCMUX 0x07
#define SI1145_PARAM_PS2ADCMUX 0x08
#define SI1145_PARAM_PS3ADCMUX 0x09
#define SI1145_PARAM_PSADCOUNTER 0x0A
#define SI1145_PARAM_PSADCGAIN 0x0B
#define SI1145_PARAM_PSADCMISC 0x0C
#define SI1145_PARAM_PSADCMISC_RANGE 0x20
#define SI1145_PARAM_PSADCMISC_PSMODE 0x04
#define SI1145_PARAM_ALSIRADCMUX 0x0E
#define SI1145_PARAM_AUXADCMUX 0x0F
#define SI1145_PARAM_ALSVISADCOUNTER 0x10
#define SI1145_PARAM_ALSVISADCGAIN 0x11
#define SI1145_PARAM_ALSVISADCMISC 0x12
#define SI1145_PARAM_ALSVISADCMISC_VISRANGE 0x20
#define SI1145_PARAM_ALSIRADCOUNTER 0x1D
#define SI1145_PARAM_ALSIRADCGAIN 0x1E
#define SI1145_PARAM_ALSIRADCMISC 0x1F
#define SI1145_PARAM_ALSIRADCMISC_RANGE 0x20
#define SI1145_PARAM_ADCCOUNTER_511CLK 0x70
#define SI1145_PARAM_ADCMUX_SMALLIR 0x00
#define SI1145_PARAM_ADCMUX_LARGEIR 0x03
/* REGISTERS */
#define SI1145_REG_PARTID 0x00
#define SI1145_REG_REVID 0x01
#define SI1145_REG_SEQID 0x02
#define SI1145_REG_INTCFG 0x03
#define SI1145_REG_INTCFG_INTOE 0x01
#define SI1145_REG_INTCFG_INTMODE 0x02
#define SI1145_REG_IRQEN 0x04
#define SI1145_REG_IRQEN_ALSEVERYSAMPLE 0x01
#define SI1145_REG_IRQEN_PS1EVERYSAMPLE 0x04
#define SI1145_REG_IRQEN_PS2EVERYSAMPLE 0x08
#define SI1145_REG_IRQEN_PS3EVERYSAMPLE 0x10
#define SI1145_REG_IRQMODE1 0x05
#define SI1145_REG_IRQMODE2 0x06
#define SI1145_REG_HWKEY 0x07
#define SI1145_REG_MEASRATE0 0x08
#define SI1145_REG_MEASRATE1 0x09
#define SI1145_REG_PSRATE 0x0A
#define SI1145_REG_PSLED21 0x0F
#define SI1145_REG_PSLED3 0x10
#define SI1145_REG_UCOEFF0 0x13
#define SI1145_REG_UCOEFF1 0x14
#define SI1145_REG_UCOEFF2 0x15
#define SI1145_REG_UCOEFF3 0x16
#define SI1145_REG_PARAMWR 0x17
#define SI1145_REG_COMMAND 0x18
#define SI1145_REG_RESPONSE 0x20
#define SI1145_REG_IRQSTAT 0x21
#define SI1145_REG_IRQSTAT_ALS 0x01
#define SI1145_REG_ALSVISDATA0 0x22
#define SI1145_REG_ALSVISDATA1 0x23
#define SI1145_REG_ALSIRDATA0 0x24
#define SI1145_REG_ALSIRDATA1 0x25
#define SI1145_REG_PS1DATA0 0x26
#define SI1145_REG_PS1DATA1 0x27
#define SI1145_REG_PS2DATA0 0x28
#define SI1145_REG_PS2DATA1 0x29
#define SI1145_REG_PS3DATA0 0x2A
#define SI1145_REG_PS3DATA1 0x2B
#define SI1145_REG_UVINDEX0 0x2C
#define SI1145_REG_UVINDEX1 0x2D
#define SI1145_REG_PARAMRD 0x2E
#define SI1145_REG_CHIPSTAT 0x30
#define SI1145_ADDR 0x60
class Adafruit_SI1145 {
public:
Adafruit_SI1145(void);
boolean begin();
void reset();
uint16_t readUV();
uint16_t readIR();
uint16_t readVisible();
uint16_t readProx();
private:
uint16_t read16(uint8_t addr);
uint8_t read8(uint8_t addr);
void write8(uint8_t reg, uint8_t val);
uint8_t readParam(uint8_t p);
uint8_t writeParam(uint8_t p, uint8_t v);
uint8_t _addr;
};
// ADAFRUIT SI1145 LIBRARY - Adafruit_SI1145.cpp
// =============================================
Adafruit_SI1145::Adafruit_SI1145() {
_addr = SI1145_ADDR;
}
boolean Adafruit_SI1145::begin(void) {
Wire.begin();
uint8_t id = read8(SI1145_REG_PARTID);
if (id != 0x45) return false; // look for SI1145
reset();
/***********************************/
// enable UVindex measurement coefficients!
write8(SI1145_REG_UCOEFF0, 0x29);
write8(SI1145_REG_UCOEFF1, 0x89);
write8(SI1145_REG_UCOEFF2, 0x02);
write8(SI1145_REG_UCOEFF3, 0x00);
// enable UV sensor
writeParam(SI1145_PARAM_CHLIST, SI1145_PARAM_CHLIST_ENUV |
SI1145_PARAM_CHLIST_ENALSIR | SI1145_PARAM_CHLIST_ENALSVIS |
SI1145_PARAM_CHLIST_ENPS1);
// enable interrupt on every sample
write8(SI1145_REG_INTCFG, SI1145_REG_INTCFG_INTOE);
write8(SI1145_REG_IRQEN, SI1145_REG_IRQEN_ALSEVERYSAMPLE);
/****************************** Prox Sense 1 */
// program LED current
write8(SI1145_REG_PSLED21, 0x03); // 20mA for LED 1 only
writeParam(SI1145_PARAM_PS1ADCMUX, SI1145_PARAM_ADCMUX_LARGEIR);
// prox sensor #1 uses LED #1
writeParam(SI1145_PARAM_PSLED12SEL, SI1145_PARAM_PSLED12SEL_PS1LED1);
// fastest clocks, clock div 1
writeParam(SI1145_PARAM_PSADCGAIN, 0);
// take 511 clocks to measure
writeParam(SI1145_PARAM_PSADCOUNTER, SI1145_PARAM_ADCCOUNTER_511CLK);
// in prox mode, high range
writeParam(SI1145_PARAM_PSADCMISC, SI1145_PARAM_PSADCMISC_RANGE|
SI1145_PARAM_PSADCMISC_PSMODE);
writeParam(SI1145_PARAM_ALSIRADCMUX, SI1145_PARAM_ADCMUX_SMALLIR);
// fastest clocks, clock div 1
writeParam(SI1145_PARAM_ALSIRADCGAIN, 0);
// take 511 clocks to measure
writeParam(SI1145_PARAM_ALSIRADCOUNTER, SI1145_PARAM_ADCCOUNTER_511CLK);
// in high range mode
writeParam(SI1145_PARAM_ALSIRADCMISC, SI1145_PARAM_ALSIRADCMISC_RANGE);
// fastest clocks, clock div 1
writeParam(SI1145_PARAM_ALSVISADCGAIN, 0);
// take 511 clocks to measure
writeParam(SI1145_PARAM_ALSVISADCOUNTER, SI1145_PARAM_ADCCOUNTER_511CLK);
// in high range mode (not normal signal)
writeParam(SI1145_PARAM_ALSVISADCMISC, SI1145_PARAM_ALSVISADCMISC_VISRANGE);
/************************/
// measurement rate for auto
write8(SI1145_REG_MEASRATE0, 0xFF); // 255 * 31.25uS = 8ms
// auto run
write8(SI1145_REG_COMMAND, SI1145_PSALS_AUTO);
return true;
}
void Adafruit_SI1145::reset() {
write8(SI1145_REG_MEASRATE0, 0);
write8(SI1145_REG_MEASRATE1, 0);
write8(SI1145_REG_IRQEN, 0);
write8(SI1145_REG_IRQMODE1, 0);
write8(SI1145_REG_IRQMODE2, 0);
write8(SI1145_REG_INTCFG, 0);
write8(SI1145_REG_IRQSTAT, 0xFF);
write8(SI1145_REG_COMMAND, SI1145_RESET);
delay(10);
write8(SI1145_REG_HWKEY, 0x17);
delay(10);
}
//////////////////////////////////////////////////////
// returns the UV index * 100 (divide by 100 to get the index)
uint16_t Adafruit_SI1145::readUV(void) { return read16(0x2C); }
// returns visible+IR light levels
uint16_t Adafruit_SI1145::readVisible(void) { return read16(0x22); }
// returns IR light levels
uint16_t Adafruit_SI1145::readIR(void) { return read16(0x24); }
// returns "Proximity" - assumes an IR LED is attached to LED
uint16_t Adafruit_SI1145::readProx(void) {
return read16(0x26);
}
/*********************************************************************/
uint8_t Adafruit_SI1145::writeParam(uint8_t p, uint8_t v) {
//Serial.print("Param 0x"); Serial.print(p, HEX);
//Serial.print(" = 0x"); Serial.println(v, HEX);
write8(SI1145_REG_PARAMWR, v);
write8(SI1145_REG_COMMAND, p | SI1145_PARAM_SET);
return read8(SI1145_REG_PARAMRD);
}
uint8_t Adafruit_SI1145::readParam(uint8_t p) {
write8(SI1145_REG_COMMAND, p | SI1145_PARAM_QUERY);
return read8(SI1145_REG_PARAMRD);
}
/*********************************************************************/
uint8_t Adafruit_SI1145::read8(uint8_t reg) {
uint16_t val;
Wire.beginTransmission(_addr);
Wire.write((uint8_t)reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)_addr, (uint8_t)1);
return Wire.read();
}
uint16_t Adafruit_SI1145::read16(uint8_t a) {
uint16_t ret;
Wire.beginTransmission(_addr); // start transmission to device
Wire.write(a); // sends register address to read from
Wire.endTransmission(); // end transmission
Wire.requestFrom(_addr, (uint8_t)2);// send data n-bytes read
ret = Wire.read(); // receive DATA
ret |= (uint16_t)Wire.read() << 8; // receive DATA
return ret;
}
void Adafruit_SI1145::write8(uint8_t reg, uint8_t val) {
Wire.beginTransmission(_addr); // start transmission to device
Wire.write(reg); // sends register address to write
Wire.write(val); // sends value
Wire.endTransmission(); // end transmission
}
Adafruit_SI1145 uv = Adafruit_SI1145();
boolean Plugin_113_init = false;
boolean Plugin_113(byte function, struct EventStruct *event, String& string)
{
boolean success=false;
switch(function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_113;
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 = 3;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_113);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_113));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_113));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_113));
break;
}
case PLUGIN_READ:
{
if (!Plugin_113_init)
{
// ziadnu EXTRA inicializaciu netreba ...
if (uv.begin()) { Plugin_113_init = true; }
}
float si1145_vis = 0.0;
float si1145_ir = 0.0;
float si1145_uv = 0.0;
si1145_vis = uv.readVisible();
si1145_ir = uv.readIR();
si1145_uv = uv.readUV();
si1145_uv /= 100.0;
UserVar[event->BaseVarIndex] = si1145_vis;
UserVar[event->BaseVarIndex+1] = si1145_ir;
UserVar[event->BaseVarIndex+2] = si1145_uv;
String log = F("SI1145: Visible: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO,log);
log = F("SI1145: Infrared: ");
log += UserVar[event->BaseVarIndex+1];
addLog(LOG_LEVEL_INFO,log);
log = F("SI1145: UV index: ");
log += UserVar[event->BaseVarIndex+2];
addLog(LOG_LEVEL_INFO,log);
success=true;
break;
}
}
return success;
}
#endif
+178
View File
@@ -0,0 +1,178 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 114: DMS501A #############################################
//#################################### by serpa #############################################
//#######################################################################################################
#define PLUGIN_114
#define PLUGIN_ID_114 114
#define PLUGIN_NAME_114 "Dust sensor - DSM501a [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_114 "PM1.0" // from the datasheet the detection is from PM1 and up. You could have from PM1 to PM2.5, on subtracting PM2.5 value on PM1 value. This value come from the pin #4
#define PLUGIN_VALUENAME2_114 "PM2.5" // from the datasheet the detection is from PM2.5 and up. This value come from the pin #2. With different resistor topn the pin #1, you could adjust the size threshold detection
unsigned long Plugin_114_pulseCounter[TASKS_MAX];
unsigned long Plugin_114_pulseTotalCounter[TASKS_MAX];
unsigned long Plugin_114_pulseTime[TASKS_MAX];
unsigned long Plugin_114_pulseTimePrevious[TASKS_MAX];
unsigned long tstart1, tstart2;
unsigned long tduration = 30000; // duration of measurement in ms
//unsigned long triggerOn; // start of pulse time in us
//unsigned long triggerOff; // end of pulse time in us
//unsigned long lowpulseoccupancy; // duration of pulse in us
volatile unsigned long thigh1, thigh2;
volatile unsigned long tlow1, tlow2;
volatile unsigned long startlow1, startlow2;
volatile unsigned long starthigh1, starthigh2;
volatile boolean done1, done2;
volatile boolean value1, value2;
//boolean trigger = false;
volatile float ratio1, ratio2;
volatile int DMSpin1, DMSpin2;
float dens1, dens2;
boolean Plugin_114(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_114;
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
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;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_114);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_114));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_114));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Averaging Time (mSec):<TD><input type='text' name='plugin_114' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
string += tmpString;
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg("plugin_114");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
// tduration= Settings.TaskDevicePluginConfig[event->TaskIndex][0];
success = true;
break;
}
case PLUGIN_INIT:
{
String log = F("INIT : DSM501A ");
log += Settings.TaskDevicePin1[event->TaskIndex];
addLog(LOG_LEVEL_INFO, log);
// tduration= Settings.TaskDevicePluginConfig[event->TaskIndex][0];
tstart1 = millis();
startlow1 = micros();
starthigh1 = startlow1;
DMSpin1 = Settings.TaskDevicePin1[event->TaskIndex];
pinMode(DMSpin1, INPUT);
attachInterrupt(digitalPinToInterrupt(DMSpin1), Plugin_114_ISR1, CHANGE);
tstart2 = millis();
startlow2 = micros();
starthigh2 = startlow2;
DMSpin2 = Settings.TaskDevicePin2[event->TaskIndex];
pinMode(DMSpin2, INPUT);
attachInterrupt(digitalPinToInterrupt(DMSpin2), Plugin_114_ISR2, CHANGE);
success = true;
break;
}
case PLUGIN_READ:
{
if (done1 && done2) {
done1 = FALSE;
dens1 = ratio1 * 110; // ug/m^3
done2 = FALSE;
dens2 = ratio2 * 110; // ug/m^3
String log = F("DSM501A: PM1.0=");
log += dens1;
log += F(" PM2.5=");
log += dens2;
addLog(LOG_LEVEL_INFO, log);
UserVar[event->BaseVarIndex] = (float) dens1;
UserVar[event->BaseVarIndex + 1] = (float) dens2;
}
success = true;
break;
}
}
return success;
}
/*********************************************************************************************\
Check Pulse (called from irq handler)
\*********************************************************************************************/
void Plugin_114_ISR1()
{
value1 = digitalRead(DMSpin1); //read input pin just changed
if (value1 == 0) { // gone low
startlow1 = micros(); // record starting of low period
thigh1 += startlow1 - starthigh1; // record duration of past high state
} else { // gone high
starthigh1 = micros(); // record starting of high period
tlow1 += starthigh1 - startlow1; // record duration of past low state
}
if (millis() > tstart1 + tduration) { // check if average time has past
tstart1 = millis(); // reset time period
ratio1 = float(tlow1) / float(thigh1 + tlow1) * 100; // compute ratio low to total
tlow1 = 0; // reset low time counter
thigh1 = 0; // reset high time counter
done1 = TRUE; // set reading complete flag
}
}
/*********************************************************************************************\
Check Pulse (called from irq handler)
\*********************************************************************************************/
void Plugin_114_ISR2()
{
value2 = digitalRead(DMSpin2); //read input pin just changed
if (value2 == 0) { // gone low
startlow2 = micros(); // record starting of low period
thigh2 += startlow2 - starthigh2; // record duration of past high state
} else { // gone high
starthigh2 = micros(); // record starting of high period
tlow2 += starthigh2 - startlow2; // record duration of past low state
}
if (millis() > tstart2 + tduration) { // check if average time has past
tstart2 = millis(); // reset time period
ratio2 = float(tlow2) / float(thigh2 + tlow2) * 100; // compute ratio low to high
tlow2 = 0; // reset low time counter
thigh2 = 0; // reset high time counter
done2 = TRUE; // set reading complete flag
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
+17 -13
View File
@@ -1,15 +1,17 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 040: Serial RFID ID-12 ####################################
//#################################### Plugin 116: Serial RFID ID-12 ####################################
//#######################################################################################################
#define PLUGIN_040
#define PLUGIN_ID_040 40
#define PLUGIN_NAME_040 "RFID Reader - ID12LA/RDM6300"
#define PLUGIN_VALUENAME1_040 "Tag"
#define PLUGIN_116
#define PLUGIN_ID_116 116
#define PLUGIN_NAME_116 "RFID Reader - ID12LA [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_116 "Tag"
boolean Plugin_040_init = false;
boolean Plugin_116_init = false;
boolean Plugin_040(byte function, struct EventStruct *event, String& string)
boolean Plugin_116(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -18,7 +20,7 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_040;
Device[++deviceCount].Number = PLUGIN_ID_116;
Device[deviceCount].VType = SENSOR_TYPE_LONG;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
@@ -33,20 +35,20 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_040);
string = F(PLUGIN_NAME_116);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_040));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_116));
break;
}
case PLUGIN_INIT:
{
Plugin_040_init = true;
Plugin_116_init = true;
Serial.begin(9600);
success = true;
break;
@@ -55,7 +57,7 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
case PLUGIN_SERIAL_IN:
{
if (Plugin_040_init)
if (Plugin_116_init)
{
byte val = 0;
byte code[6];
@@ -107,11 +109,12 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
// temp woraround, ESP Easy framework does not currently prepare this...
byte index = 0;
for (byte y = 0; y < TASKS_MAX; y++)
if (Settings.TaskDeviceNumber[y] == PLUGIN_ID_040)
if (Settings.TaskDeviceNumber[y] == PLUGIN_ID_116)
index = y;
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[index]);
event->TaskIndex = index;
event->BaseVarIndex = index * VARS_PER_TASK;
event->idx = Settings.TaskDeviceID[index];
event->sensorType = Device[DeviceIndex].VType;
// endof workaround
@@ -134,3 +137,4 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
return success;
}
#endif
+103 -72
View File
@@ -1,5 +1,5 @@
//#######################################################################################################
//#################################### Plugin 045: MPU6050 [Testing] ####################################
//#################################### Plugin 118: MPU6050 [Testing] ####################################
//#######################################################################################################
// Based on the works of Nolan Gilley @ https://home-assistant.io/blog/2016/08/03/laundry-automation-update/
@@ -34,14 +34,13 @@
// detection function to setup the plugin for further use.
// The plugin can simultanious be used with two MPU6050 devices by adding multiple instances.
// Originally released in the PlayGround as Plugin 118.
// Plugin var usage:
// Globals - int16_t _P045_axis[3][5][2] Array to store sensorvalues of the axis
// _P045_axis[0-2][x][x] = x, y, z axis
// _P045_axis[x][0-4][x] = min values, max values, range (max-min), a-values, g-values.
// _P045_axis[x][x][0-1] = device address: 0=0x68, 1=0x69
// - long _P045_time[2] = Timer to check values each 5 seconds for each used device address.
// Globals - int16_t _P118_axis[3][5][2] Array to store sensorvalues of the axis
// _P118_axis[0-2][x][x] = x, y, z axis
// _P118_axis[x][0-4][x] = min values, max values, range (max-min), a-values, g-values.
// _P118_axis[x][x][0-1] = device address: 0=0x68, 1=0x69
// - long _P118_time[2] = Timer to check values each 5 seconds for each used device address.
// Framework - Settings.TaskDevicePluginConfig[x][0] - Device address (0x68 | 0x69)
// Settings.TaskDevicePluginConfig[x][1] - Instance function
@@ -71,15 +70,15 @@
#define MPU6050_PWR1_CLKSEL_BIT 2
#define MPU6050_PWR1_CLKSEL_LENGTH 3
#define PLUGIN_045
#define PLUGIN_ID_045 45
#define PLUGIN_NAME_045 "MPU 6050 [TESTING]"
#define PLUGIN_VALUENAME1_045 ""
#define PLUGIN_118
#define PLUGIN_ID_118 118
#define PLUGIN_NAME_118 "MPU 6050 [TESTING]"
#define PLUGIN_VALUENAME1_118 ""
int16_t _P045_axis[3][5][2]; // [xyz], [min/max/range,a,g], [0x68/0x69]
long _P045_time[2];
int16_t _P118_axis[3][5][2]; // [xyz], [min/max/range,a,g], [0x68/0x69]
long _P118_time[2];
boolean Plugin_045(byte function, struct EventStruct *event, String& string)
boolean Plugin_118(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -88,7 +87,7 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_045;
Device[++deviceCount].Number = PLUGIN_ID_118;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].ValueCount = 1; // Unfortunatly domoticz has no custom multivalue sensors.
@@ -100,13 +99,13 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_045);
string = F(PLUGIN_NAME_118);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_045));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_118));
break;
}
@@ -114,19 +113,28 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
{
// Setup webform for address selection
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*
String options[10];
options[0] = F("0x68 - default settings (ADDR Low)");
options[1] = F("0x69 - alternate settings (ADDR High)");
*/
int optionValues[2];
optionValues[0] = 0x68;
optionValues[1] = 0x69;
addFormSelectorI2C(string, F("plugin_045_address"), 2, optionValues, choice);
addFormNote(string, F("ADDR Low=0x68, High=0x69"));
string += F("<TR><TD>I2C Address:<TD><select name='plugin_118_address'>");
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>");
// Setup webform for instance function
choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options[10];
string += F("<TR><TD>Function:<TD><select name='plugin_118_function'>");
options[0] = F("Movement detection");
options[1] = F("Range acceleration X");
options[2] = F("Range acceleration Y");
@@ -137,29 +145,45 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
options[7] = F("G-force X");
options[8] = F("G-force Y");
options[9] = F("G-force Z");
addFormSelector(string, F("Function"), F("plugin_045_function"), 10, options, NULL, choice);
for (byte x = 0; x < 10; x++)
{
string += F("<option value='");
string += x;
string += "'";
if (choice == x)
string += F(" selected");
string += ">";
string += options[x];
string += F("</option>");
}
string += F("</select>");
if (choice == 0) {
// If this is instance function 0, setup webform for additional vars
// Show some user information about the webform and what the vars mean.
string += F("<TR><TD><TD>The thresholdvalues (0-65535) can be used to set a threshold for one or more<br>");
string += F("axis. The axis will trigger when the range for that axis exceeds the threshold<br>");
string += F("value. A value of 0 disables movement detection for that axis.");
addFormNumericBox(string, F("Detection threshold X"), F("plugin_045_threshold_x"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 65535);
addFormNumericBox(string, F("Detection threshold Y"), F("plugin_045_threshold_y"), Settings.TaskDevicePluginConfig[event->TaskIndex][3], 0, 65535);
addFormNumericBox(string, F("Detection threshold Z"), F("plugin_045_threshold_z"), Settings.TaskDevicePluginConfig[event->TaskIndex][4], 0, 65535);
string += F("<TR><TD>Detection threshold X:<TD><input type='text' size='6' maxlength='6' name='plugin_118_threshold_x' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][2];
string += F("'>");
string += F("<TR><TD>Detection threshold Y:<TD><input type='text' size='6' maxlength='6' name='plugin_118_threshold_y' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][3];
string += F("'>");
string += F("<TR><TD>Detection threshold Z:<TD><input type='text' size='6' maxlength='6' name='plugin_118_threshold_z' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][4];
string += F("'>");
string += F("<TR><TD><TD>Each 30 seconds a counter for the detection window is increased plus all axis<br>");
string += F("are checked and if they *all* exceeded the threshold values, a counter is increased.<br>");
string += F("Each period, defined by the [detection window], the counter is checked against<br>");
string += F("the [min. detection count] and if found equal or larger, movement is detected.<br>");
string += F("If in the next window the [min. detection count] value is not met, movement has stopped.");
string += F("The [detection window] cannot be smaller than the [min. detection count].");
addFormNumericBox(string, F("Min. detection count"), F("plugin_045_threshold_counter"), Settings.TaskDevicePluginConfig[event->TaskIndex][5], 0, 999999);
addFormNumericBox(string, F("Detection window"), F("plugin_045_threshold_window"), Settings.TaskDevicePluginConfig[event->TaskIndex][6], 0, 999999);
string += F("<TR><TD>Min. detection count:<TD><input type='text' size='6' maxlength='6' name='plugin_118_threshold_counter' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][5];
string += F("'>");
string += F("<TR><TD>Detection window:<TD><input type='text' size='6' maxlength='6' name='plugin_118_threshold_window' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][6];
string += F("'>");
}
success = true;
break;
@@ -168,13 +192,20 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
// Save the vars
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_045_address"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_045_function"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_045_threshold_x"));
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("plugin_045_threshold_y"));
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = getFormItemInt(F("plugin_045_threshold_z"));
Settings.TaskDevicePluginConfig[event->TaskIndex][5] = getFormItemInt(F("plugin_045_threshold_counter"));
Settings.TaskDevicePluginConfig[event->TaskIndex][6] = getFormItemInt(F("plugin_045_threshold_window"));
String plugin1 = WebServer.arg("plugin_118_address");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_118_function");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_118_threshold_x");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_118_threshold_y");
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_118_threshold_z");
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_118_threshold_counter");
Settings.TaskDevicePluginConfig[event->TaskIndex][5] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_118_threshold_window");
Settings.TaskDevicePluginConfig[event->TaskIndex][6] = plugin1.toInt();
if (Settings.TaskDevicePluginConfig[event->TaskIndex][6] < Settings.TaskDevicePluginConfig[event->TaskIndex][5]) {
Settings.TaskDevicePluginConfig[event->TaskIndex][6] = Settings.TaskDevicePluginConfig[event->TaskIndex][5];
}
@@ -192,14 +223,14 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = devAddr;
}
// Initialize the MPU6050, for details look at the MPU6050 library: MPU6050::Initialize
_P045_writeBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, MPU6050_CLOCK_PLL_XGYRO);
_P045_writeBits(devAddr, MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, MPU6050_GYRO_FS_250);
_P045_writeBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, MPU6050_ACCEL_FS_2);
_P045_writeBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, 1, 0);
_P118_writeBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, MPU6050_CLOCK_PLL_XGYRO);
_P118_writeBits(devAddr, MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, MPU6050_GYRO_FS_250);
_P118_writeBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, MPU6050_ACCEL_FS_2);
_P118_writeBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, 1, 0);
// Read the MPU6050 once to clear out zeros (1st time reading MPU6050 returns all 0s)
int16_t ax, ay, az, gx, gy, gz;
_P045_getMotion6(devAddr, &ax, &ay, &az, &gx, &gy, &gz);
_P118_getMotion6(devAddr, &ax, &ay, &az, &gx, &gy, &gz);
// Reset vars
Settings.TaskDevicePluginConfig[event->TaskIndex][7] = 0; // Last known value of "switch" is off
@@ -216,38 +247,38 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
byte dev = devAddr & 1;
// Read the sensorvalues, we run this bit every 1/10th of a second
_P045_getMotion6(devAddr, &_P045_axis[0][3][dev], &_P045_axis[1][3][dev], &_P045_axis[2][3][dev], &_P045_axis[0][4][dev], &_P045_axis[1][4][dev], &_P045_axis[2][4][dev]);
_P118_getMotion6(devAddr, &_P118_axis[0][3][dev], &_P118_axis[1][3][dev], &_P118_axis[2][3][dev], &_P118_axis[0][4][dev], &_P118_axis[1][4][dev], &_P118_axis[2][4][dev]);
// Set the minimum and maximum value for each axis a-value, overwrite previous values if smaller/larger
_P045_trackMinMax(_P045_axis[0][3][dev], &_P045_axis[0][0][dev], &_P045_axis[0][1][dev]);
_P045_trackMinMax(_P045_axis[1][3][dev], &_P045_axis[1][0][dev], &_P045_axis[1][1][dev]);
_P045_trackMinMax(_P045_axis[2][3][dev], &_P045_axis[2][0][dev], &_P045_axis[2][1][dev]);
_P118_trackMinMax(_P118_axis[0][3][dev], &_P118_axis[0][0][dev], &_P118_axis[0][1][dev]);
_P118_trackMinMax(_P118_axis[1][3][dev], &_P118_axis[1][0][dev], &_P118_axis[1][1][dev]);
_P118_trackMinMax(_P118_axis[2][3][dev], &_P118_axis[2][0][dev], &_P118_axis[2][1][dev]);
// ^ current value @ 3 ^ min val @ 0 ^ max val @ 1
/* // Uncomment this block if you want to debug your MPU6050, but be prepared for a log overload
String log = F("MPU6050 : axis values: ");
log += _P045_axis[0][3][dev]
log += _P118_axis[0][3][dev]
log += F(", ");
log += _P045_axis[1][3][dev];
log += _P118_axis[1][3][dev];
log += F(", ");
log += _P045_axis[2][3][dev];
log += _P118_axis[2][3][dev];
log += F(", g values: ");
log += _P045_axis[0][4][dev];
log += _P118_axis[0][4][dev];
log += F(", ");
log += _P045_axis[1][4][dev];
log += _P118_axis[1][4][dev];
log += F(", ");
log += _P045_axis[2][4][dev];
log += _P118_axis[2][4][dev];
addLog(LOG_LEVEL_INFO,log);
*/
// Run this bit every 5 seconds per deviceaddress (not per instance)
if ((_P045_time[dev] + 5000) < millis())
if ((_P118_time[dev] + 5000) < millis())
{
_P045_time[dev] = millis();
_P118_time[dev] = millis();
// Determine the maximum measured range of each axis
for (uint8_t i=0; i<3; i++) {
_P045_axis[i][2][dev] = abs(_P045_axis[i][1][dev] - _P045_axis[i][0][dev]);
_P045_axis[i][0][dev] = _P045_axis[i][3][dev];
_P045_axis[i][1][dev] = _P045_axis[i][3][dev];
_P118_axis[i][2][dev] = abs(_P118_axis[i][1][dev] - _P118_axis[i][0][dev]);
_P118_axis[i][0][dev] = _P118_axis[i][3][dev];
_P118_axis[i][1][dev] = _P118_axis[i][3][dev];
}
}
success = true;
@@ -258,8 +289,8 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
{
int devAddr = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
byte dev = devAddr & 1;
int _P045_Function = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
switch (_P045_Function)
int _P118_Function = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
switch (_P118_Function)
{
// Function 0 is for movement detection
case 0:
@@ -271,7 +302,7 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
{
// for each axis:
if (Settings.TaskDevicePluginConfig[event->TaskIndex][i + 2] != 0) { // not disabled, check threshold
if (_P045_axis[i][2][dev] < Settings.TaskDevicePluginConfig[event->TaskIndex][i + 2]) { thresexceed = false; }
if (_P118_axis[i][2][dev] < Settings.TaskDevicePluginConfig[event->TaskIndex][i + 2]) { thresexceed = false; }
} else { count++; } // If disabled count + 1
}
if (count == 3) { thresexceed = false; } // If we counted to three, all three axis are disabled.
@@ -294,10 +325,10 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
// Check if UserVar changed so we do not overload homecontroller with the same readings
if (Settings.TaskDevicePluginConfigLong[event->TaskIndex][7] != UserVar[event->BaseVarIndex]) {
success = true; // Update switch status
Settings.TaskDevicePluginConfigLong[event->TaskIndex][7] = UserVar[event->BaseVarIndex];
success = true;
} else {
success = false;
success = false; // Do not update switch status
}
Settings.TaskDevicePluginConfigLong[event->TaskIndex][0] = 0; // reset threshold exceeded counter
}
@@ -309,9 +340,9 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
// All other functions are reading values. So extract xyz value and wanted type from function number:
default: // [1-3]: range-values, [4-6]: a-values, [7-9]: g-values
{
uint8_t reqaxis = (_P045_Function - 1) % 3; // xyz -> eg: function 5(ay) (5-1) % 3 = 1 (y)
uint8_t reqvar = ((_P045_Function - 1) / 3) + 2; // range, a, g -> eg: function 9(gz) ((9-1) / 3 = 2) + 2 = 4 (g)
UserVar[event->BaseVarIndex] = float(_P045_axis[reqaxis][reqvar][dev]);
uint8_t reqaxis = (_P118_Function - 1) % 3; // xyz -> eg: function 5(ay) (5-1) % 3 = 1 (y)
uint8_t reqvar = ((_P118_Function - 1) / 3) + 2; // range, a, g -> eg: function 9(gz) ((9-1) / 3 = 2) + 2 = 4 (g)
UserVar[event->BaseVarIndex] = float(_P118_axis[reqaxis][reqvar][dev]);
success = true;
break;
}
@@ -322,7 +353,7 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
return success;
}
void _P045_trackMinMax(int16_t current, int16_t *min, int16_t *max)
void _P118_trackMinMax(int16_t current, int16_t *min, int16_t *max)
// From nodemcu-laundry.ino by Nolan Gilley
{
if (current > *max)
@@ -346,7 +377,7 @@ void _P045_trackMinMax(int16_t current, int16_t *min, int16_t *max)
* @param gy 16-bit signed integer container for gyroscope Y-axis value
* @param gz 16-bit signed integer container for gyroscope Z-axis value
*/
void _P045_getMotion6(uint8_t devAddr, int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz) {
void _P118_getMotion6(uint8_t devAddr, int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz) {
// From I2Cdev::readBytes and MPU6050::getMotion6, both by Jeff Rowberg
uint8_t buffer[14];
uint8_t count = 0;
@@ -373,7 +404,7 @@ void _P045_getMotion6(uint8_t devAddr, int16_t* ax, int16_t* ay, int16_t* az, in
* @param length Number of bits to write (not more than 8)
* @param data Right-aligned value to write
*/
void _P045_writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
void _P118_writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
// From I2Cdev::writeBits by Jeff Rowberg
// 010 value to write
// 76543210 bit numbers
@@ -1,8 +1,8 @@
//#######################################################################################################
//######################## Plugin 039: Thermocouple (MAX6675 / MAX31855) ################################
//#######################################################################################################
#ifdef PLUGIN_BUILD_DEV
// Original work by Dominik
//#######################################################################################################
//######################## Plugin 120: Thermocouple (MAX6675 / MAX31855) ################################
//#######################################################################################################
// Plugin Description
// This Plugin reads the data from Thermocouples. You have to use an Adapter Board with a
@@ -35,16 +35,17 @@
#include <SPI.h>
#define PLUGIN_039
#define PLUGIN_ID_039 39
#define PLUGIN_NAME_039 "Temperature - Thermocouple"
#define PLUGIN_VALUENAME1_039 "Temperature"
#define PLUGIN_120
#define PLUGIN_ID_120 120
#define PLUGIN_NAME_120 "Temperature Thermocouple [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_120 "Temperature C"
#define PLUGIN_VALUENAME2_120 "Temperature K"
uint8_t Plugin_039_SPI_CS_Pin = 15; // D8
bool Plugin_039_SensorAttached = true;
double Plugin_039_Celsius = 0.0;
uint8_t Plugin_120_SPI_CS_Pin = 15; // D8
bool Plugin_120_SensorAttached = true;
double Plugin_120_Celsius = 0.0;
boolean Plugin_039(byte function, struct EventStruct *event, String& string)
boolean Plugin_120(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -52,14 +53,14 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_039;
Device[++deviceCount].Number = PLUGIN_ID_120;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_DUAL; // 2 Messwerte
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 1;
Device[deviceCount].ValueCount = 2;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
@@ -68,13 +69,14 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_039);
string = F(PLUGIN_NAME_120);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_039));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_120));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_120));
break;
}
@@ -85,16 +87,16 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
if (Settings.TaskDevicePin1[event->TaskIndex] != 0)
{
// Konvert the GPIO Pin to a Dogotal Puin Number first ...
Plugin_039_SPI_CS_Pin = Settings.TaskDevicePin1[event->TaskIndex];
Plugin_120_SPI_CS_Pin = Settings.TaskDevicePin1[event->TaskIndex];
}
// set the slaveSelectPin as an output:
pinMode(Plugin_039_SPI_CS_Pin, OUTPUT);
pinMode(Plugin_120_SPI_CS_Pin, OUTPUT);
// initialize SPI:
SPI.setHwCs(false);
SPI.begin();
addLog(LOG_LEVEL_INFO, F("P039 : SPI Init"));
addLog(LOG_LEVEL_INFO, (char*)"P120 : SPI Init");
success = true;
break;
@@ -102,16 +104,30 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNote(string, F("<b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)"));
//string += F("<TR><TD>Info GPIO:<TD><b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)");
string += F("<TR><TD>Info GPIO:<TD><b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)");
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2];
options[0] = F("MAX 6675");
options[1] = F("MAX 31855");
//options[2] = F("MAX 31865");
int optionValues[2] = { 1, 2 };
addFormSelector(string, F("Adapter IC"), F("plugin_039_maxtype"), 2, options, optionValues, choice);
int optionValues[2];
optionValues[0] = 1;
optionValues[1] = 2;
//optionValues[2] = 3;
string += F("<TR><TD>Adapter IC:<TD><select name='plugin_120_maxtype'>");
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;
@@ -119,7 +135,8 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_039_maxtype"));
String plugin1 = WebServer.arg("plugin_120_maxtype");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
}
@@ -132,25 +149,28 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
// Get CS Pin
// Konvert the GPIO Pin to a Dogotal Puin Number first ...
Plugin_039_SPI_CS_Pin = Settings.TaskDevicePin1[event->TaskIndex];
Plugin_120_SPI_CS_Pin = Settings.TaskDevicePin1[event->TaskIndex];
switch (MaxType) {
case 1: // MAX6675
Plugin_039_Celsius = readMax6675();
Plugin_120_Celsius = readMax6675();
break;
case 2: // MAX31855
Plugin_039_Celsius = readMax31855();
Plugin_120_Celsius = readMax31855();
break;
case 3: // MAX31865 (not implemented yet)
//do something when var equals 2
break;
}
if (Plugin_039_Celsius != NAN)
if (Plugin_120_Celsius != NAN)
{
UserVar[event->BaseVarIndex] = Plugin_039_Celsius;
String log = F("P039 : Temperature ");
UserVar[event->BaseVarIndex] = Plugin_120_Celsius;
UserVar[event->BaseVarIndex + 1] = CelsiusToFahrenheit(Plugin_120_Celsius);
String log = F("P120 : C : ");
log += UserVar[event->BaseVarIndex];
log += F(" - F : ");
log += UserVar[event->BaseVarIndex + 1];
addLog(LOG_LEVEL_INFO, log);
success = true;
}
@@ -158,7 +178,8 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
{
UserVar[event->BaseVarIndex] = NAN;
UserVar[event->BaseVarIndex + 1] = NAN;
addLog(LOG_LEVEL_INFO, F("P039 : No Sensor attached !"));
String log = F("P120 : No Sensor attached !");
addLog(LOG_LEVEL_INFO, log);
success = false;
}
@@ -172,16 +193,16 @@ double readMax6675()
{
uint16_t rawvalue = 0;
// take the SS pin low to select the chip:
digitalWrite(Plugin_039_SPI_CS_Pin, LOW);
// String log = F("P039 : CS Pin : ");
// log += Plugin_039_SPI_CS_Pin;
digitalWrite(Plugin_120_SPI_CS_Pin, LOW);
// String log = F("P120 : CS Pin : ");
// log += Plugin_120_SPI_CS_Pin;
// addLog(LOG_LEVEL_INFO, log);
// "transfer" 0x0 and read the Data from the Chip
rawvalue = SPI.transfer16(0x0);
// take the SS pin high to de-select the chip:
digitalWrite(Plugin_039_SPI_CS_Pin, HIGH);
digitalWrite(Plugin_120_SPI_CS_Pin, HIGH);
String log = F("P039 : MAX6675 : RAW - BIN:");
String log = F("P120 : MAX6675 : RAW - BIN:");
log += String(rawvalue, BIN);
log += " HEX:";
log += String(rawvalue, HEX);
@@ -193,9 +214,9 @@ double readMax6675()
// Bit D2 is normally low and goes high if the thermocouple input is open. In order to allow the operation of the
// open thermocouple detector, T- must be grounded. Make the ground connection as close to the GND pin
// as possible.
Plugin_039_SensorAttached = !(rawvalue & 0x0004);
Plugin_120_SensorAttached = !(rawvalue & 0x0004);
if (Plugin_039_SensorAttached)
if (Plugin_120_SensorAttached)
{
// Shift RAW value 3 Bits to the right to get the data
rawvalue >>= 3;
@@ -213,7 +234,7 @@ double readMax31855()
{
uint32_t rawvalue = 0;
// take the SS pin low to select the chip:
digitalWrite(Plugin_039_SPI_CS_Pin, LOW);
digitalWrite(Plugin_120_SPI_CS_Pin, LOW);
// "transfer" 0x0 and read the MSB Data from the Chip
rawvalue = SPI.transfer16(0x0);
// Shift MSB 16 Bits to the left
@@ -221,9 +242,9 @@ double readMax31855()
// "transfer" 0x0 and read the LSB Data from the Chip
rawvalue |= SPI.transfer16(0x0);
// take the SS pin high to de-select the chip:
digitalWrite(Plugin_039_SPI_CS_Pin, HIGH);
digitalWrite(Plugin_120_SPI_CS_Pin, HIGH);
String log = F("P039 : MAX31855 : RAW - BIN:");
String log = F("P120 : MAX31855 : RAW - BIN:");
log += String(rawvalue, BIN);
log += " HEX:";
log += String(rawvalue, HEX);
@@ -232,9 +253,9 @@ double readMax31855()
addLog(LOG_LEVEL_DEBUG, log);
// D16 - This bit reads at 1 when any of the SCV, SCG, or OC faults are active. Default value is 0.
Plugin_039_SensorAttached = !(rawvalue & 0x00010000);
Plugin_120_SensorAttached = !(rawvalue & 0x00010000);
if (Plugin_039_SensorAttached)
if (Plugin_120_SensorAttached)
{
// Data is D[31:18]
// Shift RAW value 18 Bits to the right to get the data
@@ -262,3 +283,10 @@ double readMax31855()
return NAN;
}
}
// Convert Celsius to Fahrenheit
double CelsiusToFahrenheit(double celsius) {
return celsius * 9.0 / 5.0 + 32;
}
#endif
+111
View File
@@ -0,0 +1,111 @@
#ifdef PLUGIN_BUILD_DEV
/*
This plug in is written by Dmitry (rel22 ___ inbox.ru)
Plugin is based upon SenseAir plugin by Daniel Tedenljung info__AT__tedenljungconsulting.com
This plugin reads the CO2 value from MH-Z19 NDIR Sensor
DevicePin1 - is RX for ESP
DevicePin2 - is TX for ESP
*/
#define PLUGIN_149
#define PLUGIN_ID_149 149
#define PLUGIN_NAME_149 "NDIR CO2 Sensor MH-Z19 [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_149 "PPM"
boolean Plugin_149_init = false;
#include <SoftwareSerial.h>
SoftwareSerial *Plugin_149_S8;
// 9-bytes CMD PPM read command
byte mhzCmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
byte mhzResp[9]; // 9 bytes bytes response
boolean Plugin_149(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_149;
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
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_149);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_149));
break;
}
case PLUGIN_INIT:
{
Plugin_149_init = true;
Plugin_149_S8 = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
success = true;
break;
}
case PLUGIN_READ:
{
if (Plugin_149_init)
{
Plugin_149_S8->write(mhzCmd, 9);
memset(mhzResp, 0, 9);
Plugin_149_S8->readBytes(mhzResp, 9);
int i;
unsigned int ppm = 0;
byte crc = 0;
for (i = 1; i < 8; i++) crc+=mhzResp[i];
crc = 255 - crc;
crc++;
if ( !(mhzResp[0] == 0xFF && mhzResp[1] == 0x86 && mhzResp[8] == crc) ) {
String log = F("MHZ19: CRC error: ");
log += String(crc); log += " / "; log += String(mhzResp[8]);
addLog(LOG_LEVEL_ERROR, log);
success = false;
break;
} else {
unsigned int mhzRespHigh = (unsigned int) mhzResp[2];
unsigned int mhzRespLow = (unsigned int) mhzResp[3];
ppm = (256*mhzRespHigh) + mhzRespLow;
}
UserVar[event->BaseVarIndex] = (float)ppm;
String log = F("MHZ19: PPM value: ");
log += ppm;
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
break;
}
}
return success;
}
#endif
+168 -142
View File
@@ -1,5 +1,5 @@
//#######################################################################################################
//#################################### Plugin 046: Ventus W266 [Testing] ################################
//#################################### Plugin 186: Ventus W266 [Testing] ################################
//#######################################################################################################
// Purpose: Sniff the data received by the Ventus W266 display unit and send it to Domoticz
@@ -32,7 +32,6 @@
// The plugin uses two buffers, ine for the ISR routines and one for the other plugin instances.
// This plugin was originally released into th eplayground as Plugin 186, it is assimilated into the core as 046.
// Why plugin nr 186? Well 266 is not possible, 206 (id on the back of the unit) is nit within the
// playground range and the W186 is an additinal external thermometer for the Ventus W266.
// The Ventus W266 is also known as the Renkforce W205GU.
@@ -59,6 +58,7 @@
// ld=lightningstorm-distance (km, 3F is max) > The distance to the stormfront in km
// lllh=strikecount-low/high (#) > A 16 bit integer holding the number of detected lightning strikes, low byte first
// crc > poly 0x31, init 0xff, revin&revout, xorout 0x00. Like Maxim 1-wire but with a 0xff initvalue. Crc is calculated over bytes 1-22
//
// Events:
// None
@@ -67,56 +67,57 @@
// None
// Current state / limitations:
// 1.0 Initial release. All values are always visible although sometimes only one is really used with domoticz.
// 1.0 Initial release. All values are always visible although sometimes
// only one is really used with domoticz.
// Needs work on a sliding window for the lightning detection.
// When porting be beware of the fact that the esp8266 uses 4 bytes as an int when reading the temperature.
//
// Exploits the fact that event->sensorType is not reset after PLUGIN_READ.
// This plugin is based on the work of the Plugin 199: RF KaKu receiver/sender and Plugin 026: Analog.
// CRC calculation is based on the works by Paul Stoffregen from the 1-Wire arduino library. Special
// thanks to Greg Cook and the team behind reveng.sourceforge.net.
#ifdef PLUGIN_BUILD_TESTING
#define PLUGIN_046_DEBUG true // Shows recieved frames and crc in log@INFO
#define PLUGIN_186_DEBUG true // Shows recieved frames and crc in log@INFO
#define PLUGIN_046 // Mandatory framework constants
#define PLUGIN_ID_046 46
#define PLUGIN_NAME_046 "Ventus W266 [TESTING]"
#define PLUGIN_VALUENAME1_046 ""
#define PLUGIN_VALUENAME2_046 ""
#define PLUGIN_VALUENAME3_046 ""
#define PLUGIN_186 // Mandatory framework constants
#define PLUGIN_ID_186 186
#define PLUGIN_NAME_186 "Ventus W266 [TESTING]"
#define PLUGIN_VALUENAME1_186 ""
#define PLUGIN_VALUENAME2_186 ""
#define PLUGIN_VALUENAME3_186 ""
#define Plugin_046_MagicByte 0x7F // When we read this byte on MOSI, switch to MISO
#define Plugin_046_RAW_BUFFER_SIZE 24 // Payload is 23 bytes, added space for header
#define Plugin_046_Payload 23
#define Plugin_186_MagicByte 0x7F // When we read this byte on MOSI, switch to MISO
#define Plugin_186_RAW_BUFFER_SIZE 24 // Payload is 23 bytes, added space for header
#define Plugin_186_Payload 23
int8_t Plugin_046_MOSIpin = -1; // GPIO pins
int8_t Plugin_046_SCLKpin = -1;
int8_t Plugin_046_nSELpin = -1;
int8_t Plugin_046_MISOpin = -1;
int8_t Plugin_186_MOSIpin = -1; // GPIO pins
int8_t Plugin_186_SCLKpin = -1;
int8_t Plugin_186_nSELpin = -1;
int8_t Plugin_186_MISOpin = -1;
// Vars used in data collection:
byte Plugin_046_ISR_Buffer[Plugin_046_RAW_BUFFER_SIZE]; // Buffer used in ISR routine
//Test data: volatile byte Plugin_046_databuffer[] = {0x7F, 0x98, 0x33, 0x1A, 0xB0, 0x00, 0x00, 0xB0, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3F, 0x8A, 0x25, 0x00, 0x49, 0x00}; // Buffer used by other instances
byte Plugin_046_databuffer[Plugin_046_RAW_BUFFER_SIZE]; // Buffer used by other instances
boolean Plugin_046_RecieveActive = false; // Active session in progress
boolean Plugin_046_MasterSlave = false; // Which pin o read? false=MOSI, true=MISO
boolean Plugin_046_newData = false; // "Valid" data ready, please process
byte Plugin_046_bitpointer; // Pointer for recieved bit
byte Plugin_046_bytepointer; // Pointe for ISR recieve buffer
byte Plugin_046_recievedData; // Byte to store recieved bits
byte Plugin_186_ISR_Buffer[Plugin_186_RAW_BUFFER_SIZE]; // Buffer used in ISR routine
//Test data: volatile byte Plugin_186_databuffer[] = {0x7F, 0x98, 0x33, 0x1A, 0xB0, 0x00, 0x00, 0xB0, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3F, 0x8A, 0x25, 0x00, 0x49, 0x00}; // Buffer used by other instances
byte Plugin_186_databuffer[Plugin_186_RAW_BUFFER_SIZE]; // Buffer used by other instances
boolean Plugin_186_RecieveActive = false; // Active session in progress
boolean Plugin_186_MasterSlave = false; // Which pin o read? false=MOSI, true=MISO
boolean Plugin_186_newData = false; // "Valid" data ready, please process
byte Plugin_186_bitpointer; // Pointer for recieved bit
byte Plugin_186_bytepointer; // Pointe for ISR recieve buffer
byte Plugin_186_recievedData; // Byte to store recieved bits
// Vars used for interpreting the data:
volatile unsigned long Plugin_046_lastrainctr; // Keep track of wdcounter (1/2 min tick)
volatile int Plugin_046_lastraincount; // Last rain count
volatile float Plugin_046_rainmmph = 0;
volatile unsigned long Plugin_046_laststrikectr; // Keep track of wdcounter (1/2 min tick)
volatile unsigned int Plugin_046_laststrikecount; // Last number of strikes
volatile int Plugin_046_strikesph = 0;
volatile unsigned long Plugin_186_lastrainctr; // Keep track of wdcounter (1/2 min tick)
volatile int Plugin_186_lastraincount; // Last rain count
volatile float Plugin_186_rainmmph = 0;
volatile unsigned long Plugin_186_laststrikectr; // Keep track of wdcounter (1/2 min tick)
volatile unsigned int Plugin_186_laststrikecount; // Last number of strikes
volatile int Plugin_186_strikesph = 0;
void Plugin_046_ISR_nSEL() ICACHE_RAM_ATTR; // Interrupt routines
void Plugin_046_ISR_SCLK() ICACHE_RAM_ATTR;
void Plugin_186_ISR_nSEL() ICACHE_RAM_ATTR; // Interrupt routines
void Plugin_186_ISR_SCLK() ICACHE_RAM_ATTR;
boolean Plugin_046(byte function, struct EventStruct *event, String& string)
boolean Plugin_186(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -124,7 +125,7 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_046;
Device[++deviceCount].Number = PLUGIN_ID_186;
Device[deviceCount].Type = DEVICE_TYPE_DUMMY; // Nothing else really fit the bill ...
Device[deviceCount].VType = SENSOR_TYPE_DUAL; // New type, see ESPEasy.ino
Device[deviceCount].Ports = 0;
@@ -152,8 +153,22 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
options[7] = F("Unknown 2, byte 16");
options[8] = F("Unknown 3, byte 19");
addFormSelector(string, F("Plugin function"), F("plugin_046"), nrchoices, options, NULL, choice);
int optionValues[nrchoices];
for (byte x = 0; x < nrchoices; x++) {
optionValues[x] = x;
}
string += F("<TR><TD>Plugin function:<TD><select name='plugin_186'>");
for (byte x = 0; x < nrchoices; 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>");
if (choice==0) {
string += F("<TR><TD>1st GPIO (5-MOSI):<TD>");
addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
@@ -230,12 +245,17 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_046"));
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 0) {
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("taskdevicepin1"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("taskdevicepin2"));
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("taskdevicepin3"));
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = getFormItemInt(F("taskdeviceport"));
String plugin1 = WebServer.arg("plugin_186");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
if (plugin1.toInt()==0) {
String plugin2 = WebServer.arg("taskdevicepin1");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
String plugin3 = WebServer.arg("taskdevicepin2");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
String plugin4 = WebServer.arg("taskdevicepin3");
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = plugin4.toInt();
String plugin5 = WebServer.arg("taskdeviceport");
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = plugin5.toInt();
}
success = true;
break;
@@ -243,15 +263,15 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_046);
string = F(PLUGIN_NAME_186);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_046));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_046));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_046));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_186));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_186));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_186));
break;
}
@@ -262,23 +282,23 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
{
case (0):
{
Plugin_046_MOSIpin = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
Plugin_046_SCLKpin = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
Plugin_046_nSELpin = Settings.TaskDevicePluginConfig[event->TaskIndex][3];
Plugin_046_MISOpin = Settings.TaskDevicePluginConfig[event->TaskIndex][4];
int8_t total = Plugin_046_MOSIpin + Plugin_046_SCLKpin + Plugin_046_nSELpin + Plugin_046_MISOpin;
Plugin_186_MOSIpin = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
Plugin_186_SCLKpin = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
Plugin_186_nSELpin = Settings.TaskDevicePluginConfig[event->TaskIndex][3];
Plugin_186_MISOpin = Settings.TaskDevicePluginConfig[event->TaskIndex][4];
int8_t total = Plugin_186_MOSIpin + Plugin_186_SCLKpin + Plugin_186_nSELpin + Plugin_186_MISOpin;
if (total > 6) { // All pins configured?
pinMode(Plugin_046_MOSIpin, INPUT);
pinMode(Plugin_046_SCLKpin, INPUT);
pinMode(Plugin_046_nSELpin, INPUT);
pinMode(Plugin_046_MISOpin, INPUT);
Plugin_046_databuffer[0] = 0; // buffer is "empty"
Plugin_046_lastrainctr = 0;
Plugin_046_lastraincount = -1;
Plugin_046_laststrikectr = 0;
Plugin_046_laststrikecount = -1;
attachInterrupt(Plugin_046_SCLKpin, Plugin_046_ISR_SCLK, RISING);
attachInterrupt(Plugin_046_nSELpin, Plugin_046_ISR_nSEL, CHANGE);
pinMode(Plugin_186_MOSIpin, INPUT);
pinMode(Plugin_186_SCLKpin, INPUT);
pinMode(Plugin_186_nSELpin, INPUT);
pinMode(Plugin_186_MISOpin, INPUT);
Plugin_186_databuffer[0] = 0; // buffer is "empty"
Plugin_186_lastrainctr = 0;
Plugin_186_lastraincount = -1;
Plugin_186_laststrikectr = 0;
Plugin_186_laststrikecount = -1;
attachInterrupt(Plugin_186_SCLKpin, Plugin_186_ISR_SCLK, RISING);
attachInterrupt(Plugin_186_nSELpin, Plugin_186_ISR_nSEL, CHANGE);
}
break;
}
@@ -289,14 +309,14 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
case PLUGIN_TEN_PER_SECOND:
{
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 0) {
if (Plugin_046_newData) {
if (Plugin_186_newData) {
uint8_t crc = 0xff; // init = 0xff
char data; // CRC = MAXIM with modified init: poly 0x31, init 0xff, refin 1; refout 1, xorout 0x00
// Copy recieved data to buffer and check CRC
Plugin_046_databuffer[0] = Plugin_046_ISR_Buffer[0];
for (int i = 1; i < Plugin_046_bytepointer; i++) {
data = Plugin_046_ISR_Buffer[i];
Plugin_046_databuffer[i] = data;
Plugin_186_databuffer[0] = Plugin_186_ISR_Buffer[0];
for (int i = 1; i < Plugin_186_bytepointer; i++) {
data = Plugin_186_ISR_Buffer[i];
Plugin_186_databuffer[i] = data;
for (int j = 0; j < 8; j++) // crc routine from Jim Studt
{ // Onewire library
uint8_t mix = (crc ^ data) & 0x01;
@@ -305,24 +325,30 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
data >>= 1;
}
}
Plugin_046_MasterSlave = false;
Plugin_046_newData = false;
if (PLUGIN_046_DEBUG) {
String log = F("Ventus W266 Rcvd(");
log += getTimeString(':');
log += F(") ");
for (int i = 0; i < Plugin_046_Payload; i++) {
Plugin_186_MasterSlave = false;
Plugin_186_newData = false;
if (PLUGIN_186_DEBUG) {
String log = "Ventus W266 Rcvd(";
log += hour();
log += ":";
if (minute() < 10) { log += "0"; }
log += minute();
log += ":";
if (tm.Second < 10) { log += "0"; }
log += tm.Second;
log += ") ";
for (int i = 0; i < Plugin_186_Payload; i++) {
if ((i==2)||(i==3)||(i==4)||(i==9)||(i==10)||(i==14)||(i==17)||(i==18)||(i==20)) {
log += F(":");
log += ":";
}
char myHex = (Plugin_046_databuffer[i] >> 4) + 0x30;
char myHex = (Plugin_186_databuffer[i] >> 4) + 0x30;
if (myHex > 0x39) { myHex += 7; }
log += myHex;
myHex = (Plugin_046_databuffer[i] & 0x0f) + 0x30;
myHex = (Plugin_186_databuffer[i] & 0x0f) + 0x30;
if (myHex > 0x39) { myHex += 7; }
log += myHex;
}
log += F(" > ");
log += " > ";
char myHex = (crc >> 4) + 0x30;
if (myHex > 0x39) { myHex += 7; }
log += myHex;
@@ -333,7 +359,7 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
}
if (crc != 00)
{
Plugin_046_databuffer[0] = 0; // Not MagicByte, so not valid.
Plugin_186_databuffer[0] = 0; // Not MagicByte, so not valid.
}
}
}
@@ -343,7 +369,7 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
case PLUGIN_READ:
{
if (Plugin_046_databuffer[0] == Plugin_046_MagicByte) // buffer[0] should be the MagicByte if valid
if (Plugin_186_databuffer[0] == Plugin_186_MagicByte) // buffer[0] should be the MagicByte if valid
{
UserVar[event->BaseVarIndex + 1] = 0;
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; // Which instance?
@@ -351,10 +377,10 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
{
case (0):
{
int myTemp = int((Plugin_046_databuffer[5] * 256) + Plugin_046_databuffer[4]);
int myTemp = int((Plugin_186_databuffer[5] * 256) + Plugin_186_databuffer[4]);
if (myTemp > 0x8000) { myTemp |= 0xffff0000; } // int @ esp8266 = 32 bits!
float temperature = float(myTemp) / 10.0; // Temperature
byte myHum = (Plugin_046_databuffer[2] >> 4) * 10 + (Plugin_046_databuffer[2] & 0x0f);
byte myHum = (Plugin_186_databuffer[2] >> 4) * 10 + (Plugin_186_databuffer[2] & 0x0f);
float humidity = float(myHum);
UserVar[event->BaseVarIndex] = temperature;
UserVar[event->BaseVarIndex + 1] = humidity;
@@ -363,10 +389,10 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
}
case (1):
{
float average = float((Plugin_046_databuffer[11] << 8) + Plugin_046_databuffer[10]) / 10; // Wind speed average in m/s
float gust = float((Plugin_046_databuffer[13] << 8) + Plugin_046_databuffer[12]) / 10; // Wind speed gust in m/s
float bearing = float(Plugin_046_databuffer[9] & 0x0f) * 22.5; // Wind bearing (0-359)
UserVar[event->BaseVarIndex] = bearing; // degrees
float average = float((Plugin_186_databuffer[11]) * 256 + Plugin_186_databuffer[10]); // Wind speed average in 10 * m/s
float gust = float((Plugin_186_databuffer[13]) * 256 + Plugin_186_databuffer[12]); // Wind speed gust in 10 * m/s
float bearing = float(Plugin_186_databuffer[9] & 0x0f) * 22.5; // Wind bearing (0-359)
UserVar[event->BaseVarIndex] = bearing; // degrees
UserVar[event->BaseVarIndex + 1] = average;
UserVar[event->BaseVarIndex + 2] = gust;
event->sensorType = SENSOR_TYPE_WIND;
@@ -374,78 +400,78 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
}
case (2):
{
float raincnt = float(((Plugin_046_databuffer[15]) * 256 + Plugin_046_databuffer[14]) / 4);
float raincnt = float(((Plugin_186_databuffer[15]) * 256 + Plugin_186_databuffer[14]) / 4);
int rainnow = int(raincnt);
if (wdcounter < Plugin_046_lastrainctr) { Plugin_046_lastrainctr = wdcounter; }
if (Plugin_046_lastrainctr > (wdcounter + 10)) // 5 min interval
if (wdcounter < Plugin_186_lastrainctr) { Plugin_186_lastrainctr = wdcounter; }
if (Plugin_186_lastrainctr > (wdcounter + 10)) // 5 min interval
{
Plugin_046_lastrainctr = wdcounter;
if (rainnow > Plugin_046_lastraincount)
Plugin_186_lastrainctr = wdcounter;
if (rainnow > Plugin_186_lastraincount)
{ // per 5 min * 12 = per hour
Plugin_046_rainmmph = float(rainnow - Plugin_046_lastraincount) * 12;
Plugin_046_lastraincount = rainnow;
Plugin_186_rainmmph = float(rainnow - Plugin_186_lastraincount) * 12;
Plugin_186_lastraincount = rainnow;
} else {
Plugin_046_rainmmph = 0;
Plugin_186_rainmmph = 0;
}
}
UserVar[event->BaseVarIndex] = Plugin_046_rainmmph;
UserVar[event->BaseVarIndex] = Plugin_186_rainmmph;
UserVar[event->BaseVarIndex + 1] = raincnt;
break;
}
case (3):
{
float uvindex = float((Plugin_046_databuffer[17]) / 10);
float uvindex = float((Plugin_186_databuffer[17]) / 10);
UserVar[event->BaseVarIndex] = uvindex;
break;
}
case (4):
{
int strikes = 0;
int strikesnow = int((Plugin_046_databuffer[21]) * 256 + Plugin_046_databuffer[20]);
if (wdcounter < Plugin_046_laststrikectr) { Plugin_046_laststrikectr = wdcounter; }
if (Plugin_046_laststrikectr > (wdcounter + 10)) // 5 min interval
int strikesnow = int((Plugin_186_databuffer[21]) * 256 + Plugin_186_databuffer[20]);
if (wdcounter < Plugin_186_laststrikectr) { Plugin_186_laststrikectr = wdcounter; }
if (Plugin_186_laststrikectr > (wdcounter + 10)) // 5 min interval
{
Plugin_046_laststrikectr = wdcounter;
if (strikesnow > Plugin_046_laststrikecount)
Plugin_186_laststrikectr = wdcounter;
if (strikesnow > Plugin_186_laststrikecount)
{
Plugin_046_strikesph = strikesnow - Plugin_046_laststrikecount;
Plugin_046_laststrikecount = strikesnow;
Plugin_186_strikesph = strikesnow - Plugin_186_laststrikecount;
Plugin_186_laststrikecount = strikesnow;
} else {
Plugin_046_strikesph = 0;
Plugin_186_strikesph = 0;
}
}
UserVar[event->BaseVarIndex] = float(Plugin_046_strikesph);
UserVar[event->BaseVarIndex] = float(Plugin_186_strikesph);
break;
}
case (5):
{
float distance = float(-1);
if (Plugin_046_databuffer[18] != 0x3F )
if (Plugin_186_databuffer[18] != 0x3F )
{
distance = float(Plugin_046_databuffer[18]);
distance = float(Plugin_186_databuffer[18]);
}
UserVar[event->BaseVarIndex] = distance;
break;
}
case (6):
{
UserVar[event->BaseVarIndex] = float(Plugin_046_databuffer[6]);
UserVar[event->BaseVarIndex] = float(Plugin_186_databuffer[6]);
break;
}
case (7):
{
UserVar[event->BaseVarIndex] = float(Plugin_046_databuffer[16]);
UserVar[event->BaseVarIndex] = float(Plugin_186_databuffer[16]);
break;
}
case (8):
{
UserVar[event->BaseVarIndex] = float(Plugin_046_databuffer[19]);
UserVar[event->BaseVarIndex] = float(Plugin_186_databuffer[19]);
break;
}
} // switch
success = true;
} else {
success = false; // No data received yet or incorrect CRC so do not publish any data
success = false;
}
break;
} // case READ
@@ -453,47 +479,47 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
return success;
}
void Plugin_046_ISR_nSEL() // Interrupt on nSEL change
void Plugin_186_ISR_nSEL() // Interrupt on nSEL change
{
if (digitalRead(Plugin_046_nSELpin)) {
Plugin_046_RecieveActive = false; // nSEL high? Recieve done.
if (Plugin_046_MasterSlave) { // If MISO not active, no data recieved
if (Plugin_046_bytepointer == Plugin_046_Payload) { // If not 23 then bad datapacket
Plugin_046_newData = true; // We have new data!
if (digitalRead(Plugin_186_nSELpin)) {
Plugin_186_RecieveActive = false; // nSEL high? Recieve done.
if (Plugin_186_MasterSlave) { // If MISO not active, no data recieved
if (Plugin_186_bytepointer == Plugin_186_Payload) { // If not 23 then bad datapacket
Plugin_186_newData = true; // We have new data!
}
}
} else { // nSEL low? Start recieve
if (!Plugin_046_newData) { // Only accept new data if the old is processed
Plugin_046_bitpointer = 7; // reset pointer (MSB first)
Plugin_046_bytepointer = 0; // reset pointers & flags
Plugin_046_MasterSlave = false;
Plugin_046_RecieveActive = true; // We are now recieving data
if (!Plugin_186_newData) { // Only accept new data if the old is processed
Plugin_186_bitpointer = 7; // reset pointer (MSB first)
Plugin_186_bytepointer = 0; // reset pointers & flags
Plugin_186_MasterSlave = false;
Plugin_186_RecieveActive = true; // We are now recieving data
}
}
}
void Plugin_046_ISR_SCLK() // Interrupt on SCLK rising
void Plugin_186_ISR_SCLK() // Interrupt on SCLK rising
{
if (Plugin_046_RecieveActive) { // Are we recieving or glitch?
if (Plugin_046_MasterSlave) { // Read MISO or MOSI?
bitWrite(Plugin_046_recievedData, Plugin_046_bitpointer, digitalRead(Plugin_046_MISOpin));
if (Plugin_186_RecieveActive) { // Are we recieving or glitch?
if (Plugin_186_MasterSlave) { // Read MISO or MOSI?
bitWrite(Plugin_186_recievedData, Plugin_186_bitpointer, digitalRead(Plugin_186_MISOpin));
} else {
bitWrite(Plugin_046_recievedData, Plugin_046_bitpointer, digitalRead(Plugin_046_MOSIpin));
bitWrite(Plugin_186_recievedData, Plugin_186_bitpointer, digitalRead(Plugin_186_MOSIpin));
}
if (Plugin_046_bitpointer == 0) { // 8 bits done?
Plugin_046_bitpointer = 7;
if (Plugin_046_recievedData==Plugin_046_MagicByte) { // Switch data pins?
Plugin_046_MasterSlave = true;
if (Plugin_186_bitpointer == 0) { // 8 bits done?
Plugin_186_bitpointer = 7;
if (Plugin_186_recievedData==Plugin_186_MagicByte) { // Switch data pins?
Plugin_186_MasterSlave = true;
}
Plugin_046_ISR_Buffer[Plugin_046_bytepointer] = Plugin_046_recievedData;
Plugin_046_bytepointer++; // TReady for the next byte ...
if (Plugin_046_bytepointer > Plugin_046_RAW_BUFFER_SIZE) {
Plugin_046_RecieveActive = false; // We don't want a bufferoverflow, so abort
Plugin_046_MasterSlave = false;
Plugin_186_ISR_Buffer[Plugin_186_bytepointer] = Plugin_186_recievedData;
Plugin_186_bytepointer++; // TReady for the next byte ...
if (Plugin_186_bytepointer > Plugin_186_RAW_BUFFER_SIZE) {
Plugin_186_RecieveActive = false; // We don't want a bufferoverflow, so abort
Plugin_186_MasterSlave = false;
}
} else {
Plugin_046_bitpointer--; // Not yet done with all bits ...
Plugin_186_bitpointer--; // Not yet done with all bits ...
}
}
}
#endif
#endif
+584
View File
@@ -0,0 +1,584 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 199: RF KaKu receiver/sender ##############################
//#######################################################################################################
// Purpose: Control Klik-Aan-Klik-Uit RF 433MHz devices directly from ESP Easy (receive and send)
// Status : "Proof of concept"
// Connect the RF Receiver data pin to the first pin selected in the webgui
// Connect the RF Transmitter data pin to the second pin selected in the webgui
// Events:
// newKaku_<address>#<Channel>=<state> (0=off, 1-15=dimvalue, 16=on)
// Kaku_<address>#<Channel>=<state> (0=off, 1=on)
// HE300EU_<address>#<Channel>=<state> (0=off, 1=on)
// Commands:
// newKakuSend <address>, <Channel>, <state/dim>
// KakuSend <address>, <Channel>, <state>
// This is a Work in Progress mini project!
// It has limited use because in most cases, your fancy Home Automation controller can handle 433MHz devices quite well using RFLink.
// It was implemented because in some cases i would like to have local "Klik-Aan-Klik-Uit" support using a standalone ESP Easy.
// (Just because i own quite a lot of these Kaku devices)
// Current state / limitations:
// Implemented send and receive support for KaKu with automatic code (no code wheel)
// Implemented send and receive support for old KaKu unit's with code wheels
// Implemented receive support for HomeEasy HE300EU remotes
// RF Sender and RF receiver each need their own antenna! (as opposed to using a transceiver)
#define MIN_PULSE_LENGTH 100 // Too short pulses are considered to be noise...
#define SIGNAL_TIMEOUT 5 // gap between transmissions
#define MIN_RAW_PULSES 32 // Minimum number of pulses to be received, otherwise considered to be noise...
#define RAW_BUFFER_SIZE 256
#define RAWSIGNAL_MULTIPLY 25
void RF_ISR() ICACHE_RAM_ATTR;
// We need our own rawsignal buffer here.
// During plugin rawsignal checks, the IRQ routine will alPlugin_199_ready be working on the next signal burst...
volatile byte Plugin_199_RFBuffer[RAW_BUFFER_SIZE];
volatile boolean Plugin_199_ready = false;
volatile byte Plugin_199_pulses[RAW_BUFFER_SIZE + 2];
volatile int Plugin_199_number;
unsigned long Plugin_199_codeHash;
unsigned long Plugin_199_lastTime;
int8_t Plugin_199_RXpin = -1;
int8_t Plugin_199_TXpin = -1;
#define PLUGIN_199
#define PLUGIN_ID_199 199
#define PLUGIN_NAME_199 "RF Receiver/Sender [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_199 "Address"
#define PLUGIN_VALUENAME2_199 "Channel"
#define PLUGIN_VALUENAME3_199 "State"
boolean Plugin_199(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_199;
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 = false;
Device[deviceCount].ValueCount = 3;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_199);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_199));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_199));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_199));
break;
}
case PLUGIN_INIT:
{
if (Settings.TaskDevicePin1[event->TaskIndex] != -1)
{
Plugin_199_RXpin = Settings.TaskDevicePin1[event->TaskIndex];
pinMode(Plugin_199_RXpin, INPUT_PULLUP);
attachInterrupt(Plugin_199_RXpin, RF_ISR, CHANGE);
success = true;
}
if (Settings.TaskDevicePin1[event->TaskIndex] != -1)
{
Plugin_199_TXpin = Settings.TaskDevicePin2[event->TaskIndex];
pinMode(Plugin_199_TXpin, OUTPUT);
}
break;
}
case PLUGIN_TEN_PER_SECOND:
{
if (Plugin_199_ready)
{
if (decodeNewKaku(event->BaseVarIndex));
else if (decodeKaku());
else if (decodeHE300EU());
Plugin_199_ready = false;
}
break;
}
case PLUGIN_WRITE:
{
String command = parseString(string, 1);
if (command == F("newkakusend"))
{
success = true;
sendNewKaku(event->Par1, event->Par2, event->Par3);
}
if (command == F("kakusend"))
{
success = true;
sendKaku(event->Par1, event->Par2, event->Par3);
}
break;
}
}
return success;
}
//********************************************************************************
// Interrupt handler for RF messages
//********************************************************************************
void RF_ISR()
{
static unsigned int counter = 0;
static unsigned long TimeStamp = 0;
unsigned long TimeElapsed = 0;
TimeElapsed = micros() - TimeStamp;
TimeStamp = micros();
if (TimeElapsed > MIN_PULSE_LENGTH && counter < RAW_BUFFER_SIZE)
{
counter++;
Plugin_199_RFBuffer[counter] = TimeElapsed / 25;
}
else
counter = 0;
if (TimeElapsed > (SIGNAL_TIMEOUT * 1000) )
{
if (counter > MIN_RAW_PULSES)
{
Plugin_199_number = counter;
// copy IRQ RF working buffer to RawSignal struct
for (unsigned int x = 0; x <= counter; x++)
Plugin_199_pulses[x] = Plugin_199_RFBuffer[x];
Plugin_199_ready = true;
counter = 0;
}
else
counter = 0;
}
if (counter >= RAW_BUFFER_SIZE)
counter = 0;
}
//********************************************************************************
// Transmit pulses using pulse array
//********************************************************************************
void RawSendRF(void)
{
if (Plugin_199_RXpin != -1)
detachInterrupt(Plugin_199_RXpin);
int x;
//digitalWrite(PIN_RF_RX_VCC,LOW); // Turn off RF receiver
//digitalWrite(PIN_RF_TX_VCC,HIGH); // Turn on RF sender
delay(5); // small delay between switching send/receive
Plugin_199_pulses[Plugin_199_number] = 1; // force last duration as 1 msec
for (byte y = 0; y < 7; y++) // repeats RF code
{
x = 1;
noInterrupts();
while (x < Plugin_199_number)
{
digitalWrite(Plugin_199_TXpin, HIGH);
delayMicroseconds(Plugin_199_pulses[x++] * 25 - 5);
digitalWrite(Plugin_199_TXpin, LOW);
delayMicroseconds(Plugin_199_pulses[x++] * 25 - 7);
}
interrupts();
delay(20);// Delay must run outside interrupt blocked code.
}
delay(5);
//digitalWrite(PIN_RF_TX_VCC,LOW); // turn off RF sender
//digitalWrite(PIN_RF_RX_VCC,HIGH); // turn on RF receiver
if (Plugin_199_RXpin != -1)
attachInterrupt(Plugin_199_RXpin, RF_ISR, CHANGE);
}
//********************************************************************************
// Decode NewKaku protocol (without code wheel)
//********************************************************************************
#define NewKAKU_RawSignalLength 132
#define NewKAKUdim_RawSignalLength 148
#define NewKAKU_1T 275 // us
#define NewKAKU_mT 650 // us
#define NewKAKU_4T 1100 // us
#define NewKAKU_8T 2200 // us
boolean decodeNewKaku(byte BaseVarIndex)
{
boolean success = false;
byte Par1 = 0;
unsigned long Par2 = 0;
unsigned long bitstream = 0L;
unsigned long address = 0L;
byte channel = 0;
byte command = 0;
boolean Bit;
int i;
int P0, P1, P2, P3;
Par1 = 0;
if (Plugin_199_number == NewKAKU_RawSignalLength || Plugin_199_number == NewKAKUdim_RawSignalLength)
{
i = 3; // Plugin_199_pulses[3] is de eerste van een T,xT,T,xT combinatie
do
{
P0 = Plugin_199_pulses[i] * 25;
P1 = Plugin_199_pulses[i + 1] * 25;
P2 = Plugin_199_pulses[i + 2] * 25;
P3 = Plugin_199_pulses[i + 3] * 25;
if (P0 < NewKAKU_mT && P1 < NewKAKU_mT && P2 < NewKAKU_mT && P3 > NewKAKU_mT)Bit = 0; // T,T,T,4T
else if (P0 < NewKAKU_mT && P1 > NewKAKU_mT && P2 < NewKAKU_mT && P3 < NewKAKU_mT)Bit = 1; // T,4T,T,T
else if (P0 < NewKAKU_mT && P1 < NewKAKU_mT && P2 < NewKAKU_mT && P3 < NewKAKU_mT) // T,T,T,T Deze hoort te zitten op i=111 want: 27e NewKAKU bit maal 4 plus 2 posities voor startbit
{
if (Plugin_199_number != NewKAKUdim_RawSignalLength) // als de dim-bits er niet zijn
return false;
}
else
return false; // andere mogelijkheden zijn niet geldig in NewKAKU signaal.
if (i < 130) // alle bits die tot de 32-bit pulstrein behoren 32bits * 4posities per bit + pulse/space voor startbit
bitstream = (bitstream << 1) | Bit;
else // de resterende vier bits die tot het dimlevel behoren
Par1 = (Par1 << 1) | Bit;
i += 4; // volgende pulsenquartet
} while (i < Plugin_199_number - 2); //-2 omdat de space/pulse van de stopbit geen deel meer van signaal uit maakt.
if (i > 140) // Commando en Dim deel
Par1++; // Dim level. +1 omdat gebruiker dim level begint bij één.
else
Par1 = ((bitstream >> 4) & 0x01) ? 16 : 0; // On/Off bit omzetten naar een Nodo waarde.
Par2 = bitstream;
address = bitstream >> 6;
channel = (bitstream & 0x0f) + 1;
command = (bitstream >> 4) & 0x03;
if (command > 1)
channel = 0;
// valid signal, remember timestamp to suppress repeats...
elapsed = millis() - Plugin_199_lastTime;
Plugin_199_lastTime = millis();
unsigned long codeHash = Par2 + Par1;
if (codeHash != Plugin_199_codeHash || (codeHash == Plugin_199_codeHash && elapsed > 250))
{
UserVar[BaseVarIndex] = address;
UserVar[BaseVarIndex + 1] = channel;
UserVar[BaseVarIndex + 2] = Par1;
String eventString = F("NewKaku_");
eventString += address;
eventString += F("#");
eventString += channel;
eventString += F("=");
eventString += Par1;
rulesProcessing(eventString);
success = true;
}
Plugin_199_codeHash = Par2 + Par1;
}
return success;
}
//********************************************************************************
// Send NewKaku protocol (without code wheel)
//********************************************************************************
void sendNewKaku(unsigned long address, byte channel, byte state)
{
unsigned long bitstream = 0L;
byte i = 1;
byte x; // aantal posities voor pulsen/spaces in RawSignal
bitstream = address << 6;
bitstream |= (channel - 1);
//RawSignal.Repeats = 7; // Aantal herhalingen van het signaal.
//RawSignal.Delay = 20; // Tussen iedere pulsenreeks enige tijd rust.
if (state == 16 || state == 0)
{
bitstream |= (state == 16) << 4; // bit-5 is het on/off commando in KAKU signaal
x = 130; // verzend startbit + 32-bits = 130
}
else
x = 146; // verzend startbit + 32-bits = 130 + 4dimbits = 146
// bitstream bevat nu de KAKU-bits die verzonden moeten worden.
for (i = 3; i <= x; i++)Plugin_199_pulses[i] = NewKAKU_1T / 25; // De meeste tijden in signaal zijn T. Vul alle pulstijden met deze waarde. Later worden de 4T waarden op hun plek gezet
i = 1;
Plugin_199_pulses[i++] = NewKAKU_1T / 25; //pulse van de startbit
Plugin_199_pulses[i++] = NewKAKU_8T / 25; //space na de startbit
byte y = 31; // bit uit de bitstream
while (i < x)
{
if ((bitstream >> (y--)) & 1)
Plugin_199_pulses[i + 1] = NewKAKU_4T / 25; // Bit=1; // T,4T,T,T
else
Plugin_199_pulses[i + 3] = NewKAKU_4T / 25; // Bit=0; // T,T,T,4T
if (x == 146) // als het een dim opdracht betreft
{
if (i == 111) // Plaats van de Commando-bit uit KAKU
Plugin_199_pulses[i + 3] = NewKAKU_1T / 25; // moet een T,T,T,T zijn bij een dim commando.
if (i == 127) // als alle pulsen van de 32-bits weggeschreven zijn
{
bitstream = (unsigned long)state; // nog vier extra dim-bits om te verzenden.
y = 3;
}
}
i += 4;
}
Plugin_199_pulses[i++] = NewKAKU_1T / 25; //pulse van de stopbit
Plugin_199_pulses[i] = 0; //space van de stopbit
Plugin_199_number = i; // aantal bits*2 die zich in het opgebouwde RawSignal bevinden
RawSendRF();
}
//********************************************************************************
// Decode Kaku protocol (with code wheel)
//********************************************************************************
#define KAKU_CodeLength 12
#define KAKU_T 350
boolean decodeKaku()
{
boolean success = false;
byte Par1 = 0;
unsigned long Par2 = 0;
int i, j;
unsigned long bitstream = 0;
if (Plugin_199_number != (KAKU_CodeLength * 4) + 2)return false; // conventionele KAKU bestaat altijd uit 12 data bits plus stop. Ongelijk, dan geen KAKU!
for (i = 0; i < KAKU_CodeLength; i++)
{
j = (KAKU_T * 2) / 25;
if (Plugin_199_pulses[4 * i + 1] < j && Plugin_199_pulses[4 * i + 2] > j && Plugin_199_pulses[4 * i + 3] < j && Plugin_199_pulses[4 * i + 4] > j) {
bitstream = (bitstream >> 1); // 0
}
else if (Plugin_199_pulses[4 * i + 1] < j && Plugin_199_pulses[4 * i + 2] > j && Plugin_199_pulses[4 * i + 3] > j && Plugin_199_pulses[4 * i + 4] < j) {
bitstream = (bitstream >> 1 | (1 << (KAKU_CodeLength - 1))); // 1
}
else if (Plugin_199_pulses[4 * i + 1] < j && Plugin_199_pulses[4 * i + 2] > j && Plugin_199_pulses[4 * i + 3] < j && Plugin_199_pulses[4 * i + 4] < j) {
bitstream = (bitstream >> 1); // Short 0, Groep commando op 2e bit.
Par1 = 2;
}
else {
return false; // foutief signaal
}
}
if ((bitstream & 0x600) == 0x600) // twee vaste bits van KAKU gebruiken als checksum
{ // Alles is in orde, bouw event op
Par2 = bitstream & 0xFF;
Par1 |= (bitstream >> 11) & 0x01;
// valid signal, remember timestamp to suppress repeats...
elapsed = millis() - Plugin_199_lastTime;
Plugin_199_lastTime = millis();
unsigned long codeHash = Par2 + Par1;
if (codeHash != Plugin_199_codeHash || (codeHash == Plugin_199_codeHash && elapsed > 250))
{
String eventString = F("Kaku_");
eventString += (Par2 & 0x0f) + 1;
eventString += F("#");
eventString += (Par2 >> 4) + 1;
eventString += F("=");
eventString += Par1;
rulesProcessing(eventString);
success = true;
}
Plugin_199_codeHash = Par2 + Par1;
}
return success;
}
//********************************************************************************
// Send Kaku protocol (with code wheel)
//********************************************************************************
void sendKaku(unsigned long address, byte channel, byte state)
{
byte Par1 = state;
unsigned long Par2 = ((channel-1) << 4) + address-1;
unsigned long Bitstream = Par2 | (0x600 | ((Par1 & 1 /*Commando*/) << 11)); // Stel een bitstream samen
// loop de 12-bits langs en vertaal naar pulse/space signalen.
for (byte i = 0; i < KAKU_CodeLength; i++)
{
Plugin_199_pulses[4 * i + 1] = KAKU_T / RAWSIGNAL_MULTIPLY;
Plugin_199_pulses[4 * i + 2] = (KAKU_T * 3) / RAWSIGNAL_MULTIPLY;
if (((Par1 >> 1) & 1) /* Groep */ && i >= 4 && i < 8)
{
Plugin_199_pulses[4 * i + 3] = KAKU_T / RAWSIGNAL_MULTIPLY;
Plugin_199_pulses[4 * i + 4] = KAKU_T / RAWSIGNAL_MULTIPLY;
} // short 0
else
{
if ((Bitstream >> i) & 1) // 1
{
Plugin_199_pulses[4 * i + 3] = (KAKU_T * 3) / RAWSIGNAL_MULTIPLY;
Plugin_199_pulses[4 * i + 4] = KAKU_T / RAWSIGNAL_MULTIPLY;
}
else //0
{
Plugin_199_pulses[4 * i + 3] = KAKU_T / RAWSIGNAL_MULTIPLY;
Plugin_199_pulses[4 * i + 4] = (KAKU_T * 3) / RAWSIGNAL_MULTIPLY;
}
}
// Stopbit
Plugin_199_pulses[4 * KAKU_CodeLength + 1] = KAKU_T / RAWSIGNAL_MULTIPLY;
Plugin_199_pulses[4 * KAKU_CodeLength + 2] = KAKU_T / RAWSIGNAL_MULTIPLY;
}
Plugin_199_number=KAKU_CodeLength*4+2;
RawSendRF();
}
//********************************************************************************
// Decode HomeEasy 3xx series EU protocol (without code wheel)
//********************************************************************************
boolean decodeHE300EU()
{
boolean success = false;
byte Par1 = 0;
unsigned long Par2 = 0;
unsigned long address = 0;
unsigned long bitstream = 0;
int counter = 0;
byte rfbit = 0;
byte state = 0;
unsigned long channel = 0;
// valid messages are 116 pulses
if (Plugin_199_number != 116) return false;
for (byte x = 1; x <= Plugin_199_number; x = x + 2)
{
if ((Plugin_199_pulses[x] * 25 < 500) & (Plugin_199_pulses[x + 1] * 25 > 500))
rfbit = 1;
else
rfbit = 0;
if ((x >= 23) && (x <= 86)) address = (address << 1) | rfbit;
if ((x >= 87) && (x <= 114)) bitstream = (bitstream << 1) | rfbit;
}
state = ((bitstream >> 8) & 0x3) - 1;
channel = (bitstream) & 0x3f;
Par1 = state;
Par2 = address + channel;
// valid signal, remember timestamp to suppress repeats...
elapsed = millis() - Plugin_199_lastTime;
Plugin_199_lastTime = millis();
unsigned long codeHash = Par2 + Par1;
if (codeHash != Plugin_199_codeHash || (codeHash == Plugin_199_codeHash && elapsed > 250))
{
String eventString = F("HE300EU_");
eventString += address;
eventString += F("#");
eventString += channel;
eventString += F("=");
eventString += Par1;
rulesProcessing(eventString);
success = true;
}
Plugin_199_codeHash = Par2 + Par1;
}
//********************************************************************************
// Decode generic protocol, deriving hash value
//********************************************************************************
boolean decodeUnknown()
{
boolean success = false;
byte Par1 = 0;
unsigned long Par2 = 0;
int x;
unsigned int MinPulse = 0xffff;
unsigned int MinSpace = 0xffff;
unsigned long CodeM = 0L;
unsigned long CodeS = 0L;
if (Plugin_199_number < MIN_RAW_PULSES) return false;
for (x = 5; x < Plugin_199_number - 2; x += 2)
{
if (Plugin_199_pulses[x] < MinPulse)MinPulse = Plugin_199_pulses[x];
if (Plugin_199_pulses[x + 1] < MinSpace)MinSpace = Plugin_199_pulses[x + 1];
}
MinPulse += (MinPulse * 100) / 100;
MinSpace += (MinSpace * 100) / 100;
// Data kan zowel in de mark als de space zitten. Daarom pakken we beide voor data opbouw.
for (x = 3; x <= Plugin_199_number; x += 2)
{
CodeM = (CodeM << 1) | (Plugin_199_pulses[x] > MinPulse);
CodeS = (CodeS << 1) | (Plugin_199_pulses[x + 1] > MinSpace);
}
// Data kan zowel in de mark als de space zitten. We nemen de grootste waarde voor de data.
if (CodeM > CodeS)
Par2 = CodeM;
else
Par2 = CodeS;
// valid signal, remember timestamp to suppress repeats...
elapsed = millis() - Plugin_199_lastTime;
Plugin_199_lastTime = millis();
unsigned long codeHash = Par2;
if (codeHash != Plugin_199_codeHash || (codeHash == Plugin_199_codeHash && elapsed > 250))
{
String eventString = F("UnknownRF_");
eventString += Par2;
rulesProcessing(eventString);
success = true;
}
Plugin_199_codeHash = Par2;
}
#endif
+490
View File
@@ -0,0 +1,490 @@
#ifdef PLUGIN_BUILD_DEV
//#######################################################################################################
//#################################### Plugin 210: MQTT Import ##########################################
//#################################### Version 0.4 5-Aug-2016 ###########################################
//## This Version Requires ESPEasy 114+, Core 2.3 and PubSub 2.6 #######
//#######################################################################################################
// This task reads data from the MQTT Import input stream and saves the value
#define PLUGIN_210
#define PLUGIN_ID_210 210
#define PLUGIN_NAME_210 "MQTT Import [DEVELOPMENT]"
#define PLUGIN_VALUENAME1_210 "Value1"
#define PLUGIN_VALUENAME2_210 "Value2"
#define PLUGIN_VALUENAME3_210 "Value3"
#define PLUGIN_VALUENAME4_210 "Value4"
#define PLUGIN_IMPORT 210 // This is a 'private' function used only by this import module
// Declare a Wifi client for this plugin only
WiFiClient espclient_210;
PubSubClient MQTTclient_210(espclient_210); // Create a new pubsub instance
boolean Plugin_210(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
char deviceTemplate[4][41]; // variable for saving the subscription topics
//
// Generate the MQTT import client name from the system name and a suffix
//
String tmpClientName = "%sysname%-Import";
String ClientName = parseTemplate(tmpClientName, 20);
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_210;
Device[deviceCount].Type = SENSOR_TYPE_SWITCH;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE; // This means it has a single pin
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true; // Need this in order to get the decimals option
Device[deviceCount].ValueCount = 4;
Device[deviceCount].SendDataOption = false;
Device[deviceCount].TimerOption=false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_210);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_210));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_210));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_210));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_210));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
for (byte varNr = 0; varNr < 4; varNr++)
{
string += F("<TR><TD>MQTT Topic ");
string += varNr + 1;
string += F(":<TD><input type='text' size='40' maxlength='40' name='Plugin_210_template");
string += varNr + 1;
string += F("' value='");
string += deviceTemplate[varNr];
string += F("'>");
}
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
String argName;
for (byte varNr = 0; varNr < 4; varNr++)
{
argName = F("Plugin_210_template");
argName += varNr + 1;
strncpy(deviceTemplate[varNr], WebServer.arg(argName).c_str(), sizeof(deviceTemplate[varNr]));
}
Settings.TaskDeviceID[event->TaskIndex] = 1; // temp fix, needs a dummy value
SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
success = true;
break;
}
case PLUGIN_INIT:
{
// When we edit the subscription data from the webserver, the plugin is called again with init.
// In order to resubscribe we have to disconnect and reconnect in order to get rid of any obsolete subscriptions
MQTTclient_210.disconnect();
if (MQTTConnect_210(ClientName))
{
// Subscribe to ALL the topics from ALL instance of this import module
MQTTSubscribe_210();
success = true;
}
else
{
success=false;
}
}
case PLUGIN_TEN_PER_SECOND:
{
MQTTclient_210.loop(); // Listen out for callbacks
success=true;
break;
}
case PLUGIN_ONCE_A_SECOND:
{
// Here we check that the MQTT client is alive.
if (!MQTTclient_210.connected()){
String log = F("IMPT : MQTT 210 Connection lost");
addLog(LOG_LEVEL_ERROR, log);
MQTTclient_210.disconnect();
delay(1000);
if (! MQTTConnect_210(ClientName)){
success=false;
break;
}
MQTTSubscribe_210();
}
success=true;
break;
}
case PLUGIN_READ:
{
// This routine does not output any data and so we do not need to respond to regular read requests
success = false;
break;
}
case PLUGIN_IMPORT:
{
// This is a private option only used by the MQTT 210 callback function
// Get the payload and check it out
String Payload=event->String2;
float floatPayload=string2float(Payload);
LoadTaskSettings(event->TaskIndex);
if (floatPayload == -999){
String log=F("IMPT : Bad Import MQTT Command ");
log+=event->String1;
addLog(LOG_LEVEL_ERROR,log);
log="ERR : Illegal Payload ";
log+=Payload;
log+=" ";
log+=ExtraTaskSettings.TaskDeviceName;
addLog(LOG_LEVEL_INFO,log);
success=false;
break;
}
// Get the Topic and see if it matches any of the subscriptions
String Topic=event->String1;
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
for (byte x = 0; x < 4; x++)
{
String subscriptionTopic = deviceTemplate[x];
subscriptionTopic.trim();
if (subscriptionTopic.length() == 0) continue; // skip blank subscriptions
// Now check if the incoming topic matches one of our subscriptions
if (MQTTCheckSubscription_210(Topic,subscriptionTopic))
{
UserVar[event->BaseVarIndex+x]=floatPayload; // Save the new value
// Log the event
String log =F("IMPT : [");
log += ExtraTaskSettings.TaskDeviceName;
log += F("#");
log += ExtraTaskSettings.TaskDeviceValueNames[x];
log += F("] : ");
log += floatPayload;
addLog(LOG_LEVEL_INFO, log);
// Generate event for rules processing - proposed by TridentTD
if (Settings.UseRules)
{
String RuleEvent = F("");
RuleEvent += ExtraTaskSettings.TaskDeviceName;
RuleEvent += F("#");
RuleEvent += ExtraTaskSettings.TaskDeviceValueNames[x];
RuleEvent += F("=");
RuleEvent += floatPayload;
rulesProcessing(RuleEvent);
}
success = true;
}
}
break;
}
}
return success;
}
boolean MQTTSubscribe_210()
{
// Subscribe to the topics requested by ALL calls to this plugin.
// We do this because if the connection to the broker is lost, we want to resubscribe for all instances.
char deviceTemplate[4][41];
// Loop over all tasks looking for a 210 instance
for (byte y = 0; y < TASKS_MAX; y++)
{
if (Settings.TaskDeviceNumber[y] == 210)
{
LoadCustomTaskSettings(y, (byte*)&deviceTemplate, sizeof(deviceTemplate));
// Now loop over all import variables and subscribe to those that are not blank
for (byte x = 0; x < 4; x++)
{
String subscribeTo = deviceTemplate[x];
if (subscribeTo.length() > 0)
{
if (MQTTclient_210.subscribe(subscribeTo.c_str()))
{
String log = F("IMPT : [");
LoadTaskSettings(y);
log += ExtraTaskSettings.TaskDeviceName;
log += F("#");
log += ExtraTaskSettings.TaskDeviceValueNames[x];
log += F("] subscribed to ");
log += subscribeTo;
addLog(LOG_LEVEL_INFO, log);
}
else
{
String log = F("IMPT : Error subscribing to ");
log += subscribeTo;
addLog(LOG_LEVEL_ERROR, log);
return false;
}
}
}
}
}
return true;
}
//
// handle MQTT messages
//
void mqttcallback_210(char* c_topic, byte* b_payload, unsigned int length)
{
// Here we have incomng MQTT messages from the mqtt import module
String topic = c_topic;
char cpayload[256];
strncpy(cpayload, (char*)b_payload, length);
cpayload[length] = 0;
String payload = cpayload; // convert byte to char string
payload.trim();
byte DeviceIndex = getDeviceIndex(210); // This is the device index of 210 modules -there should be one!
// We generate a temp event structure to pass to the plugins
struct EventStruct TempEvent;
TempEvent.String1 = topic; // This is the topic of the message
TempEvent.String2 = payload; // This is the payload
// Here we loop over all tasks and call each 210 plugin with function PLUGIN_IMPORT
for (byte y = 0; y < TASKS_MAX; y++)
{
if (Settings.TaskDeviceNumber[y] == 210) // if we have found a 210 device, then give it something to think about!
{
TempEvent.TaskIndex = y;
TempEvent.BaseVarIndex = y * VARS_PER_TASK; // This is the index in Uservar where values for this task are stored
Plugin_ptr[DeviceIndex](PLUGIN_IMPORT, &TempEvent, payload);
}
}
}
//
// Make a new client connection to the mqtt broker.
// For some reason this seems to failduring the call in INIT- however it succeeds later during recovery
// It would be nice to understand this....
boolean MQTTConnect_210(String clientid)
{
boolean result = false;
// Do nothing if already connected
if (MQTTclient_210.connected())return true;
IPAddress MQTTBrokerIP(Settings.Controller_IP);
// define stuff for the client - this could also be done in the intial declaration of MQTTclient_210
MQTTclient_210.setServer(MQTTBrokerIP, Settings.ControllerPort);
MQTTclient_210.setCallback(mqttcallback_210);
// Try three times for a connection
for (byte x = 1; x < 4; x++)
{
String log = "";
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
result = MQTTclient_210.connect(clientid.c_str(), SecuritySettings.ControllerUser, SecuritySettings.ControllerPassword);
else
result = MQTTclient_210.connect(clientid.c_str());
if (result)
{
log = F("IMPT : Connected to MQTT broker with Client ID=");
log += clientid;
addLog(LOG_LEVEL_INFO, log);
break; // end loop if succesfull
}
else
{
log = F("IMPT : Failed to connect to MQTT broker - attempt ");
log += x;
addLog(LOG_LEVEL_ERROR, log);
}
delay(500);
}
return MQTTclient_210.connected();
}
//
// Check to see if Topic matches the MQTT subscription
//
boolean MQTTCheckSubscription_210(String Topic, String Subscription) {
String tmpTopic = Topic;
String tmpSub = Subscription;
tmpTopic.trim();
tmpSub.trim();
// Get rid of any initial /
if (tmpTopic.substring(0, 1) == "/")tmpTopic = tmpTopic.substring(1);
if (tmpSub.substring(0, 1) == "/")tmpSub = tmpSub.substring(1);
// Add trailing / if required
int lenTopic = tmpTopic.length();
if (tmpTopic.substring(lenTopic - 1, lenTopic) != "/")tmpTopic += F("/");
int lenSub = tmpSub.length();
if (tmpSub.substring(lenSub - 1, lenSub) != "/")tmpSub += F("/");
// Now get first part
int SlashTopic;
int SlashSub;
int count = 0;
String pTopic;
String pSub;
while (count < 10) {
// Get locations of the first /
SlashTopic = tmpTopic.indexOf('/');
SlashSub = tmpSub.indexOf('/');
// If no slashes found then match is OK
// If only one slash found then not OK
if ((SlashTopic == -1) && (SlashSub == -1)) return true;
if ((SlashTopic == -1) && (SlashSub != -1)) return false;
if ((SlashTopic != -1) && (SlashSub == -1)) return false;
// Get the values for the current subtopic
pTopic = tmpTopic.substring(0, SlashTopic);
pSub = tmpSub.substring(0, SlashSub);
// And strip the subtopic from the topic
tmpTopic = tmpTopic.substring(SlashTopic + 1);
tmpSub = tmpSub.substring(SlashSub + 1);
// If the subtopics match then OK - otherwise fail
if (pSub == "#") return true;
if ((pTopic != pSub) && (pSub != "+"))return false;
count = count + 1;
}
return false;
}
// ***************************************************************************
// Convert String to float - returns -999 in case of error
float string2float(String myString) {
int i, len;
float value;
len = myString.length();
char tmp[(len + 1)]; // one extra for the zero termination
byte start = 0;
// Look for decimal point - they can be anywhere but no more than one of them!
int dotIndex = myString.indexOf(".");
//Serial.println(dotIndex);
if (dotIndex != -1)
{
int dotIndex2 = (myString.substring(dotIndex + 1)).indexOf(".");
//Serial.println(dotIndex2);
if (dotIndex2 != -1)return -999.00; // Give error if there is more than one dot
}
if (myString.substring(0, 1) == "-") {
start = 1; //allow a minus in front of string
tmp[i] = '-';
}
for (i = start; i<len; i++)
{
tmp[i] = myString.charAt(i);
if (!isdigit(tmp[i]))
{
if (tmp[i] != '.')return -999;
}
}
tmp[i] = 0;
value = atof(tmp);
return value;
}
#endif
View File
+6 -8
View File
@@ -1076,7 +1076,7 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
{
for (byte y = 0; y < TASKS_MAX; y++)
{
if (Settings.TaskDeviceEnabled[y] && Settings.TaskDeviceNumber[y] != 0)
if (Settings.TaskDeviceNumber[y] != 0)
{
for (x = 0; x < PLUGIN_MAX; x++)
{
@@ -1085,8 +1085,8 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]);
TempEvent.TaskIndex = y;
TempEvent.BaseVarIndex = y * VARS_PER_TASK;
//TempEvent.idx = Settings.TaskDeviceID[y]; todo check
TempEvent.sensorType = Device[DeviceIndex].VType;
TempEvent.idx = Settings.TaskDeviceID[y];
TempEvent.sensorType = Device[DeviceIndex].VType;
if (Plugin_ptr[x](Function, event, str))
return true;
}
@@ -1100,7 +1100,6 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
// Call to all plugins that are used in a task
case PLUGIN_ONCE_A_SECOND:
case PLUGIN_TEN_PER_SECOND:
case PLUGIN_FIFTY_PER_SECOND:
case PLUGIN_INIT_ALL:
case PLUGIN_CLOCK_IN:
case PLUGIN_EVENT_OUT:
@@ -1109,14 +1108,14 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
Function = PLUGIN_INIT;
for (byte y = 0; y < TASKS_MAX; y++)
{
if (Settings.TaskDeviceEnabled[y] && Settings.TaskDeviceNumber[y] != 0)
if (Settings.TaskDeviceNumber[y] != 0)
{
if (Settings.TaskDeviceDataFeed[y] == 0) // these calls only to tasks with local feed
{
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]);
TempEvent.TaskIndex = y;
TempEvent.BaseVarIndex = y * VARS_PER_TASK;
//TempEvent.idx = Settings.TaskDeviceID[y]; todo check
TempEvent.idx = Settings.TaskDeviceID[y];
TempEvent.sensorType = Device[DeviceIndex].VType;
TempEvent.OriginTaskIndex = event->TaskIndex;
for (x = 0; x < PLUGIN_MAX; x++)
@@ -1141,7 +1140,6 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
case PLUGIN_WEBFORM_SHOW_CONFIG:
case PLUGIN_GET_DEVICEVALUENAMES:
case PLUGIN_READ:
case PLUGIN_REMOTE_CONFIG:
for (x = 0; x < PLUGIN_MAX; x++)
{
if ((Plugin_id[x] != 0 ) && (Plugin_id[x] == Settings.TaskDeviceNumber[event->TaskIndex]))
@@ -1155,4 +1153,4 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
}// case
return false;
}
}
+1 -25
View File
@@ -1,30 +1,6 @@
// Rxxx 02-12-2016 EasyMega build (experimental)
// Native SPIFFS support, old custom flash routines removed
// Support OTA up to 1.5MB sketch size (change to 1M SPIFFS model) on 4M modules
// Fallback Wifi AP support
// Supports multiple active controllers
// Supports notification plugins (basic email _N001.ino provided)
// Native SD card support and system logging to SD card
// Taskvalues are preserved during reboot (not after power loss!)
// Multiple rule sets, max 4 sets, each 2k in size
// Several device plugins reworked and added to the main branch:
// P036 Framed OLED
// P037 MQTT import
// P038 NeoPixel
// P039 Thermocouple
// P040 ID12/RDM6300 RFID
// P041 NeoPixel WordClock
// P042 NeoPixel Candle
// P043 Timer Clock
// P044 P1 gateway
// Removed savesettings/savecustomsettings from candle plugin, check this later...
// UDP broadcast option prep
// Flash write protection mechanism (aded command 'resetFlashWriteCounter')
// IDX/var no longer mandatory and only requested when the selected controller needs it
// Clock#Time supports 'Wrk' for workdays and 'Wkd' for weekends as wildcards
// R148 02-12-2016
// Fixed a bug in ADS1115 plugin (contributed by Shardan)
// Fixed a bug on R146 Ser2Net
// R147 27-11-2016
// Fixed a situation where a large message delay uses background processing without UPD handling, causing network issues.
-28
View File
@@ -1,28 +0,0 @@
#!/bin/bash
VERSION=$(git describe)
echo "Creating release archives for $VERSION ..."
#binaries
# cp .pioenvs/mini_512/firmware.bin dist/"ESPEasy_$VERSION""_mini_512.bin"
cp .pioenvs/normal_1024/firmware.bin dist/"ESPEasy_$VERSION""_normal_1024.bin"
cp .pioenvs/normal_4096/firmware.bin dist/"ESPEasy_$VERSION""_normal_4096.bin"
cp .pioenvs/normal_8285/firmware.bin dist/"ESPEasy_$VERSION""_normal_8285.bin"
cp .pioenvs/test_1024/firmware.bin dist/"ESPEasy_$VERSION""_test_1024.bin"
cp .pioenvs/test_4096/firmware.bin dist/"ESPEasy_$VERSION""_test_4096.bin"
cp .pioenvs/test_8285/firmware.bin dist/"ESPEasy_$VERSION""_test_8285.bin"
cp .pioenvs/dev_1024/firmware.bin dist/"ESPEasy_$VERSION""_dev_1024.bin"
cp .pioenvs/dev_4096/firmware.bin dist/"ESPEasy_$VERSION""_dev_4096.bin"
cp .pioenvs/dev_8285/firmware.bin dist/"ESPEasy_$VERSION""_dev_8285.bin"
#create a source structure that is the same as the original ESPEasy project (and works with the howto on the wiki)
rm -rf dist/Source 2>/dev/null
mkdir dist/Source
cp -r lib dist/Source/
cp -r src dist/Source/
cp platformio.ini dist/Source/
cd dist
zip ../ESPEasy_$VERSION.zip -r .
BIN
View File
Binary file not shown.
-63
View File
@@ -1,63 +0,0 @@
plugin |cache IRAM |init RAM |r.o. RAM |uninit RAM |Flash ROM
src/_C001.ino |0 |0 |272 |0 |3520
src/_C002.ino |0 |4 |528 |32 |6064
src/_C003.ino |0 |0 |64 |0 |1072
src/_C004.ino |0 |0 |56 |8 |1280
src/_C005.ino |0 |4 |56 |8 |1424
src/_C006.ino |0 |0 |64 |0 |1296
src/_C007.ino |0 |4 |32 |0 |1664
src/_C008.ino |0 |0 |80 |0 |2272
src/_C009.ino |0 |4 |352 |16 |4896
src/_C010.ino |0 |0 |48 |0 |1136
src/_C011.ino |0 |0 |152 |8 |5248
src/_N001_Email.ino |0 |0 |72 |8 |1808
src/_N002_Buzzer.ino |288 |12 |8 |264 |1184
src/_P001_Switch.ino |1028 |8 |104 |280 |7248
src/_P002_ADC.ino |0 |0 |16 |0 |336
src/_P003_Pulse.ino |167 |0 |144 |192 |2544
src/_P004_Dallas.ino |0 |0 |64 |16 |2496
src/_P005_DHT.ino |0 |0 |56 |8 |1520
src/_P006_BMP085.ino |0 |4 |48 |8 |2112
src/_P007_PCF8591.ino |0 |0 |8 |8 |400
src/_P008_RFID.ino |101 |0 |56 |8 |624
src/_P009_MCP.ino |0 |0 |104 |24 |3232
src/_P010_BH1750.ino |0 |0 |56 |8 |2688
src/_P011_PME.ino |0 |4 |96 |0 |3040
src/_P012_LCD.ino |0 |4 |120 |8 |3520
src/_P013_HCSR04.ino |90 |0 |64 |16 |1552
src/_P014_SI7021.ino |0 |4 |48 |0 |1824
src/_P015_TSL2561.ino |0 |0 |56 |8 |3488
src/_P016_IR.ino |288 |0 |72 |480 |3600
src/_P017_PN532.ino |0 |0 |88 |72 |2016
src/_P018_Dust.ino |0 |0 |56 |8 |512
src/_P019_PCF8574.ino |0 |0 |104 |24 |2848
src/_P020_Ser2Net.ino |0 |0 |88 |40 |3456
src/_P021_Level.ino |0 |4 |136 |24 |1872
src/_P022_PCA9685.ino |0 |4 |32 |0 |1216
src/_P023_OLED.ino |0 |4 |80 |0 |4448
src/_P024_MLX90614.ino |0 |4 |56 |8 |992
src/_P025_ADS1115.ino |0 |0 |72 |8 |1184
src/_P026_Sysinfo.ino |0 |0 |72 |8 |864
src/_P027_INA219.ino |0 |0 |56 |24 |1840
src/_P028_BME280.ino |128 |0 |48 |80 |3488
src/_P029_Output.ino |0 |4 |8 |8 |256
src/_P030_BMP280.ino |128 |0 |48 |48 |3024
src/_P031_SHT1X.ino |0 |0 |100 |0 |2176
src/_P032_MS5611.ino |0 |4 |88 |56 |2592
src/_P033_Dummy.ino |0 |4 |48 |0 |1168
src/_P034_DHT12.ino |0 |0 |16 |0 |656
src/_P035_IRTX.ino |0 |4 |64 |-8 |3840
src/_P036_FrameOLED.ino |0 |4 |96 |0 |33600
src/_P037_MQTTImport.ino |0 |0 |24 |40 |3536
src/_P038_NeoPixel.ino |128 |0 |56 |8 |1712
src/_P039_Thermocouple.ino |0 |0 |104 |8 |1536
src/_P040_ID12.ino |0 |4 |72 |8 |640
src/_P041_NeoClock.ino |128 |4 |128 |0 |3344
src/_P042_Candle.ino |128 |8 |160 |32 |8048
src/_P043_ClkOutput.ino |0 |0 |80 |0 |1456
src/_P044_P1WifiGateway.ino |0 |0 |80 |64 |4032
src/_P045_MPU6050.ino |0 |4 |216 |72 |4496
src/_P046_VentusW266.ino |325 |4 |184 |88 |3920
src/_P047_i2c-soil-moisture-so|0 |4 |216 |8 |2144
src/_P048_Motorshield_v2.ino |0 |32 |208 |0 |5952
src/_P049_MHZ19.ino |380 |80 |184 |88 |3792
-377
View File
@@ -1,377 +0,0 @@
-----------------------------
Changes in release v2.0.0-dev10
-----------------------------
Release date: Mon May 29 22:53:54 CEST 2017
DatuX (1):
Update README.md
Jochen Krapf (1):
Rework of plugin ADC (#319)
krikk (1):
reverted change, this fix seems to have exactly opposite outcome than expected... with the fix applied i get errors, without is i get no errors... (#320)
-----------------------------
Changes in release v2.0.0-dev9
-----------------------------
Release date: Sun May 28 15:16:00 CEST 2017
Alex Schwantes (1):
Implemented use of addFormSelector methods to _P004_Dallas plugin. Changed the device select box to show the one wire address for each connected sensor instead of just a number. Added a blank option to the device address select box so that in the event that multiple devices are present and the configured device is not currently available, the select box will be blank instead of selecting a different device.
Bartlomiej Zimon (5):
- Misc: typo
Custom Controller Settings - add controller index
Push ProtocolIndex and ControllerIndex into CPLUGIN_WEBFORM_SAVE/LOAD
Add WifiSSID2,WifiKey2 commands
Add backup Wifi network to Settings command
Blair Thompson (1):
Added Par4 and Par5 Variables (#248)
Daniel Tedenljung (5):
Updated wrong plugin number. (#269)
P052: More descriptive log messages (#283)
GUI touchup on Tools (#286)
addSubmitButton function added (#289)
New look on Tools page (#296)
DatuX (5):
Update README.md
Update issue_template.md
Update CONTRIBUTING.md
Update README.md
Update README.md
Edwin Eefting (17):
cleaned up messagedelay: use the same function everywhere. and do serial processing as well during the messagedelay
fixed issue #253 (memory leaks/crashes)
more details in memory analyser. run memory analyser via Travis
cosmetic buildlog fix
publish MQTT Connected message
timer boundschecker was off by one. fixed memanalyser total
input box fix on setting pages
comments. checkudp only in backgroundtasks()
reboot and wifidisconnect should be handled by /
bugfix in rtc checksum
nicer sleep messages
fixed a few out of bounds bugs in Misc.ino _P023_OLED.ino _P035_IRTX.ino _P037_MQTTImport.ino with cppcheck. also added cppcheck to travis to prevent such cases in the future
fixing cpp check
fixing cpp check
fixing cpp check
fixing cpp check
also distribute ESP8285 binaries
JK (5):
added functions addCheckBox and addNumericBox
added checkbox for status LED inversed
fine tuning of status LED and pimp hardware web site
solved my commit mismatch
Fixed #196 and rework of IDX display
Jochen Krapf (11):
Added addForm*-functions for easy web-interface and pimp GUI (#259)
Added function addFormSelector (#270)
Preliminary final draft of bugfix #264 (#271)
Replaced HTML code with addFormSelector() in all plugins (#278)
Fixed readUserVarFromRTC() #265 (#280)
Limits to NumericBox and a bit of security to PasswordBox (#281)
Added HTML templates for customization (#290)
Fixed rules bug #297 (#299)
Pimp device-GUI and optimized HTML (#306)
Fixed some minor HTML syntax bugs (#310)
Rework of plugin ADS1115 (#315)
PieVo (1):
Plantower (#300)
beic (1):
Some little description corrections (#297)
krikk (13):
http advanced controller, correct passing of hostname (#250)
i2c Temperatur & Humidity Sensor Am2320 (#251)
use the new addCheckBox function and better display of device config page
another fix to http advanced...
replaced static html code with the new addForm* Functions
bug fix wrong return type + form function fixes (#266)
addFormNumeric with min and max & More Form-Function replacements (#272)
make the Settings - Save. Filename more descriptive... (#273)
addHelpButton Function and a new Help Button for the Rules and Hardware Page (#282)
DHT plugin fix 'NaN' issue (#285)
i don't like hidden features, added a json button to the tools menu, next to the advanced button (#292)
do a dns lookup on every request, solves issue #261 (#302)
AM2320: negative temperature fix... (#312)
tedenda (1):
Moving plugin from Playground into main repo. (#262)
-----------------------------
Changes in release v2.0.0-dev8
-----------------------------
Release date: Mon Apr 24 13:21:32 CEST 2017
DatuX (6):
Update README.md
Update README.md
Update README.md
Update CONTRIBUTING.md
Update CONTRIBUTING.md
Update README.md
David Conran (2):
Update IRremoteESP8266 library url in .gitmodules
update sendSony() call to use repeats.
Dirk Moeller (2):
new function, Plugin_004_DS_setResolution und Plugin_004_DS_getResolution
fix typo
Edwin Eefting (36):
temporary disabled IR plugins, because of iram1_0_seg issues
initial version of memory analyser
moved arduinojson and liquidcrytal includes to correct plugins. reanbled IR-modules to solve memory issues
make the IRTX plugin work without the IR plugin
initial memory analyser and results
reduced memory usage _C001
reduced mem C001 C002
reduced ram usage C003 ... C011
reduce memory usage N001 N002
cleaned up servo stuff
recuded number of pulsecounters from 8 to 4 to save IRAM
contributing guidelines
fixed crash in C001 (when opening /controllers)
avoid static buffers in c001. addLog now also supports F(), so we dont need all those temporary variable definitions
removed unneccesay delays from c001
avoid unneccesary string conversions and static buffers in c001
fixed crashes caused by large MQTT packets
fixed lots of common issues that might cause crashes in c011. also see https://github.com/letscontrolit/ESPEasy/issues/117#issuecomment-293713370
added issue template to get cleaner bug reports
replaced all readstringuntil() with safeReadStringUntil()
starting working on stability reporting function
fixed stability issues in c009. probably caused by illegal PSTR usage, but i completly cleaned up all string handling
improved statusled handling in background tasks
converted submodule to normal directory. lib/Adafruit_Motor_Shield_V2 upstream commit ee4c4d334f498d54cdf80c9cc6f5bdec2533f8bf
now no longer a submodule lib/AS_BH1750, upstream version 092f0b1c5fa74eb2abe3d1b2925190d066e9506d
now no longer a submodule. lib/Adafruit_NeoPixel, upstream version v1.0.6
now no longer a submodule, lib/Adafruit_TCS34725 upstream version 1.0.1-13-g12be4c6
now no longer a submodule. lib/ArduinoJson upstream version v5.6.4
now no longer a submodule. lib/IRremoteESP8266 upstream version v1.0.2
oops moved lib/Adafruit_TCS34725 to wrong place
select env
Revert "Plugin_008-RFID extended with wiegand 34-bits and key-pad (4-bits per key) support". Now uses too much IRAM.
dont use arduino OTA in the dev env
escape html in the rules page, so that strings like &param do not cause problems. fixes issue #231
properly escape html in C011 generic http advanced.
fixed #239 due to improper PSTR. cleaned up string handling
Emmanuel Tatto (1):
getBearing should be outside the FEATURE_ARDUINO_OTA condition (#207)
Gerben Meijer (1):
Extend MH-Z19 sensor support
JK (3):
More informative and intuitive status LED
Using 3 I/O-pins consequently
added union to TaskDevicePin1..3
Jochen Krapf (1):
Added function isDeepSleepEnabled() (#177)
adb76 (2):
Set BME280 to recommended values for climate / weather sensor
BME280: Ensure sensor is in sleep mode to set the config, fix small typo
beic (13):
Menu correction, added BMP180 (#199)
Added detection for the HTU21D to I2C scenner
Environment naming will better fit in...
Environment naming will better fit in + HTU21D
Environment naming will better fit in... + naming
Environment naming will better fit in...
Environment naming will better fit in...
Environment naming will better fit in...
Environment naming will better fit in...
Environment naming will better fit in...
Little naming correction
Naming correction by Datasheet
Added detection for the SI1145 to I2C scenner
dev0 (1):
_C009.ino: RFC conformity and removed obsolet code (#163)
imthemichi (1):
Plugin_008-RFID extended with wiegand 34-bits and key-pad (4-bits per key) support
jbaumann (1):
Addition of ESP8285 targets (#187)
krikk (16):
motorshield library should be a submodule, enhanced the motorshield plugin... (#162)
http advanced: add replacement variable for systime, vcc, ip, sysload, uptime (#167)
corrected name for TSL2561, add option to use different sensor adress (#170)
re-did old pull requests (#172)
Tsl2561 rewrite (#174)
I2csoilmoisture fixed bug with sleep mode (#178)
Pulsecounter minor fix (#184)
rewrote bh1750 sensor based on better library... (#182)
cppcheck style fixes... (#186)
added i2c address selection to ino219 plugin (#192)
Motorshield plugin string fixes (#200) (reduced memory usage)
Support for Tcs34725 RGB Color Sensor (#195)
_P047_i2c-soil-moisture-sensor: allow change of sensor address (#201)
Httpadvanced crashfix + patch method (#204)
Bh1750: enhance to check for valid value (#208)
removed all unnecessary Strings due to new addLog with FlashStringHelper (#223)
tedenda (1):
Update _P049_MHZ19.ino
-----------------------------
Changes in release v2.0.0-dev7
-----------------------------
Release date: Wed Mar 15 01:42:15 CET 2017
Edwin Eefting (5):
timers can be disabled by setting them to 0 now. cleaned up event output logging. added timer out-of-bounds checks
added i2scanner via serial. removed spaces from Adafruit Motor Shield library so it works with arduino IDE
fixed Arduino IDE compilebug and added help to enable plugin sets in Arduino IDE
automaticly updated release notes for v2.0.0-dev7
fix in release-script (forgot to commit it last time)
krikk (2):
code cleanup for HTTP advanced controller
show date in webinterface, and changed password fields to type=password (#161)
-----------------------------
Changes in release v2.0.0-dev6
-----------------------------
Release date: Mon Mar 13 11:54:41 CET 2017
Edwin Eefting (15):
created script to assist in creating releases
bug fix: plugin_id should not start with a 0. (compiler interprets this as octal!)
Revert "bug fix: plugin_id should not start with a 0. (compiler interprets this as octal!)"
bug fix: plugin_id should not start with a 0. (compiler interprets this as octal!)
added NDIR CO2 Sensor MH-Z19 plugin to TESTING plugin set
remove artificial sensor startup delays. (now all sensors are send immediatly after booting and wifi-connecting)
do hardwareinit() earlier so that outputs are set immeadiatly instead of waiting for connect. fixes https://github.com/letscontrolit/ESPEasy/issues/114
enable status light as soon as wifi is connected
use sizeof instead of magic numbers
Implemented speaker and tone functions from https://www.letscontrolit.com/forum/viewtopic.php?f=4&t=343&hilit=speaker&start=10
enabled Arduino OTA for dev-firmware only, to ease developing. minor output-tweaks
cold boot startup delay
major change: changed the timing of the first sensor read after initial boot. cleaned up and improved deep sleeping code.
added plugin to testing. remove useless value variable
automaticly updated release notes for v2.0.0-dev6
Gerald (2):
HTTP Advanced, enhanced, so that only one http request is sent for one sensor (#156)
added missing sensor type, to fix problem with i2c soilmoisture sensor... (#157)
Jochen Krapf (1):
cancel deep sleep loop by pulling the pin GPIO16(D0) to GND (#158)
dzikus (1):
Added BMP280_CONFIG_SETTING to reduce the temperature of sensor and use oversampling filter (#155)
-----------------------------
Changes in release v2.0.0-dev5
-----------------------------
Release date: Sat Mar 11 18:15:59 CET 2017
DatuX (5):
Update README.md
Update README.md
Update README.md
Update README.md
Update README.md
Edwin Eefting (7):
deploy in platformio format
simplified string handling and fixed buffer overflow
created release notes from R148 to v2.0.0-dev4
updated release notes for test1
BUILD_GIT is now defined via environement variables
use TRAVIS_TAG when building releases
automaticly updated release notes for v2.0.0-dev5
Gerald (3):
Update _P047_i2c-soil-moisture-sensor.ino
one newline to much
add missing features from "Generic HTTP" Plugin to "Generic HTTP Advanced" Plugin (#151)
Gustavo Spadari (3):
Adding IR received code extra info
Rename tmpString to cmdCode for clarity
IR RAW Code implementation
JustMe-NL (4):
Fix double define
Fix Windspeed values
Fix broken Domoticz MQTT helper
Update WebServer.ino
Nonflammable (1):
Extend functionality of P038
krikk (7):
new Plugin for SoilMoisturesensor from Tindie (https://www.tindie.com/products/miceuz/i2c-soil-moisture-sensor/) minor fixes in http advanced to allow sensor type triple and http response 2xx not 200 only
version check to detect if sensor is present, optimized address handling
added measurement mode selection
minor fix, shared variable name with bme280, not good :)
variable name collision with adafruit motorshield v2 library, no functional change
new plugin for adafruit motorshield v2, still needs a library and only support DC Motors up till now... still room for improvement
added function to enable/disable sleep mode and version check
psy0rztest (1):
Removed !echo, because its not supported in Windows.
---------------------------------
Changes in v2.0.0-dev4 since R148
---------------------------------
Edwin Eefting (18):
copy from ESPEasyMega commit 33f31e1fc3a9736266e9ee4781947d01808f88d6 but without the file renames
bugfix in p036: pointer was not initialized to NULL
added git version numbers output
_C001 Sent humstat to domoticz
fixed logging during first time initialisation
factory reset will now always format SPIFFS. earlier boot logging
fix factory reset by tx/rx pin double reset issue
this was only a temporary test, forgot to remove
turn on weblog by default
uninitialised var
removed systemOK: its not used anymore since SPIFFS support. (when system is not ok, it already did a resetfactory and reboots instead of continuing in emergency mode
fixed building on systems other that platformio+linux (by making sure BUILD_GIT is defined)
rename to .ino
moving source files to src, in preperation of platformio directory structure
platformio settings, travis settings, flashtools for windows, deploy script to create release .zip file
add libraries as submodules
add libraries we slightly modified or that i cant find the repositorys for
new deploy key
JustMe-NL (6):
Update ESPEasy.ino
Update Misc.ino
Update _C001.ino
Update _C002.ino
Create _P045_MPU6050
Create _P046_VentusW266
BIN
View File
Binary file not shown.
-59
View File
@@ -1,59 +0,0 @@
#include "AM2320.h"
#include <Wire.h>
//
// AM2321 Temperature & Humidity Sensor library for Arduino
// Сделана Тимофеевым Е.Н. из AM2320-master
unsigned int CRC16(byte *ptr, byte length)
{
unsigned int crc = 0xFFFF;
uint8_t s = 0x00;
while(length--) {
crc ^= *ptr++;
for(s = 0; s < 8; s++) {
if((crc & 0x01) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else crc >>= 1;
}
}
return crc;
}
AM2320::AM2320()
{
}
int AM2320::Read()
{
byte buf[8];
for(int s = 0; s < 8; s++) buf[s] = 0x00;
Wire.beginTransmission(AM2320_address);
Wire.endTransmission();
// запрос 4 байт (температуры и влажности)
Wire.beginTransmission(AM2320_address);
Wire.write(0x03);// запрос
Wire.write(0x00); // с 0-го адреса
Wire.write(0x04); // 4 байта
if (Wire.endTransmission(1) != 0) return 1;
delayMicroseconds(1600); //>1.5ms
// считываем результаты запроса
Wire.requestFrom(AM2320_address, 0x08);
for (int i = 0; i < 0x08; i++) buf[i] = Wire.read();
// CRC check
unsigned int Rcrc = buf[7] << 8;
Rcrc += buf[6];
if (Rcrc == CRC16(buf, 6)) {
unsigned int temperature = ((buf[4] & 0x7F) << 8) + buf[5];
t = temperature / 10.0;
t = ((buf[4] & 0x80) >> 7) == 1 ? t * (-1) : t;
unsigned int humidity = (buf[2] << 8) + buf[3];
h = humidity / 10.0;
return 0;
}
return 2;
}
-17
View File
@@ -1,17 +0,0 @@
#ifndef AM2320_H
#define AM2320_H
#include <Arduino.h>
#define AM2320_address (0xB8 >> 1)
class AM2320
{
public:
AM2320();
float t;
float h;
int Read(void);
};
#endif
@@ -1,29 +0,0 @@
#include <Wire.h>
#include <AM2320.h>
AM2320 th;
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
switch(th.Read()) {
case 2:
Serial.println("CRC failed");
break;
case 1:
Serial.println("Sensor offline");
break;
case 0:
Serial.print("humidity: ");
Serial.print(th.h);
Serial.print("%, temperature: ");
Serial.print(th.t);
Serial.println("*C");
break;
}
delay(200);
}
-4
View File
@@ -1,4 +0,0 @@
AM2320 KEYWORD1
getTemperature KEYWORD2
getHumidity KEYWORD2
CRCCheck KEYWORD2
-13
View File
@@ -1,13 +0,0 @@
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a
-476
View File
@@ -1,476 +0,0 @@
/*
This is a (Arduino) library for the BH1750FVI Digital Light Sensor.
Description:
http://www.rohm.com/web/global/products/-/product/BH1750FVI
Datasheet:
http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
Copyright (c) 2013 Alexander Schulz. All right reserved.
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "AS_BH1750.h"
// Debug-Flag
#define BH1750_DEBUG 0
/**
* Constructor.
* Erlaubt die I2C-Adresse des Sensors zu ändern.
* Standardadresse: 0x23, Alternativadresse: 0x5C.
* Es sind entsprechende Konstanten definiert: BH1750_DEFAULT_I2CADDR und BH1750_SECOND_I2CADDR.
* Bei Nichtangabe wird die Standardadresse verwendet.
* Um die Alternativadresse zu nutzen, muss der Sensorpin 'ADR' des Chips auf VCC gelegt werden.
*/
AS_BH1750::AS_BH1750(uint8_t address) {
_address = address;
_hardwareMode = 255;
}
/**
* Führt die anfängliche Initialisierung des Sensors.
* Mögliche Parameter:
* - Modus für die Sensorauflösung:
* -- RESOLUTION_LOW: Physische Sensormodus mit 4 lx Auflösung. Messzeit ca. 16ms. Bereich 0-54612.
* -- RESOLUTION_NORMAL: Physische Sensormodus mit 1 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* -- RESOLUTION_HIGH: Physische Sensormodus mit 0,5 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* (Die Messbereiche können durch Änderung des MTreg verschoben werden.)
* -- RESOLUTION_AUTO_HIGH: Die Werte im MTreg werden je nach Helligkeit automatisch so angepasst,
* dass eine maximalmögliche Auflösung und Messbereich erziehlt werden.
* Die messbaren Werte fangen von 0,11 lx und gehen bis über 100000 lx.
* (ich weis nicht, wie genau die Werte in Grenzbereichen sind,
* besonders bei hohen Werte habe ich da meine Zweifel.
* Die Werte scheinen jedoch weitgehend linear mit der steigenden Helligkeit zu wachsen.)
* Auflösung im Unteren Bereich ca. 0,13 lx, im mittleren 0,5 lx, im oberen etwa 1-2 lx.
* Die Messzeiten verlängern sich durch mehrfache Messungen und
* die Änderungen von Measurement Time (MTreg) bis max. ca. 500 ms.
*
* - AutoPowerDown: true = Der Sensor wird nach der Messung in den Stromsparmodus versetzt.
* Das spätere Aufwecken wird ggf. automatisch vorgenommen, braucht jedoch geringfügig mehr Zeit.
*
* Defaultwerte: RESOLUTION_AUTO_HIGH, true
*
*/
bool AS_BH1750::begin(sensors_resolution_t mode, bool autoPowerDown) {
#if BH1750_DEBUG == 1
Serial.print(" sensors_resolution_mode (virtual): ");
Serial.println(mode, DEC);
#endif
_virtualMode = mode;
_autoPowerDown = autoPowerDown;
Wire.begin();
defineMTReg(BH1750_MTREG_DEFAULT); // eigentlich normalerweise unnötig, da standard
// Hardware-Modus zum gewünschten VitrualModus ermitteltn
switch (_virtualMode) {
case RESOLUTION_LOW:
_hardwareMode = autoPowerDown?BH1750_ONE_TIME_LOW_RES_MODE:BH1750_CONTINUOUS_LOW_RES_MODE;
break;
case RESOLUTION_NORMAL:
_hardwareMode = autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE;
break;
case RESOLUTION_HIGH:
_hardwareMode = autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2;
break;
case RESOLUTION_AUTO_HIGH:
_hardwareMode = BH1750_CONTINUOUS_LOW_RES_MODE;
break;
default:
// darf eigentlich nicht passieren...
_hardwareMode = 255;
break;
}
#if BH1750_DEBUG == 1
Serial.print("hardware mode: ");
Serial.println(_hardwareMode, DEC);
#endif
if(_hardwareMode==255) {
return false;
}
// Versuchen, den gewählten Hardwaremodus zu aktivieren
if(selectResolutionMode(_hardwareMode)){
#if BH1750_DEBUG == 1
Serial.print("hardware mode defined successfully");
Serial.println(_hardwareMode, DEC);
#endif
return true;
}
// Initialisierung fehlgeschlagen
#if BH1750_DEBUG == 1
Serial.print("failure to aktivate hardware mode ");
Serial.println(_hardwareMode, DEC);
#endif
_hardwareMode = 255;
return false;
}
/**
* Erlaub eine Prüfung, ob ein (ansprechbarer) BH1750-Sensor vorhanden ist.
*/
bool AS_BH1750::isPresent() {
// Check I2C Adresse
Wire.beginTransmission(_address);
if(Wire.endTransmission()!=0) {
return false;
}
// Check device: ist es ein BH1750
if(!isInitialized()) {
// zuvor inaktiv, daher zu Testen schnelltes einmal-Mode aktivieren
//write8(BH1750_POWER_ON);
selectResolutionMode(BH1750_ONE_TIME_LOW_RES_MODE);
_hardwareMode=255;
}
else {
// falls einmal-modus aktiv war, muss der Sensor geweckt werden
powerOn();
}
// Prüfen, ob Werte auch wirklich geliefert werden (letztes Modus, ggf. wird auto-PowerDown ausgeführt)
return (readLightLevel()>=0);
}
/**
* Weckt ein im PowerDown-Modus befindlichen Sensor auf (schadet auch dem 'wachen' Sensor nicht).
* Funktionier nur, wenn der Sensor bereits initialisiert wurde.
*/
void AS_BH1750::powerOn() {
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return;
}
_valueReaded=false;
//write8(BH1750_POWER_ON); //
//fDelayPtr(10); // Nötig?
// Scheinbar reicht das Setzen von HardwareMode auch ohne PowerON-Befehl aus
selectResolutionMode(_hardwareMode); // letzten Modus wieder aktivieren
}
/**
* Schickt den Sensor in Stromsparmodus.
* Funktionier nur, wenn der Sensor bereits initialisiert wurde.
*/
void AS_BH1750::powerDown() {
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return;
}
write8(BH1750_POWER_DOWN);
}
/**
* Sendet zum Sensor ein Befehl zum Auswahl von HardwareMode.
*
* Parameter:
* - mode: s.o.
* - DelayFuncPtr: delay(n) Möglichkeit, eigene Delay-Funktion mitzugeben (z.B. um sleep-Modus zu verwenden).
*
* Defaultwerte: delay()
*
*/
bool AS_BH1750::selectResolutionMode(uint8_t mode, DelayFuncPtr fDelayPtr) {
#if BH1750_DEBUG == 1
Serial.print("selectResolutionMode: ");
Serial.println(mode, DEC);
#endif
if(!isInitialized()) {
return false;
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
}
_hardwareMode=mode;
_valueReaded=false;
// Prüfen, ob ein valides Modus vorliegt und im positiven Fall das gewünschte Modus aktivieren
switch (mode) {
case BH1750_CONTINUOUS_HIGH_RES_MODE:
case BH1750_CONTINUOUS_HIGH_RES_MODE_2:
case BH1750_CONTINUOUS_LOW_RES_MODE:
case BH1750_ONE_TIME_HIGH_RES_MODE:
case BH1750_ONE_TIME_HIGH_RES_MODE_2:
case BH1750_ONE_TIME_LOW_RES_MODE:
// Modus aktivieren
if(write8(mode)) {
// Kurze pause nötig, sonst wird das Modus nicht sicher Aktiviert
// (z.B. liefert Sensor im AutoHigh Modus abwechselnd übersteuerte Werte, etwa so: 54612.5, 68123.4, 54612.5, 69345.3,..)
fDelayPtr(5);
return true;
}
break;
default:
// Invalid measurement mode
#if BH1750_DEBUG == 1
Serial.println("Invalid measurement mode");
#endif
break;
}
return false;
}
/**
* Liefert aktuell gemessenen Wert für Helligkeit in lux (lx).
* Falls sich der Sensorf in Stromsparmodus befindet, wird er automatisch geweckt.
*
* Wurde der Sensor (noch) nicht initialisiert (begin), wird der Wert -1 geliefert.
*/
float AS_BH1750::readLightLevel(DelayFuncPtr fDelayPtr) {
#if BH1750_DEBUG == 1
Serial.print("call: readLightLevel. virtualMode: ");
Serial.println(_virtualMode, DEC);
#endif
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return -1;
}
// ggf. PowerOn
if(_autoPowerDown && _valueReaded){
powerOn();
}
// Das Automatische Modus benötigt eine Sonderbehandlung.
// Zuerst wird die Helligkeit im LowRes-Modus gelesen,
// je nach Bereich (dunkel, normal, sehr hell) werden die Werte von MTreg gesetzt und
// danach wird die eigentliche Messung vorgenommen.
/*
Die feste Grenzwerte verursachen möglicherweise einen 'Sprung' in der Messkurve.
In diesem Fall wäre eine laufende Anpassung von MTreg in Grenzbereichen vermutlich besser.
Für meine Zwecke ist das jedoch ohne Bedeutung.
*/
if(_virtualMode==RESOLUTION_AUTO_HIGH) {
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(BH1750_CONTINUOUS_LOW_RES_MODE, fDelayPtr);
fDelayPtr(16); // Lesezeit in LowResMode
uint16_t level = readRawLevel();
#if BH1750_DEBUG == 1
Serial.print("AutoHighMode: check level read: ");
Serial.println(level, DEC);
#endif
if(level<10) {
#if BH1750_DEBUG == 1
Serial.println("level 0: dark");
#endif
// Dunkel, Empfindlichkeit auf Maximum.
// Der Wert ist zufällig. Ab ca. 16000 wäre diese Vorgehnsweise möglich.
// Ich brauche diese Genauigkeit aber nur in den ganz dunklen Bereichen (zu erkennen, wann wirklich 'dunkel' ist).
defineMTReg(BH1750_MTREG_MAX);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2, fDelayPtr);
fDelayPtr(120*3.68); // TODO: Wert prüfen
//fDelayPtr(122);
}
else if(level<32767) {
#if BH1750_DEBUG == 1
Serial.println("level 1: normal");
#endif
// Bis hierher reicht die 0,5 lx Modus. Normale Empfindlichkeit.
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2, fDelayPtr);
fDelayPtr(120); // TODO: Wert prüfen
}
else if(level<60000) {
#if BH1750_DEBUG == 1
Serial.println("level 2: bright");
#endif
// hoher Bereich, 1 lx Modus, normale Empfindlichkeit. Der Wert von 60000 ist mehr oder weniger zufällig, es mus einfach ein hoher Wert, nah an der Grenze sein.
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE, fDelayPtr);
fDelayPtr(120); // TODO: Wert prüfen
}
else {
#if BH1750_DEBUG == 1
Serial.println("level 3: very bright");
#endif
// sehr hoher Bereich, Empfindlichkeit verringern
defineMTReg(32); // Min+1, bei dem Minimum aus Doku spielt der Sensor (zumindest meiner) verrückt: Die Werte sind ca. 1/10 von den Erwarteten.
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE, fDelayPtr);
fDelayPtr(120); // TODO: Wert prüfen
}
}
// Hardware Wert lesen und in Lux umrechnen.
uint16_t raw = readRawLevel();
if(raw==65535) {
// Wert verdächtig hoch. Sensor prüfen.
// Check I2C Adresse
Wire.beginTransmission(_address);
if(Wire.endTransmission()!=0) {
return -1;
}
}
return convertRawValue(raw);
}
/**
* Roh-Wert der Helligkeit auslesen.
* Wertebereich 0-65535.
*/
uint16_t AS_BH1750::readRawLevel(void) {
uint16_t level;
Wire.beginTransmission(_address);
Wire.requestFrom(_address, 2);
#if (ARDUINO >= 100)
level = Wire.read();
level <<= 8;
level |= Wire.read();
#else
level = Wire.receive();
level <<= 8;
level |= Wire.receive();
#endif
if(Wire.endTransmission()!=0) {
#if BH1750_DEBUG == 1
Serial.println("I2C read error");
#endif
return 65535; // Error marker
}
#if BH1750_DEBUG == 1
Serial.print("Raw light level: ");
Serial.println(level);
#endif
_valueReaded=true;
return level;
}
/**
* Rechnet Roh-Werte in Lux um.
*/
float AS_BH1750::convertRawValue(uint16_t raw) {
// Basisumrechnung
float flevel = raw/1.2;
#if BH1750_DEBUG == 1
Serial.print("convert light level (1): ");
Serial.println(flevel);
#endif
// MTreg-Einfluss berechnen
if(_MTreg!=BH1750_MTREG_DEFAULT) { // bei 69 ist der Faktor = 1
flevel = flevel * _MTregFactor;
#if BH1750_DEBUG == 1
Serial.print("convert light level (2): ");
Serial.println(flevel);
#endif
}
// je nach Modus ist eine weitere Umrechnung nötig
switch (_hardwareMode) {
case BH1750_CONTINUOUS_HIGH_RES_MODE_2:
case BH1750_ONE_TIME_HIGH_RES_MODE_2:
flevel = flevel/2;
#if BH1750_DEBUG == 1
Serial.print("convert light level (3): ");
Serial.println(flevel);
#endif
break;
default:
// nothing to do
break;
}
#if BH1750_DEBUG == 1
Serial.print("Light level: ");
Serial.println(flevel);
#endif
return flevel;
}
/**
* MTreg setzen. Definiert Empfindlichkeit des Sensors.
* Min.Wert (BH1750_MTREG_MIN) = 31 (Empfindlichkeit: default*0,45)
* Max.Wert (BH1750_MTREG_MAX) = 254 (Empfindlichkeit: default*3,68)
* Default (BH1750_MTREG_DEFAULT) = 69.
* Mit der Empfindlichkeit verändert sich die Lesezeit (höhere Empfindlichkeit bedeutet längere Zeitspanne).
*/
void AS_BH1750::defineMTReg(uint8_t val) {
if(val<BH1750_MTREG_MIN) {
val = BH1750_MTREG_MIN;
}
if(val>BH1750_MTREG_MAX) {
val = BH1750_MTREG_MAX;
}
if(val!=_MTreg) {
_MTreg = val;
_MTregFactor = (float)BH1750_MTREG_DEFAULT / _MTreg;
// Change Measurement time
// Übertragung in zwei Schritten: 3 Bit und 5 Bit, jeweils mit einem Prefix.
// High bit: 01000_MT[7,6,5]
// Low bit: 011_MT[4,3,2,1,0]
uint8_t hiByte = val>>5;
hiByte |= 0b01000000;
#if BH1750_DEBUG == 1
Serial.print("MGTreg high byte: ");
Serial.println(hiByte, BIN);
#endif
write8(hiByte);
//fDelayPtr(10);
// Pause nötig?
uint8_t loByte = val&0b00011111;
loByte |= 0b01100000;
#if BH1750_DEBUG == 1
Serial.print("MGTreg low byte: ");
Serial.println(loByte, BIN);
#endif
write8(hiByte);
//fDelayPtr(10);
}
}
/**
* Gibt an, ob der Sensor initialisiert ist.
*/
bool AS_BH1750::isInitialized() {
return _hardwareMode!=255;
}
/**
* Schreibt ein Byte auf I2C Bus (auf die Adresse des Sensors).
*/
bool AS_BH1750::write8(uint8_t d) {
Wire.beginTransmission(_address);
#if (ARDUINO >= 100)
Wire.write(d);
#else
Wire.send(d);
#endif
return (Wire.endTransmission()==0);
}
-183
View File
@@ -1,183 +0,0 @@
/*
This is a (Arduino) library for the BH1750FVI Digital Light Sensor.
Description:
http://www.rohm.com/web/global/products/-/product/BH1750FVI
Datasheet:
http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
Copyright (c) 2013 Alexander Schulz. All right reserved.
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AS_BH1750_h
#define AS_BH1750_h
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include "Wire.h"
// Mögliche I2C Adressen
#define BH1750_DEFAULT_I2CADDR 0x23
#define BH1750_SECOND_I2CADDR 0x5C
// MTreg Werte
// Default
#define BH1750_MTREG_DEFAULT 69
// Sensitivity : default = 0.45
#define BH1750_MTREG_MIN 31
// Sensitivity : default = 3.68
#define BH1750_MTREG_MAX 254
// Hardware Modi
// No active state
#define BH1750_POWER_DOWN 0x00
// Wating for measurment command
#define BH1750_POWER_ON 0x01
// Reset data register value - not accepted in POWER_DOWN mode
#define BH1750_RESET 0x07
// Start measurement at 1lx resolution. Measurement time is approx 120ms.
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10
// Start measurement at 0.5lx resolution. Measurement time is approx 120ms.
#define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11
// Start measurement at 4lx resolution. Measurement time is approx 16ms.
#define BH1750_CONTINUOUS_LOW_RES_MODE 0x13
// Start measurement at 1lx resolution. Measurement time is approx 120ms.
// Device is automatically set to Power Down after measurement.
#define BH1750_ONE_TIME_HIGH_RES_MODE 0x20
// Start measurement at 0.5lx resolution. Measurement time is approx 120ms.
// Device is automatically set to Power Down after measurement.
#define BH1750_ONE_TIME_HIGH_RES_MODE_2 0x21
// Start measurement at 1lx resolution. Measurement time is approx 120ms.
// Device is automatically set to Power Down after measurement.
#define BH1750_ONE_TIME_LOW_RES_MODE 0x23
/** Virtual Modi */
typedef enum
{
RESOLUTION_LOW = (1), /** 4lx resolution. Measurement time is approx 16ms. */
RESOLUTION_NORMAL = (2), /** 1lx resolution. Measurement time is approx 120ms. */
RESOLUTION_HIGH = (3), /** 0,5lx resolution. Measurement time is approx 120ms. */
RESOLUTION_AUTO_HIGH = (99) /** 0,11-1lx resolution. Measurement time is above 250ms. */
}
sensors_resolution_t;
typedef void (*DelayFuncPtr)(unsigned long);
typedef unsigned long (*TimeFuncPtr)(void);
/**
* BH1750 driver class.
*/
class AS_BH1750 {
public:
/**
* Constructor.
* Erlaubt die I2C-Adresse des Sensors zu ändern.
* Standardadresse: 0x23, Alternativadresse: 0x5C.
* Es sind entsprechende Konstanten definiert: BH1750_DEFAULT_I2CADDR und BH1750_SECOND_I2CADDR.
* Bei Nichtangabe wird die Standardadresse verwendet.
* Um die Alternativadresse zu nutzen, muss der Sensorpin 'ADR' des Chips auf VCC gelegt werden.
*/
AS_BH1750(uint8_t address = BH1750_DEFAULT_I2CADDR);
/**
* Führt die anfängliche Initialisierung des Sensors.
* Mögliche Parameter:
* - Modus für die Sensorauflösung:
* -- RESOLUTION_LOW: Physische Sensormodus mit 4 lx Auflösung. Messzeit ca. 16ms. Bereich 0-54612.
* -- RESOLUTION_NORMAL: Physische Sensormodus mit 1 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* -- RESOLUTION_HIGH: Physische Sensormodus mit 0,5 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* (Die Messbereiche können durch Änderung des MTreg verschoben werden.)
* -- RESOLUTION_AUTO_HIGH: Die Werte im MTreg werden je nach Helligkeit automatisch so angepasst,
* dass eine maximalmögliche Auflösung und Messbereich erziehlt werden.
* Die messbaren Werte fangen von 0,11 lx und gehen bis über 100000 lx.
* (ich weis nicht, wie genau die Werte in Grenzbereichen sind,
* besonders bei hohen Werte habe ich meine Zweifel.)
* Auflösung im Unteren Bereich 0,13 lx, im mittleren 0,5 lx, im oberen 1-2 lx.
* Die Messzeiten verlängern sich durch mehrfache Messungen und
* die Änderungen von Measurement Time (MTreg) bis max. ca. 500 ms.
*
* - AutoPowerDown: true = Der Sensor wird nach der Messung in den Stromsparmodus versetzt.
* Das spätere Aufwecken wird ggf. automatisch vorgenommen, braucht jedoch geringfügig mehr Zeit.
*
* Defaultwerte: RESOLUTION_AUTO_HIGH, true, delay()
*
*/
bool begin(sensors_resolution_t mode = RESOLUTION_AUTO_HIGH, bool autoPowerDown = true);
/**
* Erlaub eine Prüfung, ob ein (ansprechbarer) BH1750-Sensor vorhanden ist.
*/
bool isPresent(void);
/**
* Liefert aktuell gemessenen Wert für Helligkeit in lux (lx).
* Falls sich der Sensorf in Stromsparmodus befindet, wird er automatisch geweckt.
*
* Wurde der Sensor (noch) nicht initialisiert (begin), wird der Wert -1 geliefert.
*
* Mögliche Parameter:
*
* - DelayFuncPtr: delay(n) Möglichkeit, eigene Delay-Funktion mitzugeben (z.B. um sleep-Modus zu verwenden).
*
* Defaultwerte: delay()
*
*/
float readLightLevel(DelayFuncPtr fDelayPtr = &delay);
/**
* Schickt den Sensor in Stromsparmodus.
* Funktionier nur, wenn der Sensor bereits initialisiert wurde.
*/
void powerDown(void);
private:
int _address;
uint8_t _hardwareMode;
uint8_t _MTreg;
float _MTregFactor;
sensors_resolution_t _virtualMode;
bool _autoPowerDown;
bool _valueReaded;
bool selectResolutionMode(uint8_t mode, DelayFuncPtr fDelayPtr = &delay);
void defineMTReg(uint8_t val);
void powerOn(void);
void reset(void);
uint16_t readRawLevel(void);
float convertRawValue(uint16_t raw);
bool isInitialized();
bool write8(uint8_t data);
};
#endif
-705
View File
@@ -1,705 +0,0 @@
/*
This is a (Arduino) library for the BH1750FVI Digital Light Sensor.
Description:
http://www.rohm.com/web/global/products/-/product/BH1750FVI
Datasheet:
http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
Copyright (c) 2013 Alexander Schulz. All right reserved.
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "AS_BH1750A.h"
// Debug-Flag
#define BH1750_DEBUG 0
/**
* Constructor.
* Erlaubt die I2C-Adresse des Sensors zu ändern.
* Standardadresse: 0x23, Alternativadresse: 0x5C.
* Es sind entsprechende Konstanten definiert: BH1750_DEFAULT_I2CADDR und BH1750_SECOND_I2CADDR.
* Bei Nichtangabe wird die Standardadresse verwendet.
* Um die Alternativadresse zu nutzen, muss der Sensorpin 'ADR' des Chips auf VCC gelegt werden.
*/
AS_BH1750A::AS_BH1750A(uint8_t address) {
_address = address;
_hardwareMode = 255;
}
/**
* Führt die anfängliche Initialisierung des Sensors.
* Mögliche Parameter:
* - Modus für die Sensorauflösung:
* -- RESOLUTION_LOW: Physische Sensormodus mit 4 lx Auflösung. Messzeit ca. 16ms. Bereich 0-54612.
* -- RESOLUTION_NORMAL: Physische Sensormodus mit 1 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* -- RESOLUTION_HIGH: Physische Sensormodus mit 0,5 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* (Die Messbereiche können durch Änderung des MTreg verschoben werden.)
* -- RESOLUTION_AUTO_HIGH: Die Werte im MTreg werden je nach Helligkeit automatisch so angepasst,
* dass eine maximalmögliche Auflösung und Messbereich erziehlt werden.
* Die messbaren Werte fangen von 0,11 lx und gehen bis über 100000 lx.
* (ich weis nicht, wie genau die Werte in Grenzbereichen sind,
* besonders bei hohen Werte habe ich da meine Zweifel.
* Die Werte scheinen jedoch weitgehend linear mit der steigenden Helligkeit zu wachsen.)
* Auflösung im Unteren Bereich ca. 0,13 lx, im mittleren 0,5 lx, im oberen etwa 1-2 lx.
* Die Messzeiten verlängern sich durch mehrfache Messungen und
* die Änderungen von Measurement Time (MTreg) bis max. ca. 500 ms.
*
* - AutoPowerDown: true = Der Sensor wird nach der Messung in den Stromsparmodus versetzt.
* Das spätere Aufwecken wird ggf. automatisch vorgenommen, braucht jedoch geringfügig mehr Zeit.
*
* Defaultwerte: RESOLUTION_AUTO_HIGH, true
*
*/
bool AS_BH1750A::begin(sensors_resolution_t mode, bool autoPowerDown) {
#if BH1750_DEBUG == 1
Serial.print(" sensors_resolution_mode (virtual): ");
Serial.println(mode, DEC);
#endif
_virtualMode = mode;
_autoPowerDown = autoPowerDown;
Wire.begin();
defineMTReg(BH1750_MTREG_DEFAULT); // eigentlich normalerweise unnötig, da standard
// Hardware-Modus zum gewünschten VitrualModus ermitteltn
switch (_virtualMode) {
case RESOLUTION_LOW:
_hardwareMode = autoPowerDown?BH1750_ONE_TIME_LOW_RES_MODE:BH1750_CONTINUOUS_LOW_RES_MODE;
break;
case RESOLUTION_NORMAL:
_hardwareMode = autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE;
break;
case RESOLUTION_HIGH:
_hardwareMode = autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2;
break;
case RESOLUTION_AUTO_HIGH:
_hardwareMode = BH1750_CONTINUOUS_LOW_RES_MODE;
break;
default:
// darf eigentlich nicht passieren...
_hardwareMode = 255;
break;
}
#if BH1750_DEBUG == 1
Serial.print("hardware mode: ");
Serial.println(_hardwareMode, DEC);
#endif
if(_hardwareMode==255) {
return false;
}
// Versuchen, den gewählten Hardwaremodus zu aktivieren
if(selectResolutionMode(_hardwareMode)){
#if BH1750_DEBUG == 1
Serial.print("hardware mode defined successfully");
Serial.println(_hardwareMode, DEC);
#endif
return true;
}
// Initialisierung fehlgeschlagen
#if BH1750_DEBUG == 1
Serial.print("failure to aktivate hardware mode ");
Serial.println(_hardwareMode, DEC);
#endif
_hardwareMode = 255;
return false;
}
/**
* Erlaub eine Prüfung, ob ein (ansprechbarer) BH1750-Sensor vorhanden ist.
*/
bool AS_BH1750A::isPresent() {
// Check I2C Adresse
Wire.beginTransmission(_address);
if(Wire.endTransmission()!=0) {
return false;
}
// Check device: ist es ein BH1750
if(!isInitialized()) {
// zuvor inaktiv, daher zu Testen schnelltes einmal-Mode aktivieren
//write8(BH1750_POWER_ON);
selectResolutionMode(BH1750_ONE_TIME_LOW_RES_MODE);
delay(5);// Hier muss man in jedem Fall warten, daher die kurze Pause erstmal ok
_hardwareMode=255;
}
else {
// falls einmal-modus aktiv war, muss der Sensor geweckt werden
powerOn();
unsigned long dd = getModeDelay(); if(dd>0) {delay(dd);}
//delay(getModeDelay()); // s.o.
}
// Prüfen, ob Werte auch wirklich geliefert werden (letztes Modus, ggf. wird auto-PowerDown ausgeführt)
return (readLightLevel()>=0);
}
/**
* Weckt ein im PowerDown-Modus befindlichen Sensor auf (schadet auch dem 'wachen' Sensor nicht).
* Funktionier nur, wenn der Sensor bereits initialisiert wurde.
*/
void AS_BH1750A::powerOn() {
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return;
}
_valueReaded=false;
//write8(BH1750_POWER_ON); //
//fDelayPtr(10); // Nötig?
// Scheinbar reicht das Setzen von HardwareMode auch ohne PowerON-Befehl aus
selectResolutionMode(_hardwareMode); // letzten Modus wieder aktivieren
}
/**
* Schickt den Sensor in Stromsparmodus.
* Funktionier nur, wenn der Sensor bereits initialisiert wurde.
*/
void AS_BH1750A::powerDown() {
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return;
}
write8(BH1750_POWER_DOWN);
}
/**
* Sendet zum Sensor ein Befehl zum Auswahl von HardwareMode.
*
* Parameter:
* - mode: s.o.
* - DelayFuncPtr: delay(n) Möglichkeit, eigene Delay-Funktion mitzugeben (z.B. um sleep-Modus zu verwenden).
*
* Defaultwerte: delay()
*
*/
bool AS_BH1750A::selectResolutionMode(uint8_t mode) {
#if BH1750_DEBUG == 1
Serial.print("selectResolutionMode: ");
Serial.println(mode, DEC);
#endif
if(!isInitialized()) {
return false;
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
}
_hardwareMode=mode;
_valueReaded=false;
// Prüfen, ob ein valides Modus vorliegt und im positiven Fall das gewünschte Modus aktivieren
switch (mode) {
case BH1750_CONTINUOUS_HIGH_RES_MODE:
case BH1750_CONTINUOUS_HIGH_RES_MODE_2:
case BH1750_CONTINUOUS_LOW_RES_MODE:
case BH1750_ONE_TIME_HIGH_RES_MODE:
case BH1750_ONE_TIME_HIGH_RES_MODE_2:
case BH1750_ONE_TIME_LOW_RES_MODE:
// Modus aktivieren
if(write8(mode)) {
// Kurze pause nötig, sonst wird das Modus nicht sicher Aktiviert
// (z.B. liefert Sensor im AutoHigh Modus abwechselnd übersteuerte Werte, etwa so: 54612.5, 68123.4, 54612.5, 69345.3,..)
//fDelayPtr(5); => Aufrufer soll 5ms extra warten
return true;
}
break;
default:
// Invalid measurement mode
#if BH1750_DEBUG == 1
Serial.println("Invalid measurement mode");
#endif
break;
}
return false;
}
/**
* Liefert aktuell gemessenen Wert für Helligkeit in lux (lx).
* Falls sich der Sensorf in Stromsparmodus befindet, wird er automatisch geweckt.
*
* Wurde der Sensor (noch) nicht initialisiert (begin), wird der Wert -1 geliefert.
*/
/*float AS_BH1750A::readLightLevel_alt(DelayFuncPtr fDelayPtr) {
#if BH1750_DEBUG == 1
Serial.print("call: readLightLevel. virtualMode: ");
Serial.println(_virtualMode, DEC);
#endif
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return -1;
}
// ggf. PowerOn
if(_autoPowerDown && _valueReaded){
powerOn();
unsigned long dd = getModeDelay(); if(dd>0) {delay(dd);}
}
// Das Automatische Modus benötigt eine Sonderbehandlung.
// Zuerst wird die Helligkeit im LowRes-Modus gelesen,
// je nach Bereich (dunkel, normal, sehr hell) werden die Werte von MTreg gesetzt und
// danach wird die eigentliche Messung vorgenommen.
// Die feste Grenzwerte verursachen möglicherweise einen 'Sprung' in der Messkurve.
// In diesem Fall wäre eine laufende Anpassung von MTreg in Grenzbereichen vermutlich besser.
// Für meine Zwecke ist das jedoch ohne Bedeutung.
if(_virtualMode==RESOLUTION_AUTO_HIGH) {
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(BH1750_CONTINUOUS_LOW_RES_MODE);
//fDelayPtr(16+5); // Lesezeit in LowResMode
fDelayPtr(getModeDelay());
uint16_t level = readRawLevel();
#if BH1750_DEBUG == 1
Serial.print("AutoHighMode: check level read: ");
Serial.println(level, DEC);
#endif
if(level<10) {
#if BH1750_DEBUG == 1
Serial.println("level 0: dark");
#endif
// Dunkel, Empfindlichkeit auf Maximum.
// Der Wert ist zufällig. Ab ca. 16000 wäre diese Vorgehnsweise möglich.
// Ich brauche diese Genauigkeit aber nur in den ganz dunklen Bereichen (zu erkennen, wann wirklich 'dunkel' ist).
defineMTReg(BH1750_MTREG_MAX);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2);
//fDelayPtr(120*3.68+5); // TODO: Wert prüfen
fDelayPtr(getModeDelay());
//fDelayPtr(122);
}
else if(level<32767) {
#if BH1750_DEBUG == 1
Serial.println("level 1: normal");
#endif
// Bis hierher reicht die 0,5 lx Modus. Normale Empfindlichkeit.
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2);
//fDelayPtr(120+5); // TODO: Wert prüfen
fDelayPtr(getModeDelay());
}
else if(level<60000) {
#if BH1750_DEBUG == 1
Serial.println("level 2: bright");
#endif
// hoher Bereich, 1 lx Modus, normale Empfindlichkeit. Der Wert von 60000 ist mehr oder weniger zufällig, es mus einfach ein hoher Wert, nah an der Grenze sein.
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE);
//fDelayPtr(120+5); // TODO: Wert prüfen
fDelayPtr(getModeDelay());
}
else {
#if BH1750_DEBUG == 1
Serial.println("level 3: very bright");
#endif
// sehr hoher Bereich, Empfindlichkeit verringern
defineMTReg(32); // Min+1, bei dem Minimum aus Doku spielt der Sensor (zumindest meiner) verrückt: Die Werte sind ca. 1/10 von den Erwarteten.
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE);
//fDelayPtr(120+5); // TODO: Wert prüfen
fDelayPtr(getModeDelay());
}
}
// Hardware Wert lesen und in Lux umrechnen.
uint16_t raw = readRawLevel();
if(raw==65535) {
// Wert verdächtig hoch. Sensor prüfen.
// Check I2C Adresse
Wire.beginTransmission(_address);
if(Wire.endTransmission()!=0) {
return -1;
}
}
return convertRawValue(raw);
}*/
/**
* Roh-Wert der Helligkeit auslesen.
* Wertebereich 0-65535.
*/
uint16_t AS_BH1750A::readRawLevel(void) {
uint16_t level;
Wire.beginTransmission(_address);
Wire.requestFrom(_address, 2);
#if (ARDUINO >= 100)
level = Wire.read();
level <<= 8;
level |= Wire.read();
#else
level = Wire.receive();
level <<= 8;
level |= Wire.receive();
#endif
if(Wire.endTransmission()!=0) {
#if BH1750_DEBUG == 1
Serial.println("I2C read error");
#endif
return 65535; // Error marker
}
#if BH1750_DEBUG == 1
Serial.print("Raw light level: ");
Serial.println(level);
#endif
_valueReaded=true;
return level;
}
/**
* Rechnet Roh-Werte in Lux um.
*/
float AS_BH1750A::convertRawValue(uint16_t raw) {
// Basisumrechnung
float flevel = raw/1.2;
#if BH1750_DEBUG == 1
Serial.print("convert light level (1): ");
Serial.println(flevel);
#endif
// MTreg-Einfluss berechnen
if(_MTreg!=BH1750_MTREG_DEFAULT) { // bei 69 ist der Faktor = 1
flevel = flevel * _MTregFactor;
#if BH1750_DEBUG == 1
Serial.print("convert light level (2): ");
Serial.println(flevel);
#endif
}
// je nach Modus ist eine weitere Umrechnung nötig
switch (_hardwareMode) {
case BH1750_CONTINUOUS_HIGH_RES_MODE_2:
case BH1750_ONE_TIME_HIGH_RES_MODE_2:
flevel = flevel/2;
#if BH1750_DEBUG == 1
Serial.print("convert light level (3): ");
Serial.println(flevel);
#endif
break;
default:
// nothing to do
break;
}
#if BH1750_DEBUG == 1
Serial.print("Light level: ");
Serial.println(flevel);
#endif
return flevel;
}
/**
* MTreg setzen. Definiert Empfindlichkeit des Sensors.
* Min.Wert (BH1750_MTREG_MIN) = 31 (Empfindlichkeit: default*0,45)
* Max.Wert (BH1750_MTREG_MAX) = 254 (Empfindlichkeit: default*3,68)
* Default (BH1750_MTREG_DEFAULT) = 69.
* Mit der Empfindlichkeit verändert sich die Lesezeit (höhere Empfindlichkeit bedeutet längere Zeitspanne).
*/
void AS_BH1750A::defineMTReg(uint8_t val) {
if(val<BH1750_MTREG_MIN) {
val = BH1750_MTREG_MIN;
}
if(val>BH1750_MTREG_MAX) {
val = BH1750_MTREG_MAX;
}
if(val!=_MTreg) {
_MTreg = val;
_MTregFactor = (float)BH1750_MTREG_DEFAULT / _MTreg;
// Change Measurement time
// Übertragung in zwei Schritten: 3 Bit und 5 Bit, jeweils mit einem Prefix.
// High bit: 01000_MT[7,6,5]
// Low bit: 011_MT[4,3,2,1,0]
uint8_t hiByte = val>>5;
hiByte |= 0b01000000;
#if BH1750_DEBUG == 1
Serial.print("MGTreg high byte: ");
Serial.println(hiByte, BIN);
#endif
write8(hiByte);
//fDelayPtr(10);
// Pause nötig?
uint8_t loByte = val&0b00011111;
loByte |= 0b01100000;
#if BH1750_DEBUG == 1
Serial.print("MGTreg low byte: ");
Serial.println(loByte, BIN);
#endif
write8(hiByte);
//fDelayPtr(10);
}
}
/**
* Gibt an, ob der Sensor initialisiert ist.
*/
bool AS_BH1750A::isInitialized() {
return _hardwareMode!=255;
}
/**
* Schreibt ein Byte auf I2C Bus (auf die Adresse des Sensors).
*/
bool AS_BH1750A::write8(uint8_t d) {
Wire.beginTransmission(_address);
#if (ARDUINO >= 100)
Wire.write(d);
#else
Wire.send(d);
#endif
return (Wire.endTransmission()==0);
}
float AS_BH1750A::readLightLevel(DelayFuncPtr fDelayPtr, TimeFuncPtr fTimePtr) {
startMeasurementAsync(fTimePtr);
while(!isMeasurementReady()) {
fDelayPtr(_nextDelay);
}
return readLightLevelAsync();
}
/*float AS_BH1750A::checkAndReadLightLevelAsync(TimeFuncPtr fTimePtr) {
//Serial.print("--stage: ");
//Serial.println(_stage);
if(_stage==0 || _stage>=100) {
if(startMeasurementAsync(fTimePtr)) return -100;
return -1; // Marker "nicht vorhanden"
} else if(_stage==99) {
_stage=100;
return readLightLevelAsync();
}
return readLightLevelAsync();
}*/
unsigned long AS_BH1750A::nextDelay(void) {
return _nextDelay;
}
//void AS_BH1750A::reset(void) {
//_stage==0;
//}
bool AS_BH1750A::startMeasurementAsync(TimeFuncPtr fTimePtr) {
_fTimePtr = fTimePtr;
_stage = 0;
_nextDelay = 0;
int _lastResult = -1;
_lastTimestamp=fTimePtr();
return readLightLevelAsync()!=-1;
}
bool AS_BH1750A::isMeasurementReady(void) {
return readLightLevelAsync() >= -1; // -1 ist 'not initialized'-Marker (prevent hangs)
}
bool AS_BH1750A::delayExpired() {
unsigned long timestamp = _fTimePtr();
// Zeitdifferenz
unsigned long delayTime = 0;
// Auf Ueberlauf pruefen
if (timestamp < _lastTimestamp)
{
// Ueberlauf: Delay ist Zeit zum MaxWert plus Zeit ab Null
delayTime = MAX_U_LONG - _lastTimestamp + timestamp;
} else {
// Kein Ueberlauf: einfache Differenz
delayTime = timestamp - _lastTimestamp;
}
return (delayTime >= _nextDelay);
}
float AS_BH1750A::readLightLevelAsync() {
if(_stage>=99) return _lastResult;
if(_stage==0) {
#if BH1750_DEBUG == 1
Serial.print("call: readLightLevel. virtualMode: ");
Serial.println(_virtualMode, DEC);
#endif
if(!isInitialized()) {
#if BH1750_DEBUG == 1
Serial.println("sensor not initialized");
#endif
return -1;
}
// ggf. PowerOn
if(_autoPowerDown && _valueReaded){
powerOn();
_nextDelay = getModeDelay();
// TEST delay(getModeDelay());_stage=99;
return -100;
} else {
_nextDelay = 0;
}
_stage++;
}
// Das Automatische Modus benötigt eine Sonderbehandlung.
// Zuerst wird die Helligkeit im LowRes-Modus gelesen,
// je nach Bereich (dunkel, normal, sehr hell) werden die Werte von MTreg gesetzt und
// danach wird die eigentliche Messung vorgenommen.
/*
Die feste Grenzwerte verursachen möglicherweise einen 'Sprung' in der Messkurve.
In diesem Fall wäre eine laufende Anpassung von MTreg in Grenzbereichen vermutlich besser.
Für meine Zwecke ist das jedoch ohne Bedeutung.
*/
if(_virtualMode==RESOLUTION_AUTO_HIGH) {
selectAutoMode();
} else {
if(delayExpired()) {_stage=99;} // Fertig
}
if(_stage<99) return -100; // Marker: wait for next step
// Hardware Wert lesen und in Lux umrechnen.
uint16_t raw = readRawLevel();
if(raw==65535) {
// Wert verdächtig hoch. Sensor prüfen.
// Check I2C Adresse
Wire.beginTransmission(_address);
if(Wire.endTransmission()!=0) {
return -1;
}
}
_lastResult = convertRawValue(raw);
return _lastResult;
}
void AS_BH1750A::selectAutoMode() {
//if(!delayExpired()) return;
if(_stage==1) {
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(BH1750_CONTINUOUS_LOW_RES_MODE);
//fDelayPtr(16+5); // Lesezeit in LowResMode
//fDelayPtr(getModeDelay());
_nextDelay=getModeDelay();
_stage++;
return;
}
if(!delayExpired()) return;
if(_stage==2) {
uint16_t level = readRawLevel();
#if BH1750_DEBUG == 1
Serial.print("AutoHighMode: check level read: ");
Serial.println(level, DEC);
#endif
if(level<10) {
#if BH1750_DEBUG == 1
Serial.println("level 0: dark");
#endif
// Dunkel, Empfindlichkeit auf Maximum.
// Der Wert ist zufällig. Ab ca. 16000 wäre diese Vorgehnsweise möglich.
// Ich brauche diese Genauigkeit aber nur in den ganz dunklen Bereichen (zu erkennen, wann wirklich 'dunkel' ist).
defineMTReg(BH1750_MTREG_MAX);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2);
//fDelayPtr(120*3.68+5); // TODO: Wert prüfen
//fDelayPtr(getModeDelay());
_nextDelay=getModeDelay();
//fDelayPtr(122);
} else if(level<32767) {
#if BH1750_DEBUG == 1
Serial.println("level 1: normal");
#endif
// Bis hierher reicht die 0,5 lx Modus. Normale Empfindlichkeit.
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE_2:BH1750_CONTINUOUS_HIGH_RES_MODE_2);
//fDelayPtr(120+5); // TODO: Wert prüfen
//fDelayPtr(getModeDelay());
_nextDelay=getModeDelay();
} else if(level<60000) {
#if BH1750_DEBUG == 1
Serial.println("level 2: bright");
#endif
// hoher Bereich, 1 lx Modus, normale Empfindlichkeit. Der Wert von 60000 ist mehr oder weniger zufällig, es mus einfach ein hoher Wert, nah an der Grenze sein.
defineMTReg(BH1750_MTREG_DEFAULT);
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE);
//fDelayPtr(120+5); // TODO: Wert prüfen
//fDelayPtr(getModeDelay());
_nextDelay=getModeDelay();
} else {
#if BH1750_DEBUG == 1
Serial.println("level 3: very bright");
#endif
// sehr hoher Bereich, Empfindlichkeit verringern
defineMTReg(32); // Min+1, bei dem Minimum aus Doku spielt der Sensor (zumindest meiner) verrückt: Die Werte sind ca. 1/10 von den Erwarteten.
selectResolutionMode(_autoPowerDown?BH1750_ONE_TIME_HIGH_RES_MODE:BH1750_CONTINUOUS_HIGH_RES_MODE);
//fDelayPtr(120+5); // TODO: Wert prüfen
//fDelayPtr(getModeDelay());
_nextDelay=getModeDelay();
}
_stage++;
return;
}
_stage = 99; // fertig
}
unsigned long AS_BH1750A::getModeDelay() {
float ml;
if(_MTreg<=BH1750_MTREG_MIN+1) { ml = 0.45; }
else if(_MTreg<=BH1750_MTREG_DEFAULT+1) { ml = 1.0; }
else { ml = 3.68; }
switch (_hardwareMode) {
case BH1750_CONTINUOUS_HIGH_RES_MODE:
case BH1750_ONE_TIME_HIGH_RES_MODE:
return ml*120+5;
case BH1750_ONE_TIME_HIGH_RES_MODE_2:
case BH1750_CONTINUOUS_HIGH_RES_MODE_2:
return ml*120+5;
case BH1750_CONTINUOUS_LOW_RES_MODE:
case BH1750_ONE_TIME_LOW_RES_MODE:
return ml*16+5;
default:
return 0;
}
}
-207
View File
@@ -1,207 +0,0 @@
/*
This is a (Arduino) library for the BH1750FVI Digital Light Sensor.
Description:
http://www.rohm.com/web/global/products/-/product/BH1750FVI
Datasheet:
http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
Copyright (c) 2013 Alexander Schulz. All right reserved.
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AS_BH1750A_h
#define AS_BH1750A_h
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include "Wire.h"
// Mögliche I2C Adressen
#define BH1750_DEFAULT_I2CADDR 0x23
#define BH1750_SECOND_I2CADDR 0x5C
// MTreg Werte
// Default
#define BH1750_MTREG_DEFAULT 69
// Sensitivity : default = 0.45
#define BH1750_MTREG_MIN 31
// Sensitivity : default = 3.68
#define BH1750_MTREG_MAX 254
// Hardware Modi
// No active state
#define BH1750_POWER_DOWN 0x00
// Wating for measurment command
#define BH1750_POWER_ON 0x01
// Reset data register value - not accepted in POWER_DOWN mode
#define BH1750_RESET 0x07
// Start measurement at 1lx resolution. Measurement time is approx 120ms.
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10
// Start measurement at 0.5lx resolution. Measurement time is approx 120ms.
#define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11
// Start measurement at 4lx resolution. Measurement time is approx 16ms.
#define BH1750_CONTINUOUS_LOW_RES_MODE 0x13
// Start measurement at 1lx resolution. Measurement time is approx 120ms.
// Device is automatically set to Power Down after measurement.
#define BH1750_ONE_TIME_HIGH_RES_MODE 0x20
// Start measurement at 0.5lx resolution. Measurement time is approx 120ms.
// Device is automatically set to Power Down after measurement.
#define BH1750_ONE_TIME_HIGH_RES_MODE_2 0x21
// Start measurement at 1lx resolution. Measurement time is approx 120ms.
// Device is automatically set to Power Down after measurement.
#define BH1750_ONE_TIME_LOW_RES_MODE 0x23
#define MAX_U_LONG 4294967295;
/** Virtual Modi */
typedef enum
{
RESOLUTION_LOW = (1), /** 4lx resolution. Measurement time is approx 16ms. */
RESOLUTION_NORMAL = (2), /** 1lx resolution. Measurement time is approx 120ms. */
RESOLUTION_HIGH = (3), /** 0,5lx resolution. Measurement time is approx 120ms. */
RESOLUTION_AUTO_HIGH = (99) /** 0,11-1lx resolution. Measurement time is above 250ms. */
}
sensors_resolution_t;
typedef void (*DelayFuncPtr)(unsigned long);
typedef unsigned long (*TimeFuncPtr)(void);
/**
* BH1750 driver class.
*/
class AS_BH1750A {
public:
/**
* Constructor.
* Erlaubt die I2C-Adresse des Sensors zu ändern.
* Standardadresse: 0x23, Alternativadresse: 0x5C.
* Es sind entsprechende Konstanten definiert: BH1750_DEFAULT_I2CADDR und BH1750_SECOND_I2CADDR.
* Bei Nichtangabe wird die Standardadresse verwendet.
* Um die Alternativadresse zu nutzen, muss der Sensorpin 'ADR' des Chips auf VCC gelegt werden.
*/
AS_BH1750A(uint8_t address = BH1750_DEFAULT_I2CADDR);
/**
* Führt die anfängliche Initialisierung des Sensors.
* Mögliche Parameter:
* - Modus für die Sensorauflösung:
* -- RESOLUTION_LOW: Physische Sensormodus mit 4 lx Auflösung. Messzeit ca. 16ms. Bereich 0-54612.
* -- RESOLUTION_NORMAL: Physische Sensormodus mit 1 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* -- RESOLUTION_HIGH: Physische Sensormodus mit 0,5 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* (Die Messbereiche können durch Änderung des MTreg verschoben werden.)
* -- RESOLUTION_AUTO_HIGH: Die Werte im MTreg werden je nach Helligkeit automatisch so angepasst,
* dass eine maximalmögliche Auflösung und Messbereich erziehlt werden.
* Die messbaren Werte fangen von 0,11 lx und gehen bis über 100000 lx.
* (ich weis nicht, wie genau die Werte in Grenzbereichen sind,
* besonders bei hohen Werte habe ich meine Zweifel.)
* Auflösung im Unteren Bereich 0,13 lx, im mittleren 0,5 lx, im oberen 1-2 lx.
* Die Messzeiten verlängern sich durch mehrfache Messungen und
* die Änderungen von Measurement Time (MTreg) bis max. ca. 500 ms.
*
* - AutoPowerDown: true = Der Sensor wird nach der Messung in den Stromsparmodus versetzt.
* Das spätere Aufwecken wird ggf. automatisch vorgenommen, braucht jedoch geringfügig mehr Zeit.
*
* Defaultwerte: RESOLUTION_AUTO_HIGH, true, delay()
*
*/
bool begin(sensors_resolution_t mode = RESOLUTION_AUTO_HIGH, bool autoPowerDown = true);
/**
* Erlaub eine Prüfung, ob ein (ansprechbarer) BH1750-Sensor vorhanden ist.
*/
bool isPresent(void);
/**
* Liefert aktuell gemessenen Wert für Helligkeit in lux (lx).
* Falls sich der Sensorf in Stromsparmodus befindet, wird er automatisch geweckt.
*
* Wurde der Sensor (noch) nicht initialisiert (begin), wird der Wert -1 geliefert.
*
* Mögliche Parameter:
*
* - DelayFuncPtr: delay(n) Möglichkeit, eigene Delay-Funktion mitzugeben (z.B. um sleep-Modus zu verwenden).
*
* Defaultwerte: delay()
*
*/
float readLightLevel(DelayFuncPtr fDelayPtr = &delay, TimeFuncPtr fTimePtr = &millis);
bool startMeasurementAsync(TimeFuncPtr fTimePtr = &millis);
bool isMeasurementReady(void);
float readLightLevelAsync();
//float checkAndReadLightLevelAsync(TimeFuncPtr fTimePtr);
//void reset(void);
unsigned long nextDelay(void);
/**
* Schickt den Sensor in Stromsparmodus.
* Funktionier nur, wenn der Sensor bereits initialisiert wurde.
*/
void powerDown(void);
//bool delayExpired(); // TEST
private:
int _address;
uint8_t _hardwareMode;
uint8_t _MTreg;
float _MTregFactor;
sensors_resolution_t _virtualMode;
bool _autoPowerDown;
bool _valueReaded;
bool selectResolutionMode(uint8_t mode);
void defineMTReg(uint8_t val);
void powerOn();
//void reset(void);
uint16_t readRawLevel(void);
float convertRawValue(uint16_t raw);
bool isInitialized();
bool write8(uint8_t data);
TimeFuncPtr _fTimePtr;
int _stage = 0;
int _nextDelay = 0;
int _lastTimestamp = 0;
float _lastResult = -100;
bool delayExpired();
void selectAutoMode();
// TEST
//float readLightLevel_alt(DelayFuncPtr fDelayPtr = &delay);
unsigned long getModeDelay();
};
#endif
-502
View File
@@ -1,502 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. 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 not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the 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
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
a (Arduino) library for the BH1750FVI Digital Light Sensor
Copyright (C) 2013 Alex Hexenmeister
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
{signature of Ty Coon}, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
-37
View File
@@ -1,37 +0,0 @@
AS_BH1750
=========
a (Arduino) library for the BH1750FVI Digital Light Sensor.
(http://s6z.de/joomla3/index.php/arduino/sensoren/15-umgebungslichtsensor-bh1750)
Features:
- unterstützt beide möglichen I2C-Adressen des Sensors:
Standardadresse: 0x23, Alternativadresse: 0x5C.
Es sind entsprechende Konstanten definiert: BH1750_DEFAULT_I2CADDR und BH1750_SECOND_I2CADDR.
- alle Hardware-Auflösungsmodi:
* RESOLUTION_LOW: Physische Sensormodus mit 4 lx Auflösung. Messzeit ca. 16ms. Bereich 0-54612.
* RESOLUTION_NORMAL: Physische Sensormodus mit 1 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
* RESOLUTION_HIGH: Physische Sensormodus mit 0,5 lx Auflösung. Messzeit ca. 120ms. Bereich 0-54612.
- Virtueller Modus:
* RESOLUTION_AUTO_HIGH: Die Werte im MTreg ('Measurement Time'-Register) werden je nach Helligkeit
automatisch so angepasst, dass eine maximalmögliche Auflösung
und Messbereich erziehlt werden.
Die messbaren Werte fangen von 0,11 lx und gehen bis über 100000 lx.
(ich weis nicht, wie genau die Werte in Grenzbereichen sind,
besonders bei hohen Werte habe ich da meine Zweifel.
Die Werte scheinen jedoch weitgehend linear mit der steigenden Helligkeit zu wachsen.)
Auflösung im Unteren Bereich ca. 0,13 lx, im mittleren 0,5 lx, im oberen etwa 1-2 lx.
Die Messzeiten verlängern sich durch mehrfache Messungen und
die Änderungen von Measurement Time (MTreg) bis max. ca. 500 ms.
- Methode zur Änderung von 'Measurement Time'-Registers. Damit kann die Empfindlichkeit beeinflusst werden.
- auto power down: Der Sensor wird nach der Messung in den Stromsparmodus versetzt.
Das spätere Aufwecken wird ggf. automatisch vorgenommen, braucht jedoch geringfügig mehr Zeit.
Defaultwerte: Modus = RESOLUTION_AUTO_HIGH, AutoPowerDown = true

Some files were not shown because too many files have changed in this diff Show More