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
189 changed files with 6109 additions and 16718 deletions
+1 -4
View File
@@ -1,4 +1 @@
.pioenvs
.clang_complete
.gcc-flags.json
.piolibdeps
Version.h
-9
View File
@@ -1,9 +0,0 @@
[submodule "lib/Adafruit_NeoPixel"]
path = lib/Adafruit_NeoPixel
url = https://github.com/adafruit/Adafruit_NeoPixel.git
[submodule "lib/ArduinoJson"]
path = lib/ArduinoJson
url = https://github.com/bblanchon/ArduinoJson.git
[submodule "lib/IRremoteESP8266"]
path = lib/IRremoteESP8266
url = https://github.com/sebastienwarin/IRremoteESP8266.git
-32
View File
@@ -1,32 +0,0 @@
language: python
python:
- '2.7'
sudo: false
cache:
directories:
- "~/.platformio"
- "./.pioenvs"
install:
- pip install -U platformio
script:
- platformio run
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
+65 -140
View File
@@ -1,5 +1,3 @@
char* ramtest;
#define INPUT_COMMAND_SIZE 80
void ExecuteCommand(byte source, const char *Line)
{
@@ -21,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;
@@ -150,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)
@@ -203,13 +96,6 @@ void ExecuteCommand(byte source, const char *Line)
// 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;
@@ -322,7 +208,7 @@ void ExecuteCommand(byte source, const char *Line)
while (client.available()) {
String line = client.readStringUntil('\n');
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
addLog(LOG_LEVEL_DEBUG, line);
delay(1);
}
@@ -331,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
@@ -356,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)
@@ -382,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
@@ -405,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;
@@ -445,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();
}
}
+24 -32
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)
{
@@ -30,18 +30,11 @@ boolean sendData(struct EventStruct *event)
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();
}
@@ -66,7 +59,7 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
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);
}
@@ -76,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
@@ -88,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");
@@ -106,8 +101,8 @@ 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;
@@ -130,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())
{
@@ -173,14 +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);
}
+237 -365
View File
@@ -104,59 +104,30 @@
#define UNIT 0
#define FEATURE_TIME true
#define FEATURE_SSDP true
// Enable FEATURE_ADC_VCC to measure supply voltage using the analog pin
// Please note that the TOUT pin has to be disconnected in this mode
// Use the "System Info" device to read the VCC value
#define FEATURE_ADC_VCC false
//enable Arduino OTA updating.
//Note: This adds around 10kb to the firmware size, and 1kb extra ram.
//Normally only enabled for dev environment, since its helpfull while developing.
// #define FEATURE_ARDUINO_OTA
// ********************************************************************************
// DO NOT CHANGE ANYTHING BELOW THIS LINE
// ********************************************************************************
#define ESP_PROJECT_PID 2016110801L
#define VERSION 2
#define BUILD 20000 // git version 2.0.0
#define BUILD_NOTES " - Mega"
#ifndef BUILD_GIT
#define BUILD_GIT "(custom)"
#endif
#define MAX_FLASHWRITES_PER_DAY 100 // per 24 hour window
#define ESP_PROJECT_PID 2015050101L
#define ESP_EASY
#define VERSION 9
#define BUILD 148
#define BUILD_NOTES ""
#define FEATURE_SPIFFS false
#define NODE_TYPE_ID_ESP_EASY_STD 1
#define NODE_TYPE_ID_ESP_EASYM_STD 17
#define NODE_TYPE_ID_ESP_EASY32_STD 33
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
#define NODE_TYPE_ID_NANO_EASY_STD 81
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD
#define PLUGIN_INIT_ALL 1
#define PLUGIN_INIT 2
#define PLUGIN_READ 3
#define PLUGIN_ONCE_A_SECOND 4
#define PLUGIN_TEN_PER_SECOND 5
#define PLUGIN_DEVICE_ADD 6
#define PLUGIN_EVENTLIST_ADD 7
#define PLUGIN_WEBFORM_SAVE 8
#define PLUGIN_WEBFORM_LOAD 9
#define PLUGIN_WEBFORM_SHOW_VALUES 10
#define PLUGIN_GET_DEVICENAME 11
#define PLUGIN_GET_DEVICEVALUENAMES 12
#define PLUGIN_WRITE 13
#define PLUGIN_EVENT_OUT 14
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
#define PLUGIN_SERIAL_IN 16
#define PLUGIN_UDP_IN 17
#define PLUGIN_CLOCK_IN 18
#define PLUGIN_TIMER_IN 19
#define PLUGIN_FIFTY_PER_SECOND 20
#define PLUGIN_REMOTE_CONFIG 21
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY_STD
#define CPLUGIN_PROTOCOL_ADD 1
#define CPLUGIN_PROTOCOL_TEMPLATE 2
@@ -166,13 +137,6 @@
#define CPLUGIN_WEBFORM_SAVE 6
#define CPLUGIN_WEBFORM_LOAD 7
#define NPLUGIN_PROTOCOL_ADD 1
#define NPLUGIN_GET_DEVICENAME 2
#define NPLUGIN_WEBFORM_SAVE 3
#define NPLUGIN_WEBFORM_LOAD 4
#define NPLUGIN_WRITE 5
#define NPLUGIN_NOTIFY 6
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
@@ -182,9 +146,7 @@
#define CMD_WIFI_DISCONNECT 135
#define DEVICES_MAX 64
#define TASKS_MAX 12 // max 12!
#define CONTROLLER_MAX 3 // max 4!
#define NOTIFICATION_MAX 3 // max 4!
#define TASKS_MAX 12
#define VARS_PER_TASK 4
#define PLUGIN_MAX 64
#define PLUGIN_CONFIGVAR_MAX 8
@@ -192,7 +154,6 @@
#define PLUGIN_CONFIGLONGVAR_MAX 4
#define PLUGIN_EXTRACONFIGVAR_MAX 16
#define CPLUGIN_MAX 16
#define NPLUGIN_MAX 4
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
#define RULES_TIMER_MAX 8
#define SYSTEM_TIMER_MAX 8
@@ -200,7 +161,6 @@
#define PINSTATE_TABLE_MAX 32
#define RULES_MAX_SIZE 2048
#define RULES_MAX_NESTING_LEVEL 3
#define RULESETS_MAX 4
#define PIN_MODE_UNDEFINED 0
#define PIN_MODE_INPUT 1
@@ -229,6 +189,26 @@
#define SENSOR_TYPE_LONG 20
#define SENSOR_TYPE_WIND 21
#define PLUGIN_INIT_ALL 1
#define PLUGIN_INIT 2
#define PLUGIN_READ 3
#define PLUGIN_ONCE_A_SECOND 4
#define PLUGIN_TEN_PER_SECOND 5
#define PLUGIN_DEVICE_ADD 6
#define PLUGIN_EVENTLIST_ADD 7
#define PLUGIN_WEBFORM_SAVE 8
#define PLUGIN_WEBFORM_LOAD 9
#define PLUGIN_WEBFORM_SHOW_VALUES 10
#define PLUGIN_GET_DEVICENAME 11
#define PLUGIN_GET_DEVICEVALUENAMES 12
#define PLUGIN_WRITE 13
#define PLUGIN_EVENT_OUT 14
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
#define PLUGIN_SERIAL_IN 16
#define PLUGIN_UDP_IN 17
#define PLUGIN_CLOCK_IN 18
#define PLUGIN_TIMER_IN 19
#define VALUE_SOURCE_SYSTEM 1
#define VALUE_SOURCE_SERIAL 2
#define VALUE_SOURCE_HTTP 3
@@ -237,18 +217,9 @@
#define BOOT_CAUSE_MANUAL_REBOOT 0
#define BOOT_CAUSE_COLD_BOOT 1
#define BOOT_CAUSE_DEEP_SLEEP 2
#define BOOT_CAUSE_EXT_WD 10
#define DAT_TASKS_SIZE 2048
#define DAT_TASKS_CUSTOM_OFFSET 1024
#define DAT_CONTROLLER_SIZE 1024
#define DAT_NOTIFICATION_SIZE 1024
#define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max
#define DAT_OFFSET_CONTROLLER 28672 // each controller = 1k, 4 max
#define DAT_OFFSET_CUSTOMCONTROLLER 32768 // custom controller config = 4k, currently only one can use it.
#include "Version.h"
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <WiFiUdp.h>
@@ -259,9 +230,9 @@
#include <ArduinoJson.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#define FS_NO_GLOBALS
#if FEATURE_SPIFFS
#include <FS.h>
#include <SD.h>
#endif
#include <ESP8266HTTPUpdateServer.h>
ESP8266HTTPUpdateServer httpUpdater(true);
#include <base64.h>
@@ -280,13 +251,6 @@ extern "C" {
#include "user_interface.h"
}
#ifdef FEATURE_ARDUINO_OTA
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
bool ArduinoOTAtriggered=false;
#endif
// Setup DNS, only used if the ESP has no valid WiFi config
const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 4, 1);
@@ -305,6 +269,7 @@ ESP8266WebServer WebServer(80);
// syslog stuff
WiFiUDP portUDP;
#define FLASH_EEPROM_SIZE 4096
extern "C" {
#include "spi_flash.h"
}
@@ -317,11 +282,9 @@ struct SecurityStruct
{
char WifiSSID[32];
char WifiKey[64];
char WifiSSID2[32];
char WifiKey2[64];
char WifiAPKey[64];
char ControllerUser[CONTROLLER_MAX][26];
char ControllerPassword[CONTROLLER_MAX][64];
char ControllerUser[26];
char ControllerPassword[64];
char Password[26];
} SecuritySettings;
@@ -329,90 +292,66 @@ struct SettingsStruct
{
unsigned long PID;
int Version;
int16_t Build;
byte IP[4];
byte Gateway[4];
byte Subnet[4];
byte DNS[4];
byte IP_Octet;
byte Unit;
char Name[26];
byte Controller_IP[4];
unsigned int ControllerPort;
byte IP_Octet;
char NTPHost[64];
unsigned long Delay;
int8_t Pin_i2c_sda;
int8_t Pin_i2c_scl;
int8_t Pin_status_led;
int8_t Pin_sd_cs;
int8_t PinBootStates[17];
byte Syslog_IP[4];
unsigned int UDPPort;
byte Protocol;
byte IP[4];
byte Gateway[4];
byte Subnet[4];
char Name[26];
byte SyslogLevel;
byte SerialLogLevel;
byte WebLogLevel;
byte SDLogLevel;
unsigned long BaudRate;
unsigned long MessageDelay;
byte TaskDeviceNumber[TASKS_MAX];
unsigned int TaskDeviceID[TASKS_MAX];
int8_t TaskDevicePin1[TASKS_MAX];
int8_t TaskDevicePin2[TASKS_MAX];
byte TaskDevicePort[TASKS_MAX];
boolean TaskDevicePin1PullUp[TASKS_MAX];
int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX];
boolean TaskDevicePin1Inversed[TASKS_MAX];
byte deepSleep;
char MQTTpublish[81];
char MQTTsubscribe[81];
boolean CustomCSS;
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
boolean TaskDeviceSendData[TASKS_MAX];
int16_t Build;
byte DNS[4];
int8_t TimeZone_OLD;
char ControllerHostName[64];
boolean UseNTP;
boolean DST;
byte WDI2CAddress;
boolean TaskDeviceGlobalSync[TASKS_MAX];
int8_t TaskDevicePin3[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX];
int8_t PinBootStates[17];
byte UseDNS;
boolean UseRules;
int8_t Pin_status_led;
boolean UseSerial;
unsigned long TaskDeviceTimer[TASKS_MAX];
boolean UseSSDP;
boolean UseNTP;
unsigned long WireClockStretchLimit;
boolean GlobalSync;
unsigned long ConnectionFailuresThreshold;
int16_t TimeZone;
boolean MQTTRetainFlag;
boolean InitSPI;
byte Protocol[CONTROLLER_MAX];
byte Notification[NOTIFICATION_MAX];
byte TaskDeviceNumber[TASKS_MAX];
unsigned int OLD_TaskDeviceID[TASKS_MAX];
int8_t TaskDevicePin1[TASKS_MAX];
int8_t TaskDevicePin2[TASKS_MAX];
int8_t TaskDevicePin3[TASKS_MAX];
byte TaskDevicePort[TASKS_MAX];
boolean TaskDevicePin1PullUp[TASKS_MAX];
int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX];
boolean TaskDevicePin1Inversed[TASKS_MAX];
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
boolean OLD_TaskDeviceSendData[TASKS_MAX];
boolean TaskDeviceGlobalSync[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX];
unsigned long TaskDeviceTimer[TASKS_MAX];
boolean TaskDeviceEnabled[TASKS_MAX];
boolean ControllerEnabled[CONTROLLER_MAX];
boolean NotificationEnabled[NOTIFICATION_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
} Settings;
struct ControllerSettingsStruct
{
boolean UseDNS;
byte IP[4];
unsigned int Port;
char HostName[65];
char Publish[129];
char Subscribe[129];
};
struct NotificationSettingsStruct
{
char Server[65];
unsigned int Port;
char Domain[65];
char Sender[65];
char Receiver[65];
char Subject[129];
char Body[513];
byte Pin1;
byte Pin2;
};
struct ExtraTaskSettingsStruct
{
byte TaskIndex;
@@ -421,17 +360,12 @@ struct ExtraTaskSettingsStruct
char TaskDeviceValueNames[VARS_PER_TASK][41];
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
byte TaskDeviceValueDecimals[VARS_PER_TASK];
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
} ExtraTaskSettings;
struct EventStruct
{
byte Source;
byte TaskIndex; // index position in TaskSettings array, 0-11
byte ControllerIndex; // index position in Settings.Controller, 0-3
byte ProtocolIndex; // index position in protocol array, depending on which controller plugins are loaded.
byte NotificationIndex; // index position in Settings.Notification, 0-3
byte NotificationProtocolIndex; // index position in notification array, depending on which controller plugins are loaded.
byte TaskIndex;
byte BaseVarIndex;
int idx;
byte sensorType;
@@ -447,7 +381,7 @@ struct EventStruct
struct LogStruct
{
unsigned long timeStamp;
char* Message;
String Message;
} Logging[10];
int logcount = -1;
@@ -477,16 +411,8 @@ struct ProtocolStruct
boolean usesPassword;
int defaultPort;
boolean usesTemplate;
boolean usesID;
} Protocol[CPLUGIN_MAX];
struct NotificationStruct
{
byte Number;
boolean usesMessaging;
byte usesGPIO;
} Notification[NPLUGIN_MAX];
struct NodeStruct
{
byte ip[4];
@@ -519,21 +445,8 @@ struct pinStatesStruct
uint16_t value;
} pinStates[PINSTATE_TABLE_MAX];
struct RTCStruct
{
byte ID1;
byte ID2;
boolean valid;
byte factoryResetCounter;
byte deepSleepState;
byte rebootCounter; //not used yet?
byte flashDayCounter;
unsigned long flashCounter;
} RTC;
int deviceCount = -1;
int protocolCount = -1;
int notificationCount = -1;
boolean printToWeb = false;
String printWebString = "";
@@ -543,8 +456,8 @@ float UserVar[VARS_PER_TASK * TASKS_MAX];
unsigned long RulesTimer[RULES_TIMER_MAX];
unsigned long timerSensor[TASKS_MAX];
unsigned long timer;
unsigned long timer100ms;
unsigned long timer20ms;
unsigned long timer1s;
unsigned long timerwd;
unsigned long lastSend;
@@ -565,15 +478,13 @@ int WebLoggedInTimer = 300;
boolean (*Plugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&);
byte Plugin_id[PLUGIN_MAX];
boolean (*CPlugin_ptr[CPLUGIN_MAX])(byte, struct EventStruct*, String&);
byte CPlugin_id[CPLUGIN_MAX];
boolean (*NPlugin_ptr[NPLUGIN_MAX])(byte, struct EventStruct*, String&);
byte NPlugin_id[NPLUGIN_MAX];
boolean (*CPlugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&);
byte CPlugin_id[PLUGIN_MAX];
String dummyString = "";
byte lastBootCause = BOOT_CAUSE_MANUAL_REBOOT;
boolean systemOK = false;
byte lastBootCause = 0;
boolean wifiSetup = false;
boolean wifiSetupConnect = false;
@@ -584,52 +495,34 @@ unsigned long loopCounter = 0;
unsigned long loopCounterLast = 0;
unsigned long loopCounterMax = 1;
unsigned long dailyResetCounter = 0;
unsigned long flashWrites = 0;
String eventBuffer = "";
uint16_t lowestRAM = 0;
byte lowestRAMid=0;
/*
1 savetoflash - obsolete
2 loadfrom flash - obsolete
3 zerofillflash - obsolete
4 rulesprocessing
5 handle_download
6 handle_css
7 handlefileupload
8 handle_rules
9 handle_devices
*/
// Blynk_get prototype
boolean Blynk_get(String command,float *data = NULL );
/*********************************************************************************************\
* SETUP
\*********************************************************************************************/
void setup()
{
lowestRAM = FreeMem();
Serial.begin(115200);
initLog();
if (SpiffsSectors() < 32)
if (SpiffsSectors() == 0)
{
Serial.println(F("\nNo (or too small) SPIFFS area..\nSystem Halted\nPlease reflash with 128k SPIFFS minimum!"));
Serial.println(F("\nNo SPIFFS area..\nSystem Halted\nPlease reflash with SPIFFS"));
while (true)
delay(1);
}
#if FEATURE_SPIFFS
fileSystemCheck();
#endif
emergencyReset();
String log = F("\n\n\rINIT : Booting version: ");
log += BUILD_GIT;
addLog(LOG_LEVEL_INFO, log);
fileSystemCheck();
LoadSettings();
if (strcasecmp(SecuritySettings.WifiSSID, "ssid") == 0)
wifiSetup = true;
@@ -637,7 +530,11 @@ void setup()
// if different version, eeprom settings structure has changed. Full Reset needed
// on a fresh ESP module eeprom values are set to 255. Version results into -1 (signed int)
if (Settings.Version != VERSION || Settings.PID != ESP_PROJECT_PID)
if (Settings.Version == VERSION && Settings.PID == ESP_PROJECT_PID)
{
systemOK = true;
}
else
{
// Direct Serial is allowed here, since this is only an emergency task.
Serial.print(F("\nPID:"));
@@ -649,113 +546,117 @@ void setup()
ResetFactory();
}
if (Settings.UseSerial)
Serial.begin(Settings.BaudRate);
if (Settings.Build != BUILD)
BuildFixes();
log = F("INIT : Free RAM:");
log += FreeMem();
addLog(LOG_LEVEL_INFO, log);
if (Settings.UseSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
Serial.setDebugOutput(true);
hardwareInit();
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
WifiAPconfig();
if (!WifiConnect(true,3))
WifiConnect(false,3);
//After booting, we want all the tasks to run without delaying more than neccesary.
//Plugins that need an initial startup delay need to overwrite their initial timerSensor value in PLUGIN_INIT
//They should also check if we returned from deep sleep so that they can skip the delay in that case.
for (byte x = 0; x < TASKS_MAX; x++)
if (Settings.TaskDeviceTimer[x] !=0)
timerSensor[x] = millis() + (x * Settings.MessageDelay);
timer100ms = 0; // timer for periodic actions 10 x per/sec
timer1s = 0; // timer for periodic actions once per/sec
timerwd = 0; // timer for watchdog once per 30 sec
PluginInit();
CPluginInit();
NPluginInit();
WebServerInit();
#ifdef FEATURE_ARDUINO_OTA
ArduinoOTAInit();
#endif
// setup UDP
if (Settings.UDPPort != 0)
portUDP.begin(Settings.UDPPort);
// Setup MQTT Client
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
if (Protocol[ProtocolIndex].usesMQTT)
MQTTConnect();
sendSysInfoUDP(3);
//warm boot
if (readFromRTC())
if (systemOK)
{
readUserVarFromRTC();
if (RTC.deepSleepState == 1)
if (Settings.UseSerial)
Serial.begin(Settings.BaudRate);
if (Settings.Build != BUILD)
BuildFixes();
String log = F("\nINIT : Booting Build nr:");
log += BUILD;
addLog(LOG_LEVEL_INFO, log);
if (Settings.UseSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
Serial.setDebugOutput(true);
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
WifiAPconfig();
WifiConnect(3);
hardwareInit();
PluginInit();
CPluginInit();
WebServerInit();
// setup UDP
if (Settings.UDPPort != 0)
portUDP.begin(Settings.UDPPort);
// Setup MQTT Client
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
if (Protocol[ProtocolIndex].usesMQTT)
MQTTConnect();
sendSysInfoUDP(3);
log = F("INIT : Boot OK");
addLog(LOG_LEVEL_INFO, log);
if (Settings.deepSleep)
{
log = F("INIT : Rebooted from deepsleep");
lastBootCause=BOOT_CAUSE_DEEP_SLEEP;
log = F("INIT : Deep sleep enabled");
addLog(LOG_LEVEL_INFO, log);
}
byte bootMode = 0;
if (readFromRTC(&bootMode))
{
if (bootMode == 1)
log = F("INIT : Reboot from deepsleep");
else
log = F("INIT : Normal boot");
}
else
log = F("INIT : Normal boot");
}
//cold boot (RTC memory empty)
else
{
RTC.factoryResetCounter=0;
RTC.deepSleepState=0;
RTC.rebootCounter=0;
RTC.flashDayCounter=0;
RTC.flashCounter=0;
saveToRTC();
{
// cold boot situation
if (lastBootCause == 0) // only set this if not set earlier during boot stage.
lastBootCause = BOOT_CAUSE_COLD_BOOT;
log = F("INIT : Cold Boot");
}
// cold boot situation
if (lastBootCause == BOOT_CAUSE_MANUAL_REBOOT) // only set this if not set earlier during boot stage.
lastBootCause = BOOT_CAUSE_COLD_BOOT;
log = F("INIT : Cold Boot");
}
addLog(LOG_LEVEL_INFO, log);
addLog(LOG_LEVEL_INFO, log);
saveToRTC(0);
// Setup timers
if (bootMode == 0)
{
for (byte x = 0; x < TASKS_MAX; x++)
if (Settings.TaskDeviceTimer[x] !=0)
timerSensor[x] = millis() + 30000 + (x * Settings.MessageDelay);
if (Settings.UseNTP)
initTime();
timer = millis() + 30000; // startup delay 30 sec
}
else
{
for (byte x = 0; x < TASKS_MAX; x++)
timerSensor[x] = millis() + 0;
timer = millis() + 0; // no startup from deepsleep wake up
}
#if FEATURE_ADC_VCC
vcc = ESP.getVcc() / 1000.0;
timer100ms = millis() + 100; // timer for periodic actions 10 x per/sec
timer1s = millis() + 1000; // timer for periodic actions once per/sec
timerwd = millis() + 30000; // timer for watchdog once per 30 sec
#if FEATURE_TIME
if (Settings.UseNTP)
initTime();
#endif
// Start DNS, only used if the ESP has no valid WiFi config
// It will reply with it's own address on all DNS requests
// (captive portal concept)
if (wifiSetup)
dnsServer.start(DNS_PORT, "*", apIP);
#if FEATURE_ADC_VCC
vcc = ESP.getVcc() / 1000.0;
#endif
// Start DNS, only used if the ESP has no valid WiFi config
// It will reply with it's own address on all DNS requests
// (captive portal concept)
if (wifiSetup)
dnsServer.start(DNS_PORT, "*", apIP);
if (Settings.UseRules)
{
String event = F("System#Boot");
rulesProcessing(event);
}
if (Settings.UseRules)
{
String event = F("System#Boot");
rulesProcessing(event);
}
RTC.deepSleepState=0;
saveToRTC();
else
{
Serial.println(F("Entered Rescue mode!"));
}
}
@@ -769,7 +670,7 @@ void loop()
if (wifiSetupConnect)
{
// try to connect for setup wizard
WifiConnect(true,1);
WifiConnect(1);
wifiSetupConnect = false;
}
@@ -778,48 +679,25 @@ void loop()
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
serial();
// Deep sleep mode, just run all tasks one time and go back to sleep as fast as possible
if (Settings.deepSleep)
if (systemOK)
{
run50TimesPerSecond();
run10TimesPerSecond();
runEach30Seconds();
runOncePerSecond();
deepSleep(Settings.Delay);
//deepsleep will never return, its a special kind of reboot
}
//normal mode, run each task when its time
else
{
if (millis() > timer20ms)
run50TimesPerSecond();
if (millis() > timer100ms)
run10TimesPerSecond();
if (millis() > timerwd)
runEach30Seconds();
if (millis() > timer1s)
runOncePerSecond();
if (millis() > timerwd)
runEach30Seconds();
backgroundtasks();
}
else
delay(1);
}
/*********************************************************************************************\
* Tasks that run 50 times per second
\*********************************************************************************************/
void run50TimesPerSecond()
{
timer20ms = millis() + 20;
PluginCall(PLUGIN_FIFTY_PER_SECOND, 0, dummyString);
}
/*********************************************************************************************\
* Tasks that run 10 times per second
\*********************************************************************************************/
@@ -843,16 +721,6 @@ void run10TimesPerSecond()
\*********************************************************************************************/
void runOncePerSecond()
{
dailyResetCounter++;
if (dailyResetCounter > 86400) // 1 day elapsed... //86400
{
RTC.flashDayCounter=0;
saveToRTC();
dailyResetCounter=0;
String log = F("SYS : Reset 24h counters");
addLog(LOG_LEVEL_INFO, log);
}
timer1s = millis() + 1000;
checkSensors();
@@ -879,10 +747,11 @@ void runOncePerSecond()
cmd_within_mainloop = 0;
}
#if FEATURE_TIME
// clock events
if (Settings.UseNTP)
checkTime();
#endif
unsigned long timer = micros();
PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummyString);
@@ -934,8 +803,10 @@ void runEach30Seconds()
sendSysInfoUDP(1);
refreshNodeList();
MQTTCheck();
#if FEATURE_SSDP
if (Settings.UseSSDP)
SSDP_update();
#endif
#if FEATURE_ADC_VCC
vcc = ESP.getVcc() / 1000.0;
#endif
@@ -954,34 +825,48 @@ void runEach30Seconds()
\*********************************************************************************************/
void checkSensors()
{
//check all the devices and only run the sendtask if its time, or we if we used deep sleep mode
for (byte x = 0; x < TASKS_MAX; x++)
// Check sensors and send data to controller when sensor timer has elapsed
// If deepsleep, use the single timer
if (Settings.deepSleep)
{
if (
(Settings.TaskDeviceTimer[x] != 0) &&
(Settings.deepSleep || (millis() > timerSensor[x]))
)
if (millis() > timer)
{
timerSensor[x] = millis() + Settings.TaskDeviceTimer[x] * 1000;
if (timerSensor[x] == 0) // small fix if result is 0, else timer will be stopped...
timerSensor[x] = 1;
SensorSendTask(x);
timer = millis() + Settings.Delay * 1000;
SensorSend();
saveToRTC(1);
String log = F("Enter deep sleep...");
addLog(LOG_LEVEL_INFO, log);
String event = F("System#Sleep");
rulesProcessing(event);
ESP.deepSleep(Settings.Delay * 1000000, WAKE_RF_DEFAULT); // Sleep for set delay
}
}
else // use individual timers for tasks
{
for (byte x = 0; x < TASKS_MAX; x++)
{
if ((Settings.TaskDeviceTimer[x] != 0) && (millis() > timerSensor[x]))
{
timerSensor[x] = millis() + Settings.TaskDeviceTimer[x] * 1000;
if (timerSensor[x] == 0) // small fix if result is 0, else timer will be stopped...
timerSensor[x] = 1;
SensorSendTask(x);
}
}
}
saveUserVarToRTC();
}
/*********************************************************************************************\
* send all sensordata
\*********************************************************************************************/
// void SensorSendAll()
// {
// for (byte x = 0; x < TASKS_MAX; x++)
// {
// SensorSendTask(x);
// }
// }
void SensorSend()
{
for (byte x = 0; x < TASKS_MAX; x++)
{
SensorSendTask(x);
}
}
/*********************************************************************************************\
@@ -989,7 +874,7 @@ void checkSensors()
\*********************************************************************************************/
void SensorSendTask(byte TaskIndex)
{
if (Settings.TaskDeviceEnabled[TaskIndex])
if (Settings.TaskDeviceID[TaskIndex] != 0)
{
byte varIndex = TaskIndex * VARS_PER_TASK;
@@ -1000,7 +885,7 @@ void SensorSendTask(byte TaskIndex)
struct EventStruct TempEvent;
TempEvent.TaskIndex = TaskIndex;
TempEvent.BaseVarIndex = varIndex;
// TempEvent.idx = Settings.TaskDeviceID[TaskIndex]; todo check
TempEvent.idx = Settings.TaskDeviceID[TaskIndex];
TempEvent.sensorType = Device[DeviceIndex].VType;
float preValue[VARS_PER_TASK]; // store values before change, in case we need it in the formula
@@ -1023,8 +908,8 @@ void SensorSendTask(byte TaskIndex)
float value = UserVar[varIndex + varNr];
float result = 0;
String svalue = String(value);
formula.replace(F("%pvalue%"), spreValue);
formula.replace(F("%value%"), svalue);
formula.replace("%pvalue%", spreValue);
formula.replace("%value%", svalue);
byte error = Calculate(formula.c_str(), &result);
if (error == 0)
UserVar[varIndex + varNr] = result;
@@ -1135,18 +1020,5 @@ void backgroundtasks()
MQTTclient.loop();
statusLED(false);
checkUDP();
#ifdef FEATURE_ARDUINO_OTA
ArduinoOTA.handle();
//once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails)
while (ArduinoOTAtriggered)
{
yield();
ArduinoOTA.handle();
}
#endif
yield();
}
+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");
}
}
+403 -478
View File
File diff suppressed because it is too large Load Diff
+10 -13
View File
@@ -153,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]);
@@ -279,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,20 +292,15 @@ void SendUDPCommand(byte destUnit, char* data, byte dataLength)
\*********************************************************************************************/
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();
@@ -344,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);
@@ -388,6 +382,7 @@ void sendSysInfoUDP(byte repeats)
}
#if FEATURE_SSDP
/********************************************************************************************\
Respond to HTTP XML requests for SSDP information
\*********************************************************************************************/
@@ -429,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>"
@@ -704,3 +699,5 @@ void SSDP_update() {
}
}
#endif
+5 -6
View File
@@ -1,11 +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:
This is the development branch for the next upcoming release (2.0.0). This is also known as ESPEasyMega.
Current development branch: https://github.com/letscontrolit/ESPEasy/tree/mega (new features + fixes from v2.0 )
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
Next stable version: https://github.com/letscontrolit/ESPEasy/tree/v2.0 (fixes only)
Binary development releases are here: https://github.com/letscontrolit/ESPEasy/releases
Details and discussion are on the Experimental forum: http://www.letscontrolit.com/forum/viewtopic.php?f=18&t=2257&p=13600#p13600
+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"
File diff suppressed because it is too large Load Diff
+3 -16
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,12 +73,7 @@ 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();
@@ -99,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(0);
break;
}
else
@@ -134,11 +128,6 @@ boolean WifiConnect(boolean primary, byte connectAttempts)
WifiAPMode(true);
}
}
if (WiFi.status() == WL_CONNECTED)
return true;
return false;
}
@@ -200,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;
}
+4 -8
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;
}
@@ -31,20 +30,17 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
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"));
@@ -85,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();
+7 -11
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;
}
@@ -31,20 +30,17 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
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: ");
@@ -94,7 +90,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
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);
+8 -20
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;
}
@@ -73,28 +72,22 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
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,17 +95,12 @@ 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;
}
+7 -11
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;
}
@@ -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
+7 -11
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;
}
@@ -31,20 +30,17 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
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"));
@@ -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: ");
@@ -132,7 +128,7 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
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);
+17 -22
View File
@@ -20,7 +20,6 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
Protocol[protocolCount].usesID = false;
break;
}
@@ -32,8 +31,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_TEMPLATE:
{
event->String1 = "";
event->String2 = F("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%");
strcpy_P(Settings.MQTTpublish, PSTR("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%"));
break;
}
@@ -66,30 +64,27 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
//********************************************************************************
boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
String authHeader = "";
if ((SecuritySettings.ControllerUser[event->ControllerIndex][0] != 0) && (SecuritySettings.ControllerPassword[event->ControllerIndex][0] != 0))
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
{
base64 encoder;
String auth = SecuritySettings.ControllerUser[event->ControllerIndex];
String auth = SecuritySettings.ControllerUser;
auth += ":";
auth += SecuritySettings.ControllerPassword[event->ControllerIndex];
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"), 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"));
@@ -104,22 +99,22 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String url = "/";
url += ControllerSettings.Publish;
url.replace(F("%sysname%"), URLEncode(Settings.Name));
url.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName));
url.replace(F("%id%"), String(event->idx));
url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
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(F("%value%"), String(longValue));
url.replace("%value%", String(longValue));
else
url.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
url.replace("%value%", toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
String hostName = host;
if (ControllerSettings.UseDNS)
hostName = ControllerSettings.HostName;
if (Settings.UseDNS)
hostName = Settings.ControllerHostName;
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
@@ -135,7 +130,7 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
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);
+13 -17
View File
@@ -35,7 +35,6 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesTemplate = false;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].usesID = false;
Protocol[protocolCount].defaultPort = 8383;
break;
}
@@ -45,7 +44,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
string = F(CPLUGIN_NAME_009);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
@@ -73,7 +72,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
// embed IP, important if there is NAT/PAT
char ipStr[20];
IPAddress ip = WiFi.localIP();
sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
sprintf(ipStr, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
ESP["ip"] = ipStr;
// Create nested SENSOR json object
@@ -116,7 +115,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
char buffer[root.measureLength() +1];
root.printTo(buffer, sizeof(buffer));
// Push data to server
FHEMHTTPsend(url, buffer, event->ControllerIndex);
FHEMHTTPsend(url, buffer);
break;
}
}
@@ -127,19 +126,16 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
//********************************************************************************
// FHEM HTTP request
//********************************************************************************
boolean FHEMHTTPsend(String url, char* buffer, byte index)
boolean FHEMHTTPsend(String url, char* buffer)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(index, (byte*)&ControllerSettings, sizeof(ControllerSettings));
boolean success = false;
String authHeader = "";
if ((SecuritySettings.ControllerUser[index][0] != 0) && (SecuritySettings.ControllerPassword[index][0] != 0)) {
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) {
base64 encoder;
String auth = SecuritySettings.ControllerUser[index];
String auth = SecuritySettings.ControllerUser;
auth += ":";
auth += SecuritySettings.ControllerPassword[index];
auth += SecuritySettings.ControllerPassword;
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
}
@@ -148,14 +144,14 @@ boolean FHEMHTTPsend(String url, char* buffer, byte index)
addLog(LOG_LEVEL_DEBUG_MORE, log);
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);
@@ -184,14 +180,14 @@ boolean FHEMHTTPsend(String url, char* buffer, byte index)
String helper = line;
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 : Success"));
success = true;
}
else if (line.substring(0, 24) == F("HTTP/1.1 400 Bad Request")) {
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
else if (line.substring(0, 25) == F("HTTP/1.1 401 Unauthorized")) {
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
addLog(LOG_LEVEL_DEBUG, log);
+12 -17
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;
}
@@ -66,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);
@@ -83,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();
+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
+38 -40
View File
@@ -6,7 +6,6 @@
#define PLUGIN_ID_001 1
#define PLUGIN_NAME_001 "Switch input"
#define PLUGIN_VALUENAME1_001 "Switch"
boolean Plugin_001(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -109,17 +108,17 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(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)
{
String plugin2 = WebServer.arg(F("plugin_001_dimvalue"));
String plugin2 = WebServer.arg("plugin_001_dimvalue");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
}
String plugin3 = WebServer.arg(F("plugin_001_button"));
String plugin3 = WebServer.arg("plugin_001_button");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
String plugin4 = WebServer.arg(F("plugin_001_boot"));
String plugin4 = WebServer.arg("plugin_001_boot");
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = (plugin4 == "on");
success = true;
@@ -225,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;
@@ -328,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;
}
+1 -1
View File
@@ -53,4 +53,4 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
}
}
return success;
}
}
+2 -2
View File
@@ -98,9 +98,9 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_003"));
String plugin1 = WebServer.arg("plugin_003");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg(F("plugin_003_countertype"));
String plugin2 = WebServer.arg("plugin_003_countertype");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
success = true;
break;
+1 -1
View File
@@ -81,7 +81,7 @@ boolean Plugin_004(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
uint8_t addr[8];
String plugin1 = WebServer.arg(F("plugin_004_dev"));
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
+2 -3
View File
@@ -76,7 +76,7 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_005_dhttype"));
String plugin1 = WebServer.arg("plugin_005_dhttype");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
@@ -117,8 +117,7 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
dht_dat[i] = data;
else
{
String log = F("DHT : protocol timeout!");
addLog(LOG_LEVEL_ERROR, log);
addLog(LOG_LEVEL_ERROR, (char*)"DHT : protocol timeout!");
error = true;
}
}
+1 -1
View File
@@ -57,7 +57,7 @@ boolean Plugin_006(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String elev = WebServer.arg(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
}
+2 -2
View File
@@ -59,7 +59,7 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_009_boot"));
String plugin1 = WebServer.arg("plugin_009_boot");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = (plugin1 == "on");
success = true;
@@ -311,4 +311,4 @@ boolean Plugin_009_Config(byte Par1, byte Par2)
Wire.endTransmission();
}
}
+7 -90
View File
@@ -9,29 +9,6 @@
#define BH1750_ADDRESS_1 0x23
#define BH1750_ADDRESS_2 0x5c
// 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
boolean Plugin_010_init_1 = false;
boolean Plugin_010_init_2 = false;
@@ -93,45 +70,14 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
}
string += F("</select>");
byte choiceMode = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String optionsMode[6];
optionsMode[0] = F("BH1750_CONTINUOUS_HIGH_RES_MODE");
optionsMode[1] = F("BH1750_CONTINUOUS_HIGH_RES_MODE_2");
optionsMode[2] = F("BH1750_CONTINUOUS_LOW_RES_MODE");
optionsMode[3] = F("BH1750_ONE_TIME_HIGH_RES_MODE");
optionsMode[4] = F("BH1750_ONE_TIME_HIGH_RES_MODE_2");
optionsMode[5] = F("BH1750_ONE_TIME_LOW_RES_MODE");
int optionValuesMode[6];
optionValuesMode[0] = 0;
optionValuesMode[1] = 1;
optionValuesMode[2] = 2;
optionValuesMode[3] = 3;
optionValuesMode[4] = 4;
optionValuesMode[5] = 5;
string += F("<TR><TD>measurment mode:<TD><select name='plugin_010_mode'>");
for (byte x = 0; x < 6; x++)
{
string += F("<option value='");
string += optionValuesMode[x];
string += "'";
if (choiceMode == optionValuesMode[x])
string += F(" selected");
string += ">";
string += optionsMode[x];
string += F("</option>");
}
string += F("</select>");
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_010"));
String plugin1 = WebServer.arg("plugin_010");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg(F("plugin_010_mode"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
success = true;
break;
}
@@ -152,33 +98,11 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
Plugin_010_init = &Plugin_010_init_2;
}
byte mode = -1;
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1]) {
case 0:
mode = BH1750_CONTINUOUS_HIGH_RES_MODE;
break;
case 1:
mode = BH1750_CONTINUOUS_HIGH_RES_MODE_2;
break;
case 2:
mode = BH1750_CONTINUOUS_LOW_RES_MODE;
break;
case 3:
mode = BH1750_ONE_TIME_HIGH_RES_MODE;
break;
case 4:
mode = BH1750_ONE_TIME_HIGH_RES_MODE_2;
break;
case 5:
mode = BH1750_ONE_TIME_LOW_RES_MODE;
break;
if (!*Plugin_010_init)
{
*Plugin_010_init = Plugin_010_setResolution(address);
}
*Plugin_010_init = Plugin_010_setResolution(address,mode);
delay(150); //need this otherwise we get one wrong reading after mode change
if (Wire.requestFrom(address, (uint8_t)2) == 2)
{
byte b1 = Wire.read();
@@ -187,16 +111,9 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
if (b1 != 0xff || b2 != 0xff) { //pm-cz: Add maximum range check
val=((b1<<8)|b2)/1.2;
}
if (mode==BH1750_CONTINUOUS_HIGH_RES_MODE_2 || mode==BH1750_ONE_TIME_HIGH_RES_MODE_2) {
UserVar[event->BaseVarIndex] = val/2;
}
else {
UserVar[event->BaseVarIndex] = val;
}
UserVar[event->BaseVarIndex] = val;
String log = F("LUX 0x");
log += String(address,HEX);
log += F(" Mode: 0x");
log += String(mode,HEX);
log += F(" : Light intensity: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO,log);
@@ -208,9 +125,9 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
return success;
}
boolean Plugin_010_setResolution(uint8_t address, byte mode){
boolean Plugin_010_setResolution(uint8_t address){
Wire.beginTransmission(address);
Wire.write(mode);
Wire.write(0x10); // 1 lx resolution
Wire.endTransmission();
return true;
}
+1 -1
View File
@@ -72,7 +72,7 @@ boolean Plugin_011(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_011"));
String plugin1 = WebServer.arg("plugin_011");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
+6 -4
View File
@@ -122,11 +122,11 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_012_adr"));
String plugin1 = WebServer.arg("plugin_012_adr");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg(F("plugin_012_size"));
String plugin2 = WebServer.arg("plugin_012_size");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
String plugin3 = WebServer.arg(F("plugin_12_timer"));
String plugin3 = WebServer.arg("plugin_12_timer");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
char deviceTemplate[4][80];
@@ -140,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;
@@ -251,4 +253,4 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
}
return success;
}
}
+2 -2
View File
@@ -86,11 +86,11 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(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)
{
String plugin2 = WebServer.arg(F("plugin_013_threshold"));
String plugin2 = WebServer.arg("plugin_013_threshold");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
}
success = true;
+1 -1
View File
@@ -106,7 +106,7 @@ boolean Plugin_014(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(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;
+1 -1
View File
@@ -143,7 +143,7 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_015_integration"));
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;
-4
View File
@@ -75,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);
}
+1 -1
View File
@@ -59,7 +59,7 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_019_boot"));
String plugin1 = WebServer.arg("plugin_019_boot");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = (plugin1 == "on");
success = true;
+19 -17
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;
@@ -114,19 +114,19 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_020_port"));
String plugin1 = WebServer.arg("plugin_020_port");
ExtraTaskSettings.TaskDevicePluginConfigLong[0] = plugin1.toInt();
String plugin2 = WebServer.arg(F("plugin_020_baud"));
String plugin2 = WebServer.arg("plugin_020_baud");
ExtraTaskSettings.TaskDevicePluginConfigLong[1] = plugin2.toInt();
String plugin3 = WebServer.arg(F("plugin_020_data"));
String plugin3 = WebServer.arg("plugin_020_data");
ExtraTaskSettings.TaskDevicePluginConfigLong[2] = plugin3.toInt();
String plugin4 = WebServer.arg(F("plugin_020_parity"));
String plugin4 = WebServer.arg("plugin_020_parity");
ExtraTaskSettings.TaskDevicePluginConfigLong[3] = plugin4.toInt();
String plugin5 = WebServer.arg(F("plugin_020_stop"));
String plugin5 = WebServer.arg("plugin_020_stop");
ExtraTaskSettings.TaskDevicePluginConfigLong[4] = plugin5.toInt();
String plugin6 = WebServer.arg(F("plugin_020_rxwait"));
String plugin6 = WebServer.arg("plugin_020_rxwait");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin6.toInt();
String plugin7 = WebServer.arg(F("plugin_020_events"));
String plugin7 = WebServer.arg("plugin_020_events");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin7.toInt();
success = true;
break;
@@ -179,17 +179,17 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
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--;
char log[40];
@@ -197,7 +197,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
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);
}
@@ -223,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;
@@ -232,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++;
}
@@ -245,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())
@@ -265,7 +265,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
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);
@@ -295,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;"
@@ -330,3 +331,4 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
}
return success;
}
+4 -20
View File
@@ -67,10 +67,10 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_021_task"));
String plugin2 = WebServer.arg(F("plugin_021_value"));
String plugin3 = WebServer.arg(F("plugin_021_setvalue"));
String plugin4 = WebServer.arg(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();
@@ -79,22 +79,6 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
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;
}
+11 -7
View File
@@ -149,25 +149,28 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_023_adr"));
String plugin1 = WebServer.arg("plugin_023_adr");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String plugin2 = WebServer.arg(F("plugin_023_rotate"));
String plugin2 = WebServer.arg("plugin_023_rotate");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
String plugin3 = WebServer.arg(F("plugin_23_timer"));
String plugin3 = WebServer.arg("plugin_23_timer");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
String plugin4 = WebServer.arg(F("plugin_023_size"));
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;
@@ -538,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
}
@@ -97,7 +97,7 @@ boolean Plugin_024(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(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;
+1 -1
View File
@@ -91,7 +91,7 @@ boolean Plugin_025(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_025_gain"));
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;
+2 -2
View File
@@ -72,7 +72,7 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_026"));
String plugin1 = WebServer.arg("plugin_026");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
@@ -111,7 +111,7 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
{
value = (100 - (100 * loopCounterLast / loopCounterMax));
break;
}
}
}
UserVar[event->BaseVarIndex] = value;
String log = F("SYS : ");
+1 -1
View File
@@ -129,7 +129,7 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_027_value"));
String plugin1 = WebServer.arg("plugin_027_value");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
+2 -2
View File
@@ -151,9 +151,9 @@ boolean Plugin_028(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_028_bme280_i2c"));
String plugin1 = WebServer.arg("plugin_028_bme280_i2c");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String elev = WebServer.arg(F("plugin_028_bme280_elev"));
String elev = WebServer.arg("plugin_028_bme280_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
+2 -4
View File
@@ -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
@@ -133,9 +132,9 @@ boolean Plugin_030(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_030_bmp280_i2c"));
String plugin1 = WebServer.arg("plugin_030_bmp280_i2c");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String elev = WebServer.arg(F("plugin_030_bmp280_elev"));
String elev = WebServer.arg("plugin_030_bmp280_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
@@ -232,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;
}
+2 -2
View File
@@ -100,9 +100,9 @@ boolean Plugin_032(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_032_ms5611_i2c"));
String plugin1 = WebServer.arg("plugin_032_ms5611_i2c");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
String elev = WebServer.arg(F("plugin_032_ms5611_elev"));
String elev = WebServer.arg("plugin_032_ms5611_elev");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt();
success = true;
break;
+1 -1
View File
@@ -85,7 +85,7 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg(F("plugin_033_sensortype"));
String plugin1 = WebServer.arg("plugin_033_sensortype");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
+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
+61 -62
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;
}
@@ -120,7 +119,7 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
int optionValues[2];
optionValues[0] = 0x68;
optionValues[1] = 0x69;
string += F("<TR><TD>I2C Address:<TD><select name='plugin_045_address'>");
string += F("<TR><TD>I2C Address:<TD><select name='plugin_118_address'>");
for (byte x = 0; x < 2; x++)
{
string += F("<option value='");
@@ -135,7 +134,7 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
string += F("</select>");
// Setup webform for instance function
choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
string += F("<TR><TD>Function:<TD><select name='plugin_045_function'>");
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");
@@ -164,13 +163,13 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
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.");
string += F("<TR><TD>Detection threshold X:<TD><input type='text' size='6' maxlength='6' name='plugin_045_threshold_x' value='");
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_045_threshold_y' value='");
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_045_threshold_z' value='");
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>");
@@ -179,10 +178,10 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
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].");
string += F("<TR><TD>Min. detection count:<TD><input type='text' size='6' maxlength='6' name='plugin_045_threshold_counter' value='");
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_045_threshold_window' value='");
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("'>");
}
@@ -193,19 +192,19 @@ boolean Plugin_045(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
// Save the vars
String plugin1 = WebServer.arg("plugin_045_address");
String plugin1 = WebServer.arg("plugin_118_address");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_045_function");
plugin1 = WebServer.arg("plugin_118_function");
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_045_threshold_x");
plugin1 = WebServer.arg("plugin_118_threshold_x");
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_045_threshold_y");
plugin1 = WebServer.arg("plugin_118_threshold_y");
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_045_threshold_z");
plugin1 = WebServer.arg("plugin_118_threshold_z");
Settings.TaskDevicePluginConfig[event->TaskIndex][4] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_045_threshold_counter");
plugin1 = WebServer.arg("plugin_118_threshold_counter");
Settings.TaskDevicePluginConfig[event->TaskIndex][5] = plugin1.toInt();
plugin1 = WebServer.arg("plugin_045_threshold_window");
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];
@@ -224,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
@@ -248,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;
@@ -290,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:
@@ -303,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.
@@ -326,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
}
@@ -341,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;
}
@@ -354,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)
@@ -378,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;
@@ -405,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, (char*)"P039 : SPI Init");
addLog(LOG_LEVEL_INFO, (char*)"P120 : SPI Init");
success = true;
break;
@@ -113,7 +115,7 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
optionValues[0] = 1;
optionValues[1] = 2;
//optionValues[2] = 3;
string += F("<TR><TD>Adapter IC:<TD><select name='plugin_039_maxtype'>");
string += F("<TR><TD>Adapter IC:<TD><select name='plugin_120_maxtype'>");
for (byte x = 0; x < 2; x++)
{
string += F("<option value='");
@@ -133,7 +135,7 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg("plugin_039_maxtype");
String plugin1 = WebServer.arg("plugin_120_maxtype");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
success = true;
break;
@@ -147,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;
}
@@ -173,7 +178,7 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
{
UserVar[event->BaseVarIndex] = NAN;
UserVar[event->BaseVarIndex + 1] = NAN;
String log = F("P039 : No Sensor attached !");
String log = F("P120 : No Sensor attached !");
addLog(LOG_LEVEL_INFO, log);
success = false;
}
@@ -188,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);
@@ -209,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;
@@ -229,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
@@ -237,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);
@@ -248,16 +253,16 @@ 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
rawvalue >>= 18;
// Check for negative Values
// +25.00 0000 0001 1001 00
// +25.00 0000 0001 1001 00
// 0.00 0000 0000 0000 00
// -0.25 1111 1111 1111 11
// -1.00 1111 1111 1111 00
@@ -265,11 +270,11 @@ double readMax31855()
if (rawvalue & 0x2000) // Bit 31=1 -> neg Values
{
// Negate all Bits
rawvalue = ~rawvalue;
// Add 1 and make negative
rawvalue = ~rawvalue;
// Add 1 and make negative
rawvalue = (rawvalue + 1) * -1;
}
// Calculate Celsius
return rawvalue * 0.25;
}
@@ -278,3 +283,10 @@ double readMax31855()
return NAN;
}
}
// Convert Celsius to Fahrenheit
double CelsiusToFahrenheit(double celsius) {
return celsius * 9.0 / 5.0 + 32;
}
#endif
+21 -55
View File
@@ -1,3 +1,4 @@
#ifdef PLUGIN_BUILD_DEV
/*
This plug in is written by Dmitry (rel22 ___ inbox.ru)
@@ -8,33 +9,31 @@
DevicePin2 - is TX for ESP
*/
#ifdef PLUGIN_BUILD_TESTING
#define PLUGIN_049
#define PLUGIN_ID_049 49
#define PLUGIN_NAME_049 "NDIR CO2 Sensor MH-Z19 [TESTING]"
#define PLUGIN_VALUENAME1_049 "PPM"
#define PLUGIN_READ_TIMEOUT 3000
#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_049_init = false;
boolean Plugin_149_init = false;
#include <SoftwareSerial.h>
SoftwareSerial *Plugin_049_S8;
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_049(byte function, struct EventStruct *event, String& string)
boolean Plugin_149(byte function, struct EventStruct *event, String& string)
{
bool success = false;
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_049;
Device[++deviceCount].Number = PLUGIN_ID_149;
Device[deviceCount].Type = DEVICE_TYPE_DUAL;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].Ports = 0;
@@ -50,28 +49,20 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_049);
string = F(PLUGIN_NAME_149);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_049));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_149));
break;
}
case PLUGIN_INIT:
{
Plugin_049_S8 = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
Plugin_049_S8->begin(9600);
String log = F("MHZ19: Init OK ");
addLog(LOG_LEVEL_INFO, log);
//delay first read, because hardware needs to initialize on cold boot
//otherwise we get a weird value or read error
timerSensor[event->TaskIndex] = millis() + 15000;
Plugin_049_init = true;
Plugin_149_init = true;
Plugin_149_S8 = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
success = true;
break;
}
@@ -79,51 +70,27 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
case PLUGIN_READ:
{
if (Plugin_049_init)
if (Plugin_149_init)
{
//send read PPM command
int nbBytesSent = Plugin_049_S8->write(mhzCmd, 9);
if (nbBytesSent != 9) {
String log = F("MHZ19: Error, nb bytes sent != 9 : ");
log += nbBytesSent;
addLog(LOG_LEVEL_INFO, log);
}
// get response
memset(mhzResp, 0, sizeof(mhzResp));
long start = millis();
int counter = 0;
while (((millis() - start) < PLUGIN_READ_TIMEOUT) && (counter < 9)) {
if (Plugin_049_S8->available() > 0) {
mhzResp[counter++] = Plugin_049_S8->read();
} else {
delay(10);
}
}
if (counter < 9){
String log = F("MHZ19: Error, timeout while trying to read");
addLog(LOG_LEVEL_INFO, log);
}
unsigned int ppm = 0;
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: Read error : CRC = ");
String log = F("MHZ19: CRC error: ");
log += String(crc); log += " / "; log += String(mhzResp[8]);
log += " bytes read => ";for (i = 0; i < 9; i++) {log += mhzResp[i];log += "/" ;}
addLog(LOG_LEVEL_ERROR, log);
success = false;
break;
} else {
//calculate CO2 PPM
unsigned int mhzRespHigh = (unsigned int) mhzResp[2];
unsigned int mhzRespLow = (unsigned int) mhzResp[3];
ppm = (256*mhzRespHigh) + mhzRespLow;
@@ -141,5 +108,4 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+132 -131
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;
@@ -156,7 +157,7 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
for (byte x = 0; x < nrchoices; x++) {
optionValues[x] = x;
}
string += F("<TR><TD>Plugin function:<TD><select name='plugin_046'>");
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];
@@ -244,7 +245,7 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
String plugin1 = WebServer.arg("plugin_046");
String plugin1 = WebServer.arg("plugin_186");
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
if (plugin1.toInt()==0) {
String plugin2 = WebServer.arg("taskdevicepin1");
@@ -262,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;
}
@@ -281,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;
}
@@ -308,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;
@@ -324,9 +325,9 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
data >>= 1;
}
}
Plugin_046_MasterSlave = false;
Plugin_046_newData = false;
if (PLUGIN_046_DEBUG) {
Plugin_186_MasterSlave = false;
Plugin_186_newData = false;
if (PLUGIN_186_DEBUG) {
String log = "Ventus W266 Rcvd(";
log += hour();
log += ":";
@@ -336,14 +337,14 @@ boolean Plugin_046(byte function, struct EventStruct *event, String& string)
if (tm.Second < 10) { log += "0"; }
log += tm.Second;
log += ") ";
for (int i = 0; i < Plugin_046_Payload; i++) {
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 += ":";
}
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;
}
@@ -358,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.
}
}
}
@@ -368,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?
@@ -376,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;
@@ -388,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;
@@ -399,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
@@ -478,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.
-25
View File
@@ -1,25 +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/test_1024/firmware.bin dist/"ESPEasy_$VERSION""_test_1024.bin"
cp .pioenvs/test_4096/firmware.bin dist/"ESPEasy_$VERSION""_test_4096.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"
#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.
-121
View File
@@ -1,121 +0,0 @@
-----------------------------
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.
@@ -1,47 +0,0 @@
{
"description": "Library for the Adafruit Motor Shield V2 for Arduino. It supports DC motors & stepper motors with microstepping as well as stacking-support.",
"repository": {
"url": "https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library",
"type": "git"
},
"platforms": [
"atmelavr",
"atmelsam",
"espressif8266",
"intel_arc32",
"microchippic32",
"nordicnrf51",
"teensy",
"timsp430"
],
"export": {
"exclude": [
"extras",
"docs",
"tests",
"test",
"*.doxyfile",
"*.pdf"
],
"include": null
},
"authors": [
{
"maintainer": true,
"name": "Adafruit",
"url": null,
"email": "info@adafruit.com"
}
],
"keywords": [
"device",
"control"
],
"id": 783,
"name": "Adafruit Motor Shield V2 Library",
"frameworks": [
"arduino"
],
"version": "1.0.4",
"homepage": null
}
@@ -1,397 +0,0 @@
/******************************************************************
This is the library for the Adafruit Motor Shield V2 for Arduino.
It supports DC motors & Stepper motors with microstepping as well
as stacking-support. It is *not* compatible with the V1 library!
It will only work with https://www.adafruit.com/products/1483
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
******************************************************************/
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
#include "Adafruit_MotorShield.h"
#include <Adafruit_MS_PWMServoDriver.h>
#if defined(ARDUINO_SAM_DUE)
#define WIRE Wire1
#else
#define WIRE Wire
#endif
#if (MICROSTEPS == 8)
uint8_t microstepcurve[] = {0, 50, 98, 142, 180, 212, 236, 250, 255};
#elif (MICROSTEPS == 16)
uint8_t microstepcurve[] = {0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255};
#endif
Adafruit_MotorShield::Adafruit_MotorShield(uint8_t addr) {
_addr = addr;
_pwm = Adafruit_MS_PWMServoDriver(_addr);
}
void Adafruit_MotorShield::begin(uint16_t freq) {
// init PWM w/_freq
WIRE.begin();
_pwm.begin();
_freq = freq;
_pwm.setPWMFreq(_freq); // This is the maximum PWM frequency
for (uint8_t i=0; i<16; i++)
_pwm.setPWM(i, 0, 0);
}
void Adafruit_MotorShield::setPWM(uint8_t pin, uint16_t value) {
if (value > 4095) {
_pwm.setPWM(pin, 4096, 0);
} else
_pwm.setPWM(pin, 0, value);
}
void Adafruit_MotorShield::setPin(uint8_t pin, boolean value) {
if (value == LOW)
_pwm.setPWM(pin, 0, 0);
else
_pwm.setPWM(pin, 4096, 0);
}
Adafruit_DCMotor *Adafruit_MotorShield::getMotor(uint8_t num) {
if (num > 4) return NULL;
num--;
if (dcmotors[num].motornum == 0) {
// not init'd yet!
dcmotors[num].motornum = num;
dcmotors[num].MC = this;
uint8_t pwm, in1, in2;
if (num == 0) {
pwm = 8; in2 = 9; in1 = 10;
} else if (num == 1) {
pwm = 13; in2 = 12; in1 = 11;
} else if (num == 2) {
pwm = 2; in2 = 3; in1 = 4;
} else if (num == 3) {
pwm = 7; in2 = 6; in1 = 5;
}
dcmotors[num].PWMpin = pwm;
dcmotors[num].IN1pin = in1;
dcmotors[num].IN2pin = in2;
}
return &dcmotors[num];
}
Adafruit_StepperMotor *Adafruit_MotorShield::getStepper(uint16_t steps, uint8_t num) {
if (num > 2) return NULL;
num--;
if (steppers[num].steppernum == 0) {
// not init'd yet!
steppers[num].steppernum = num;
steppers[num].revsteps = steps;
steppers[num].MC = this;
uint8_t pwma, pwmb, ain1, ain2, bin1, bin2;
if (num == 0) {
pwma = 8; ain2 = 9; ain1 = 10;
pwmb = 13; bin2 = 12; bin1 = 11;
} else if (num == 1) {
pwma = 2; ain2 = 3; ain1 = 4;
pwmb = 7; bin2 = 6; bin1 = 5;
}
steppers[num].PWMApin = pwma;
steppers[num].PWMBpin = pwmb;
steppers[num].AIN1pin = ain1;
steppers[num].AIN2pin = ain2;
steppers[num].BIN1pin = bin1;
steppers[num].BIN2pin = bin2;
}
return &steppers[num];
}
/******************************************
MOTORS
******************************************/
Adafruit_DCMotor::Adafruit_DCMotor(void) {
MC = NULL;
motornum = 0;
PWMpin = IN1pin = IN2pin = 0;
}
void Adafruit_DCMotor::run(uint8_t cmd) {
switch (cmd) {
case FORWARD:
MC->setPin(IN2pin, LOW); // take low first to avoid 'break'
MC->setPin(IN1pin, HIGH);
break;
case BACKWARD:
MC->setPin(IN1pin, LOW); // take low first to avoid 'break'
MC->setPin(IN2pin, HIGH);
break;
case RELEASE:
MC->setPin(IN1pin, LOW);
MC->setPin(IN2pin, LOW);
break;
}
}
void Adafruit_DCMotor::setSpeed(uint8_t speed) {
MC->setPWM(PWMpin, speed*16);
}
/******************************************
STEPPERS
******************************************/
Adafruit_StepperMotor::Adafruit_StepperMotor(void) {
revsteps = steppernum = currentstep = 0;
}
/*
uint16_t steps, Adafruit_MotorShield controller) {
revsteps = steps;
steppernum = 1;
currentstep = 0;
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
// enable both H bridges
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(3, HIGH);
// use PWM for microstepping support
MC->setPWM(1, 255);
MC->setPWM(2, 255);
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
// enable both H bridges
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
// use PWM for microstepping support
// use PWM for microstepping support
MC->setPWM(3, 255);
MC->setPWM(4, 255);
}
}
*/
void Adafruit_StepperMotor::setSpeed(uint16_t rpm) {
//Serial.println("steps per rev: "); Serial.println(revsteps);
//Serial.println("RPM: "); Serial.println(rpm);
usperstep = 60000000 / ((uint32_t)revsteps * (uint32_t)rpm);
}
void Adafruit_StepperMotor::release(void) {
MC->setPin(AIN1pin, LOW);
MC->setPin(AIN2pin, LOW);
MC->setPin(BIN1pin, LOW);
MC->setPin(BIN2pin, LOW);
MC->setPWM(PWMApin, 0);
MC->setPWM(PWMBpin, 0);
}
void Adafruit_StepperMotor::step(uint16_t steps, uint8_t dir, uint8_t style) {
uint32_t uspers = usperstep;
uint8_t ret = 0;
if (style == INTERLEAVE) {
uspers /= 2;
}
else if (style == MICROSTEP) {
uspers /= MICROSTEPS;
steps *= MICROSTEPS;
#ifdef MOTORDEBUG
Serial.print("steps = "); Serial.println(steps, DEC);
#endif
}
while (steps--) {
//Serial.println("step!"); Serial.println(uspers);
ret = onestep(dir, style);
delayMicroseconds(uspers);
}
}
uint8_t Adafruit_StepperMotor::onestep(uint8_t dir, uint8_t style) {
uint8_t a, b, c, d;
uint8_t ocrb, ocra;
ocra = ocrb = 255;
// next determine what sort of stepping procedure we're up to
if (style == SINGLE) {
if ((currentstep/(MICROSTEPS/2)) % 2) { // we're at an odd step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
}
else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next even step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
}
else {
currentstep -= MICROSTEPS;
}
}
} else if (style == DOUBLE) {
if (! (currentstep/(MICROSTEPS/2) % 2)) { // we're at an even step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next odd step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
} else {
currentstep -= MICROSTEPS;
}
}
} else if (style == INTERLEAVE) {
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
}
if (style == MICROSTEP) {
if (dir == FORWARD) {
currentstep++;
} else {
// BACKWARDS
currentstep--;
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
ocra = ocrb = 0;
if ( (currentstep >= 0) && (currentstep < MICROSTEPS)) {
ocra = microstepcurve[MICROSTEPS - currentstep];
ocrb = microstepcurve[currentstep];
} else if ( (currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2)) {
ocra = microstepcurve[currentstep - MICROSTEPS];
ocrb = microstepcurve[MICROSTEPS*2 - currentstep];
} else if ( (currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3)) {
ocra = microstepcurve[MICROSTEPS*3 - currentstep];
ocrb = microstepcurve[currentstep - MICROSTEPS*2];
} else if ( (currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4)) {
ocra = microstepcurve[currentstep - MICROSTEPS*3];
ocrb = microstepcurve[MICROSTEPS*4 - currentstep];
}
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
#ifdef MOTORDEBUG
Serial.print("current step: "); Serial.println(currentstep, DEC);
Serial.print(" pwmA = "); Serial.print(ocra, DEC);
Serial.print(" pwmB = "); Serial.println(ocrb, DEC);
#endif
MC->setPWM(PWMApin, ocra*16);
MC->setPWM(PWMBpin, ocrb*16);
// release all
uint8_t latch_state = 0; // all motor pins to 0
//Serial.println(step, DEC);
if (style == MICROSTEP) {
if ((currentstep >= 0) && (currentstep < MICROSTEPS))
latch_state |= 0x03;
if ((currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2))
latch_state |= 0x06;
if ((currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3))
latch_state |= 0x0C;
if ((currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4))
latch_state |= 0x09;
} else {
switch (currentstep/(MICROSTEPS/2)) {
case 0:
latch_state |= 0x1; // energize coil 1 only
break;
case 1:
latch_state |= 0x3; // energize coil 1+2
break;
case 2:
latch_state |= 0x2; // energize coil 2 only
break;
case 3:
latch_state |= 0x6; // energize coil 2+3
break;
case 4:
latch_state |= 0x4; // energize coil 3 only
break;
case 5:
latch_state |= 0xC; // energize coil 3+4
break;
case 6:
latch_state |= 0x8; // energize coil 4 only
break;
case 7:
latch_state |= 0x9; // energize coil 1+4
break;
}
}
#ifdef MOTORDEBUG
Serial.print("Latch: 0x"); Serial.println(latch_state, HEX);
#endif
if (latch_state & 0x1) {
// Serial.println(AIN2pin);
MC->setPin(AIN2pin, HIGH);
} else {
MC->setPin(AIN2pin, LOW);
}
if (latch_state & 0x2) {
MC->setPin(BIN1pin, HIGH);
// Serial.println(BIN1pin);
} else {
MC->setPin(BIN1pin, LOW);
}
if (latch_state & 0x4) {
MC->setPin(AIN1pin, HIGH);
// Serial.println(AIN1pin);
} else {
MC->setPin(AIN1pin, LOW);
}
if (latch_state & 0x8) {
MC->setPin(BIN2pin, HIGH);
// Serial.println(BIN2pin);
} else {
MC->setPin(BIN2pin, LOW);
}
return currentstep;
}
@@ -1,102 +0,0 @@
/******************************************************************
This is the library for the Adafruit Motor Shield V2 for Arduino.
It supports DC motors & Stepper motors with microstepping as well
as stacking-support. It is *not* compatible with the V1 library!
It will only work with https://www.adafruit.com/products/1483
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
******************************************************************/
#ifndef _Adafruit_MotorShield_h_
#define _Adafruit_MotorShield_h_
#include <inttypes.h>
#include <Wire.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
//#define MOTORDEBUG
#define MICROSTEPS 16 // 8 or 16
#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7
#define FORWARD 1
#define BACKWARD 2
#define BRAKE 3
#define RELEASE 4
#define SINGLE 1
#define DOUBLE 2
#define INTERLEAVE 3
#define MICROSTEP 4
class Adafruit_MotorShield;
class Adafruit_DCMotor
{
public:
Adafruit_DCMotor(void);
friend class Adafruit_MotorShield;
void run(uint8_t);
void setSpeed(uint8_t);
private:
uint8_t PWMpin, IN1pin, IN2pin;
Adafruit_MotorShield *MC;
uint8_t motornum;
};
class Adafruit_StepperMotor {
public:
Adafruit_StepperMotor(void);
friend class Adafruit_MotorShield;
void step(uint16_t steps, uint8_t dir, uint8_t style = SINGLE);
void setSpeed(uint16_t);
uint8_t onestep(uint8_t dir, uint8_t style);
void release(void);
uint32_t usperstep;
private:
uint8_t PWMApin, AIN1pin, AIN2pin;
uint8_t PWMBpin, BIN1pin, BIN2pin;
uint16_t revsteps; // # steps per revolution
uint8_t currentstep;
Adafruit_MotorShield *MC;
uint8_t steppernum;
};
class Adafruit_MotorShield
{
public:
Adafruit_MotorShield(uint8_t addr = 0x60);
friend class Adafruit_DCMotor;
void begin(uint16_t freq = 1600);
void setPWM(uint8_t pin, uint16_t val);
void setPin(uint8_t pin, boolean val);
Adafruit_DCMotor *getMotor(uint8_t n);
Adafruit_StepperMotor *getStepper(uint16_t steps, uint8_t n);
private:
uint8_t _addr;
uint16_t _freq;
Adafruit_DCMotor dcmotors[4];
Adafruit_StepperMotor steppers[2];
Adafruit_MS_PWMServoDriver _pwm;
};
#endif
-45
View File
@@ -1,45 +0,0 @@
# Adafruit Motor Shield v2 Library
This is the library for the Adafruit Motor Shield V2 for Arduino.
It supports DC motors & Stepper motors with microstepping as well
as stacking-support. It is *not* compatible with the V1 library!
It will only work with https://www.adafruit.com/products/1438
<!-- START COMPATIBILITY TABLE -->
## Compatibility
MCU | Tested Works | Doesn't Work | Not Tested | Notes
----------------- | :----------: | :----------: | :---------: | -----
Atmega328 @ 16MHz | X | | |
Atmega328 @ 12MHz | X | | |
Atmega32u4 @ 16MHz | X | | |
Atmega32u4 @ 8MHz | X | | |
ESP8266 | | | X |
Atmega2560 @ 16MHz | X | | |
ATSAM3X8E | | X | |
ATSAM21D | | X | |
ATtiny85 @ 16MHz | | | X |
ATtiny85 @ 8MHz | | | X |
* ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
* ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
* ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
* ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
* ESP8266 : Adafruit Huzzah
* ATmega2560 @ 16MHz : Arduino Mega
* ATSAM3X8E : Arduino Due
* ATSAM21D : Arduino Zero, M0 Pro
* ATtiny85 @ 16MHz : Adafruit Trinket 5V
* ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
<!-- END COMPATIBILITY TABLE -->
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
@@ -1,52 +0,0 @@
// ConstantSpeed.pde
// -*- mode: C++ -*-
//
// Shows how to run AccelStepper in the simplest,
// fixed speed mode with no accelerations
// Requires the Adafruit_Motorshield v2 library
// https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library
// And AccelStepper with AFMotor support
// https://github.com/adafruit/AccelStepper
// This tutorial is for Adafruit Motorshield v2 only!
// Will not work with v1 shields
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myStepper1 = AFMS.getStepper(200, 2);
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
void forwardstep1() {
myStepper1->onestep(FORWARD, SINGLE);
}
void backwardstep1() {
myStepper1->onestep(BACKWARD, SINGLE);
}
AccelStepper Astepper1(forwardstep1, backwardstep1); // use functions to step
void setup()
{
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Stepper test!");
AFMS.begin(); // create with the default frequency 1.6KHz
//AFMS.begin(1000); // OR with a different frequency, say 1KHz
Astepper1.setSpeed(50);
}
void loop()
{
Astepper1.runSpeed();
}
@@ -1,90 +0,0 @@
// Shows how to run three Steppers at once with varying speeds
//
// Requires the Adafruit_Motorshield v2 library
// https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library
// And AccelStepper with AFMotor support
// https://github.com/adafruit/AccelStepper
// This tutorial is for Adafruit Motorshield v2 only!
// Will not work with v1 shields
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMSbot(0x61); // Rightmost jumper closed
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
// Connect two steppers with 200 steps per revolution (1.8 degree)
// to the top shield
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
// Connect one stepper with 200 steps per revolution (1.8 degree)
// to the bottom shield
Adafruit_StepperMotor *myStepper3 = AFMSbot.getStepper(200, 2);
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
// wrappers for the first motor!
void forwardstep1() {
myStepper1->onestep(FORWARD, SINGLE);
}
void backwardstep1() {
myStepper1->onestep(BACKWARD, SINGLE);
}
// wrappers for the second motor!
void forwardstep2() {
myStepper2->onestep(FORWARD, DOUBLE);
}
void backwardstep2() {
myStepper2->onestep(BACKWARD, DOUBLE);
}
// wrappers for the third motor!
void forwardstep3() {
myStepper3->onestep(FORWARD, INTERLEAVE);
}
void backwardstep3() {
myStepper3->onestep(BACKWARD, INTERLEAVE);
}
// Now we'll wrap the 3 steppers in an AccelStepper object
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);
AccelStepper stepper3(forwardstep3, backwardstep3);
void setup()
{
AFMSbot.begin(); // Start the bottom shield
AFMStop.begin(); // Start the top shield
stepper1.setMaxSpeed(100.0);
stepper1.setAcceleration(100.0);
stepper1.moveTo(24);
stepper2.setMaxSpeed(200.0);
stepper2.setAcceleration(100.0);
stepper2.moveTo(50000);
stepper3.setMaxSpeed(300.0);
stepper3.setAcceleration(100.0);
stepper3.moveTo(1000000);
}
void loop()
{
// Change direction at the limits
if (stepper1.distanceToGo() == 0)
stepper1.moveTo(-stepper1.currentPosition());
if (stepper2.distanceToGo() == 0)
stepper2.moveTo(-stepper2.currentPosition());
if (stepper3.distanceToGo() == 0)
stepper3.moveTo(-stepper3.currentPosition());
stepper1.run();
stepper2.run();
stepper3.run();
}
@@ -1,68 +0,0 @@
/*
This is a test sketch for the Adafruit assembled Motor Shield for Arduino v2
It won't work with v1.x motor shields! Only for the v2's with built in PWM
control
For use with the Adafruit Motor Shield v2
----> http://www.adafruit.com/products/1438
*/
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// Select which 'port' M1, M2, M3 or M4. In this case, M1
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
// You can also make another motor on port M2
//Adafruit_DCMotor *myOtherMotor = AFMS.getMotor(2);
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Adafruit Motorshield v2 - DC Motor test!");
AFMS.begin(); // create with the default frequency 1.6KHz
//AFMS.begin(1000); // OR with a different frequency, say 1KHz
// Set the speed to start, from 0 (off) to 255 (max speed)
myMotor->setSpeed(150);
myMotor->run(FORWARD);
// turn on motor
myMotor->run(RELEASE);
}
void loop() {
uint8_t i;
Serial.print("tick");
myMotor->run(FORWARD);
for (i=0; i<255; i++) {
myMotor->setSpeed(i);
delay(10);
}
for (i=255; i!=0; i--) {
myMotor->setSpeed(i);
delay(10);
}
Serial.print("tock");
myMotor->run(BACKWARD);
for (i=0; i<255; i++) {
myMotor->setSpeed(i);
delay(10);
}
for (i=255; i!=0; i--) {
myMotor->setSpeed(i);
delay(10);
}
Serial.print("tech");
myMotor->run(RELEASE);
delay(1000);
}
@@ -1,84 +0,0 @@
/*
This is a test sketch for the Adafruit assembled Motor Shield for Arduino v2
It won't work with v1.x motor shields! Only for the v2's with built in PWM
control
For use with the Adafruit Motor Shield v2
----> http://www.adafruit.com/products/1438
This sketch creates a fun motor party on your desk *whiirrr*
Connect a unipolar/bipolar stepper to M3/M4
Connect a DC motor to M1
Connect a hobby servo to SERVO1
*/
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
#include <Servo.h>
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myStepper = AFMS.getStepper(200, 2);
// And connect a DC motor to port M1
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
// We'll also test out the built in Arduino Servo library
Servo servo1;
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("MMMMotor party!");
AFMS.begin(); // create with the default frequency 1.6KHz
//AFMS.begin(1000); // OR with a different frequency, say 1KHz
// Attach a servo to pin #10
servo1.attach(10);
// turn on motor M1
myMotor->setSpeed(200);
myMotor->run(RELEASE);
// setup the stepper
myStepper->setSpeed(10); // 10 rpm
}
int i;
void loop() {
myMotor->run(FORWARD);
for (i=0; i<255; i++) {
servo1.write(map(i, 0, 255, 0, 180));
myMotor->setSpeed(i);
myStepper->step(1, FORWARD, INTERLEAVE);
delay(3);
}
for (i=255; i!=0; i--) {
servo1.write(map(i, 0, 255, 0, 180));
myMotor->setSpeed(i);
myStepper->step(1, BACKWARD, INTERLEAVE);
delay(3);
}
myMotor->run(BACKWARD);
for (i=0; i<255; i++) {
servo1.write(map(i, 0, 255, 0, 180));
myMotor->setSpeed(i);
myStepper->step(1, FORWARD, DOUBLE);
delay(3);
}
for (i=255; i!=0; i--) {
servo1.write(map(i, 0, 255, 0, 180));
myMotor->setSpeed(i);
myStepper->step(1, BACKWARD, DOUBLE);
delay(3);
}
}
@@ -1,76 +0,0 @@
/*
This is a test sketch for the Adafruit assembled Motor Shield for Arduino v2
It won't work with v1.x motor shields! Only for the v2's with built in PWM
control
For use with the Adafruit Motor Shield v2
----> http://www.adafruit.com/products/1438
*/
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMSbot(0x61); // Rightmost jumper closed
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
// On the top shield, connect two steppers, each with 200 steps
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper3 = AFMStop.getStepper(200, 2);
// On the bottom shield connect a stepper to port M3/M4 with 200 steps
Adafruit_StepperMotor *myStepper1 = AFMSbot.getStepper(200, 2);
// And a DC Motor to port M1
Adafruit_DCMotor *myMotor1 = AFMSbot.getMotor(1);
void setup() {
while (!Serial);
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("MMMMotor party!");
AFMSbot.begin(); // Start the bottom shield
AFMStop.begin(); // Start the top shield
// turn on the DC motor
myMotor1->setSpeed(200);
myMotor1->run(RELEASE);
}
int i;
void loop() {
myMotor1->run(FORWARD);
for (i=0; i<255; i++) {
myMotor1->setSpeed(i);
myStepper1->onestep(FORWARD, INTERLEAVE);
myStepper2->onestep(BACKWARD, DOUBLE);
myStepper3->onestep(FORWARD, MICROSTEP);
delay(3);
}
for (i=255; i!=0; i--) {
myMotor1->setSpeed(i);
myStepper1->onestep(BACKWARD, INTERLEAVE);
myStepper2->onestep(FORWARD, DOUBLE);
myStepper3->onestep(BACKWARD, MICROSTEP);
delay(3);
}
myMotor1->run(BACKWARD);
for (i=0; i<255; i++) {
myMotor1->setSpeed(i);
myStepper1->onestep(FORWARD, DOUBLE);
myStepper2->onestep(BACKWARD, INTERLEAVE);
myStepper3->onestep(FORWARD, MICROSTEP);
delay(3);
}
for (i=255; i!=0; i--) {
myMotor1->setSpeed(i);
myStepper1->onestep(BACKWARD, DOUBLE);
myStepper2->onestep(FORWARD, INTERLEAVE);
myStepper3->onestep(BACKWARD, MICROSTEP);
delay(3);
}
}
@@ -1,51 +0,0 @@
/*
This is a test sketch for the Adafruit assembled Motor Shield for Arduino v2
It won't work with v1.x motor shields! Only for the v2's with built in PWM
control
For use with the Adafruit Motor Shield v2
----> http://www.adafruit.com/products/1438
*/
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Stepper test!");
AFMS.begin(); // create with the default frequency 1.6KHz
//AFMS.begin(1000); // OR with a different frequency, say 1KHz
myMotor->setSpeed(10); // 10 rpm
}
void loop() {
Serial.println("Single coil steps");
myMotor->step(100, FORWARD, SINGLE);
myMotor->step(100, BACKWARD, SINGLE);
Serial.println("Double coil steps");
myMotor->step(100, FORWARD, DOUBLE);
myMotor->step(100, BACKWARD, DOUBLE);
Serial.println("Interleave coil steps");
myMotor->step(100, FORWARD, INTERLEAVE);
myMotor->step(100, BACKWARD, INTERLEAVE);
Serial.println("Microstep steps");
myMotor->step(50, FORWARD, MICROSTEP);
myMotor->step(50, BACKWARD, MICROSTEP);
}
-40
View File
@@ -1,40 +0,0 @@
#######################################
# Syntax Coloring Map for AFMotor
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Adafruit_MotorShield KEYWORD1
Adafruit_DCMotor KEYWORD1
Adafruit_StepperMotor KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
enable KEYWORD2
run KEYWORD2
setSpeed KEYWORD2
step KEYWORD2
onestep KEYWORD2
release KEYWORD2
getMotor KEYWORD2
getStepper KEYWORD2
setPin KEYWORD2
setPWM KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
MICROSTEPPING LITERAL1
FORWARD LITERAL1
BACKWARD LITERAL1
BRAKE LITERAL1
RELEASE LITERAL1
SINGLE LITERAL1
DOUBLE LITERAL1
INTERLEAVE LITERAL1
MICROSTEP LITERAL1
@@ -1,9 +0,0 @@
name=Adafruit Motor Shield V2 Library
version=1.0.4
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Library for the Adafruit Motor Shield V2 for Arduino. It supports DC motors & stepper motors with microstepping as well as stacking-support.
paragraph=Library for the Adafruit Motor Shield V2 for Arduino. It supports DC motors & stepper motors with microstepping as well as stacking-support.
category=Device Control
url=https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library
architectures=*
-25
View File
@@ -1,25 +0,0 @@
Software License Agreement (BSD License)
Copyright (c) 2012, Adafruit Industries. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,113 +0,0 @@
/***************************************************
This is a library for our Adafruit 16-channel PWM & Servo driver
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/815
These displays use I2C to communicate, 2 pins are required to
interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_MS_PWMServoDriver.h>
#include <Wire.h>
#if defined(ARDUINO_SAM_DUE)
#define WIRE Wire1
#else
#define WIRE Wire
#endif
Adafruit_MS_PWMServoDriver::Adafruit_MS_PWMServoDriver(uint8_t addr) {
_i2caddr = addr;
}
void Adafruit_MS_PWMServoDriver::begin(void) {
WIRE.begin();
reset();
}
void Adafruit_MS_PWMServoDriver::reset(void) {
write8(PCA9685_MODE1, 0x0);
}
void Adafruit_MS_PWMServoDriver::setPWMFreq(float freq) {
//Serial.print("Attempting to set freq ");
//Serial.println(freq);
freq *= 0.9; // Correct for overshoot in the frequency setting (see issue #11).
float prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
//Serial.print("Estimated pre-scale: "); Serial.println(prescaleval);
uint8_t prescale = floor(prescaleval + 0.5);
//Serial.print("Final pre-scale: "); Serial.println(prescale);
uint8_t oldmode = read8(PCA9685_MODE1);
uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep
write8(PCA9685_MODE1, newmode); // go to sleep
write8(PCA9685_PRESCALE, prescale); // set the prescaler
write8(PCA9685_MODE1, oldmode);
delay(5);
write8(PCA9685_MODE1, oldmode | 0xa1); // This sets the MODE1 register to turn on auto increment.
// This is why the beginTransmission below was not working.
// Serial.print("Mode now 0x"); Serial.println(read8(PCA9685_MODE1), HEX);
}
void Adafruit_MS_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) {
//Serial.print("Setting PWM "); Serial.print(num); Serial.print(": "); Serial.print(on); Serial.print("->"); Serial.println(off);
WIRE.beginTransmission(_i2caddr);
#if ARDUINO >= 100
WIRE.write(LED0_ON_L+4*num);
WIRE.write(on);
WIRE.write(on>>8);
WIRE.write(off);
WIRE.write(off>>8);
#else
WIRE.send(LED0_ON_L+4*num);
WIRE.send((uint8_t)on);
WIRE.send((uint8_t)(on>>8));
WIRE.send((uint8_t)off);
WIRE.send((uint8_t)(off>>8));
#endif
WIRE.endTransmission();
}
uint8_t Adafruit_MS_PWMServoDriver::read8(uint8_t addr) {
WIRE.beginTransmission(_i2caddr);
#if ARDUINO >= 100
WIRE.write(addr);
#else
WIRE.send(addr);
#endif
WIRE.endTransmission();
WIRE.requestFrom((uint8_t)_i2caddr, (uint8_t)1);
#if ARDUINO >= 100
return WIRE.read();
#else
return WIRE.receive();
#endif
}
void Adafruit_MS_PWMServoDriver::write8(uint8_t addr, uint8_t d) {
WIRE.beginTransmission(_i2caddr);
#if ARDUINO >= 100
WIRE.write(addr);
WIRE.write(d);
#else
WIRE.send(addr);
WIRE.send(d);
#endif
WIRE.endTransmission();
}

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