mirror of
https://github.com/letscontrolit/ArduinoEasy.git
synced 2026-03-04 17:14:02 +01:00
R147
This commit is contained in:
813
ArduinoEasy.ino
Normal file
813
ArduinoEasy.ino
Normal file
@@ -0,0 +1,813 @@
|
||||
/****************************************************************************************************************************\
|
||||
* Arduino project "Arduino Easy" © Copyright www.letscontrolit.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* You received a copy of the GNU General Public License along with this program in file 'License.txt'.
|
||||
*
|
||||
* IDE download : https://www.arduino.cc/en/Main/Software
|
||||
*
|
||||
* Source Code : https://github.com/ESP8266nu/ESPEasy
|
||||
* Support : http://www.letscontrolit.com
|
||||
* Discussion : http://www.letscontrolit.com/forum/
|
||||
*
|
||||
* Additional information about licensing can be found at : http://www.gnu.org/licenses
|
||||
\*************************************************************************************************************************/
|
||||
|
||||
// This file incorporates work covered by the following copyright and permission notice:
|
||||
|
||||
/****************************************************************************************************************************\
|
||||
* Arduino project "Nodo" © Copyright 2010..2015 Paul Tonkes
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* You received a copy of the GNU General Public License along with this program in file 'License.txt'.
|
||||
*
|
||||
* Voor toelichting op de licentievoorwaarden zie : http://www.gnu.org/licenses
|
||||
* Uitgebreide documentatie is te vinden op : http://www.nodo-domotica.nl
|
||||
* Compiler voor deze programmacode te downloaden op : http://arduino.cc
|
||||
\*************************************************************************************************************************/
|
||||
|
||||
// ********************************************************************************
|
||||
// User specific configuration
|
||||
// ********************************************************************************
|
||||
|
||||
// Set default configuration settings if you want (not mandatory)
|
||||
// You can always change these during runtime and save to eeprom
|
||||
// After loading firmware, issue a 'reset' command to load the defaults.
|
||||
|
||||
#define DEFAULT_NAME "newdevice" // Enter your device friendly name
|
||||
#define DEFAULT_SERVER "192.168.0.8" // Enter your Domoticz Server IP address
|
||||
#define DEFAULT_PORT 8080 // Enter your Domoticz Server port value
|
||||
#define DEFAULT_DELAY 60 // Enter your Send delay in seconds
|
||||
|
||||
#define DEFAULT_USE_STATIC_IP false // true or false enabled or disabled set static IP
|
||||
#define DEFAULT_IP "192.168.0.50" // Enter your IP address
|
||||
#define DEFAULT_DNS "192.168.0.1" // Enter your DNS
|
||||
#define DEFAULT_GW "192.168.0.1" // Enter your gateway
|
||||
#define DEFAULT_SUBNET "255.255.255.0" // Enter your subnet
|
||||
|
||||
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
|
||||
#define UNIT 0
|
||||
|
||||
#define FEATURE_MQTT true
|
||||
#define FEATURE_MQTT_DOM false // Not tested yet!
|
||||
|
||||
// ********************************************************************************
|
||||
// DO NOT CHANGE ANYTHING BELOW THIS LINE
|
||||
// ********************************************************************************
|
||||
|
||||
// Challenges on Arduino/W5100 ethernet platform:
|
||||
// Only 4 ethernet sockets:
|
||||
// 1: UPD traffic server/send
|
||||
// 2: Webserver
|
||||
// 3: MQTT client
|
||||
// 4: Webclient, active when webserver serves an incoming client or outgoing webclient calls.
|
||||
|
||||
#define socketdebug false
|
||||
#define ARDUINO_PROJECT_PID 2016110201L
|
||||
#define VERSION 2
|
||||
#define BUILD 147
|
||||
#define BUILD_NOTES ""
|
||||
|
||||
#define NODE_TYPE_ID_ESP_EASY_STD 1
|
||||
#define NODE_TYPE_ID_ESP_EASY4M_STD 17
|
||||
#define NODE_TYPE_ID_ESP_EASY32_STD 33
|
||||
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
|
||||
#define NODE_TYPE_ID NODE_TYPE_ID_ARDUINO_EASY_STD
|
||||
|
||||
#define CPLUGIN_PROTOCOL_ADD 1
|
||||
#define CPLUGIN_PROTOCOL_TEMPLATE 2
|
||||
#define CPLUGIN_PROTOCOL_SEND 3
|
||||
#define CPLUGIN_PROTOCOL_RECV 4
|
||||
#define CPLUGIN_GET_DEVICENAME 5
|
||||
#define CPLUGIN_WEBFORM_SAVE 6
|
||||
#define CPLUGIN_WEBFORM_LOAD 7
|
||||
|
||||
#define LOG_LEVEL_ERROR 1
|
||||
#define LOG_LEVEL_INFO 2
|
||||
#define LOG_LEVEL_DEBUG 3
|
||||
#define LOG_LEVEL_DEBUG_MORE 4
|
||||
|
||||
#define CMD_REBOOT 89
|
||||
|
||||
#define DEVICES_MAX 8 // ESP Easy 64
|
||||
#define TASKS_MAX 8 // ESP Easy 12
|
||||
#define VARS_PER_TASK 4
|
||||
#define PLUGIN_MAX 8 // ESP Easy 64
|
||||
#define PLUGIN_CONFIGVAR_MAX 8
|
||||
#define PLUGIN_CONFIGFLOATVAR_MAX 4
|
||||
#define PLUGIN_CONFIGLONGVAR_MAX 4
|
||||
#define PLUGIN_EXTRACONFIGVAR_MAX 16
|
||||
#define CPLUGIN_MAX 4 // ESP Easy 16
|
||||
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
|
||||
#define RULES_TIMER_MAX 8
|
||||
#define SYSTEM_TIMER_MAX 2 // ESP Easy 8
|
||||
#define SYSTEM_CMD_TIMER_MAX 1 // ESP Easy 2
|
||||
#define PINSTATE_TABLE_MAX 16 // ESP Easy 32
|
||||
#define RULES_MAX_SIZE 512 // ESP Easy 2048
|
||||
#define RULES_MAX_NESTING_LEVEL 3
|
||||
|
||||
#define PIN_MODE_UNDEFINED 0
|
||||
#define PIN_MODE_INPUT 1
|
||||
#define PIN_MODE_OUTPUT 2
|
||||
#define PIN_MODE_PWM 3
|
||||
#define PIN_MODE_SERVO 4
|
||||
|
||||
#define SEARCH_PIN_STATE true
|
||||
#define NO_SEARCH_PIN_STATE false
|
||||
|
||||
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
|
||||
#define DEVICE_TYPE_I2C 2 // connected through I2C
|
||||
#define DEVICE_TYPE_ANALOG 3 // tout pin
|
||||
#define DEVICE_TYPE_DUAL 4 // connected through 2 datapins
|
||||
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
|
||||
|
||||
#define SENSOR_TYPE_SINGLE 1
|
||||
#define SENSOR_TYPE_TEMP_HUM 2
|
||||
#define SENSOR_TYPE_TEMP_BARO 3
|
||||
#define SENSOR_TYPE_TEMP_HUM_BARO 4
|
||||
#define SENSOR_TYPE_DUAL 5
|
||||
#define SENSOR_TYPE_TRIPLE 6
|
||||
#define SENSOR_TYPE_QUAD 7
|
||||
#define SENSOR_TYPE_SWITCH 10
|
||||
#define SENSOR_TYPE_DIMMER 11
|
||||
#define SENSOR_TYPE_LONG 20
|
||||
|
||||
#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
|
||||
#define VALUE_SOURCE_MQTT 4
|
||||
#define VALUE_SOURCE_UDP 5
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Ethernet.h>
|
||||
#include <EthernetUdp.h>
|
||||
#if FEATURE_MQTT
|
||||
#include <PubSubClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#endif
|
||||
|
||||
void(*Reboot)(void)=0;
|
||||
|
||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
|
||||
// WebServer
|
||||
EthernetServer WebServer(80);
|
||||
|
||||
#if FEATURE_MQTT
|
||||
EthernetClient mqtt;
|
||||
PubSubClient MQTTclient(mqtt);
|
||||
#endif
|
||||
|
||||
#define EthernetShield_CS_SDCard 4
|
||||
#define EthernetShield_CS_W5100 10
|
||||
|
||||
// syslog stuff
|
||||
EthernetUDP portUDP;
|
||||
|
||||
struct SecurityStruct
|
||||
{
|
||||
char ControllerUser[26];
|
||||
char ControllerPassword[64];
|
||||
char Password[26];
|
||||
} SecuritySettings;
|
||||
|
||||
struct SettingsStruct
|
||||
{
|
||||
unsigned long PID;
|
||||
int Version;
|
||||
byte Unit;
|
||||
int16_t Build;
|
||||
byte IP[4];
|
||||
byte Gateway[4];
|
||||
byte Subnet[4];
|
||||
byte DNS[4];
|
||||
byte Controller_IP[4];
|
||||
unsigned int ControllerPort;
|
||||
byte IP_Octet;
|
||||
char NTPHost[64];
|
||||
unsigned long Delay;
|
||||
byte Syslog_IP[4];
|
||||
unsigned int UDPPort;
|
||||
byte Protocol;
|
||||
char Name[26];
|
||||
byte SyslogLevel;
|
||||
byte SerialLogLevel;
|
||||
unsigned long BaudRate;
|
||||
unsigned long MessageDelay;
|
||||
boolean CustomCSS;
|
||||
char ControllerHostName[64];
|
||||
boolean UseNTP;
|
||||
boolean DST;
|
||||
byte WDI2CAddress;
|
||||
int8_t PinBootStates[17];
|
||||
byte UseDNS;
|
||||
boolean UseRules;
|
||||
int8_t Pin_status_led;
|
||||
boolean UseSerial;
|
||||
boolean GlobalSync;
|
||||
unsigned long ConnectionFailuresThreshold;
|
||||
int16_t TimeZone;
|
||||
byte SDLogLevel;
|
||||
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];
|
||||
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
|
||||
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
|
||||
boolean TaskDeviceSendData[TASKS_MAX];
|
||||
boolean TaskDeviceGlobalSync[TASKS_MAX];
|
||||
int8_t TaskDevicePin3[TASKS_MAX];
|
||||
byte TaskDeviceDataFeed[TASKS_MAX];
|
||||
unsigned long TaskDeviceTimer[TASKS_MAX];
|
||||
boolean MQTTRetainFlag;
|
||||
char MQTTpublish[81];
|
||||
char MQTTsubscribe[81];
|
||||
} Settings;
|
||||
|
||||
struct ExtraTaskSettingsStruct
|
||||
{
|
||||
byte TaskIndex;
|
||||
char TaskDeviceName[41];
|
||||
char TaskDeviceFormula[VARS_PER_TASK][41];
|
||||
char TaskDeviceValueNames[VARS_PER_TASK][41];
|
||||
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
|
||||
byte TaskDeviceValueDecimals[VARS_PER_TASK];
|
||||
} ExtraTaskSettings;
|
||||
|
||||
struct EventStruct
|
||||
{
|
||||
byte Source;
|
||||
byte TaskIndex;
|
||||
byte BaseVarIndex;
|
||||
int idx;
|
||||
byte sensorType;
|
||||
int Par1;
|
||||
int Par2;
|
||||
int Par3;
|
||||
byte OriginTaskIndex;
|
||||
String String1;
|
||||
String String2;
|
||||
byte *Data;
|
||||
};
|
||||
|
||||
struct DeviceStruct
|
||||
{
|
||||
byte Number;
|
||||
byte Type;
|
||||
byte VType;
|
||||
byte Ports;
|
||||
boolean PullUpOption;
|
||||
boolean InverseLogicOption;
|
||||
boolean FormulaOption;
|
||||
byte ValueCount;
|
||||
boolean Custom;
|
||||
boolean SendDataOption;
|
||||
boolean GlobalSyncOption;
|
||||
boolean TimerOption;
|
||||
boolean TimerOptional;
|
||||
boolean DecimalsOnly;
|
||||
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
|
||||
|
||||
struct ProtocolStruct
|
||||
{
|
||||
byte Number;
|
||||
boolean usesMQTT;
|
||||
boolean usesAccount;
|
||||
boolean usesPassword;
|
||||
int defaultPort;
|
||||
boolean usesTemplate;
|
||||
} Protocol[CPLUGIN_MAX];
|
||||
|
||||
struct NodeStruct
|
||||
{
|
||||
byte ip[4];
|
||||
byte age;
|
||||
uint16_t build;
|
||||
} Nodes[UNIT_MAX];
|
||||
|
||||
struct systemTimerStruct
|
||||
{
|
||||
unsigned long timer;
|
||||
byte plugin;
|
||||
byte Par1;
|
||||
byte Par2;
|
||||
byte Par3;
|
||||
} systemTimers[SYSTEM_TIMER_MAX];
|
||||
|
||||
struct systemCMDTimerStruct
|
||||
{
|
||||
unsigned long timer;
|
||||
String action;
|
||||
} systemCMDTimers[SYSTEM_CMD_TIMER_MAX];
|
||||
|
||||
struct pinStatesStruct
|
||||
{
|
||||
byte plugin;
|
||||
byte index;
|
||||
byte mode;
|
||||
uint16_t value;
|
||||
} pinStates[PINSTATE_TABLE_MAX];
|
||||
|
||||
int deviceCount = -1;
|
||||
int protocolCount = -1;
|
||||
|
||||
boolean printToWeb = false;
|
||||
String printWebString = "";
|
||||
boolean printToWebJSON = false;
|
||||
|
||||
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 timer1s;
|
||||
unsigned long timerwd;
|
||||
unsigned long lastSend;
|
||||
byte cmd_within_mainloop = 0;
|
||||
unsigned long connectionFailures;
|
||||
unsigned long wdcounter = 0;
|
||||
|
||||
boolean WebLoggedIn = false;
|
||||
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];
|
||||
|
||||
String dummyString = "";
|
||||
|
||||
boolean systemOK = false;
|
||||
|
||||
unsigned long start = 0;
|
||||
unsigned long elapsed = 0;
|
||||
unsigned long loopCounter = 0;
|
||||
unsigned long loopCounterLast = 0;
|
||||
unsigned long loopCounterMax = 1;
|
||||
|
||||
unsigned long flashWrites = 0;
|
||||
|
||||
String eventBuffer = "";
|
||||
|
||||
/*********************************************************************************************\
|
||||
* SETUP
|
||||
\*********************************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
fileSystemCheck();
|
||||
|
||||
emergencyReset();
|
||||
|
||||
LoadSettings();
|
||||
|
||||
ExtraTaskSettings.TaskIndex = 255; // make sure this is an unused nr to prevent cache load on boot
|
||||
|
||||
// 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 == ARDUINO_PROJECT_PID)
|
||||
{
|
||||
systemOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Direct Serial is allowed here, since this is only an emergency task.
|
||||
Serial.print(F("\nPID:"));
|
||||
Serial.println(Settings.PID);
|
||||
Serial.print(F("Version:"));
|
||||
Serial.println(Settings.Version);
|
||||
Serial.println(F("INIT : Incorrect PID or version!"));
|
||||
delay(1000);
|
||||
ResetFactory();
|
||||
}
|
||||
|
||||
if (systemOK)
|
||||
{
|
||||
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);
|
||||
|
||||
hardwareInit();
|
||||
PluginInit();
|
||||
CPluginInit();
|
||||
|
||||
mac[5] = Settings.Unit; // make sure every unit has a unique mac address
|
||||
if (Settings.IP[0] == 0)
|
||||
Ethernet.begin(mac);
|
||||
else
|
||||
Ethernet.begin(mac, Settings.IP, Settings.DNS, Settings.Gateway, Settings.Subnet);
|
||||
|
||||
// setup UDP
|
||||
if (Settings.UDPPort != 0)
|
||||
portUDP.begin(Settings.UDPPort);
|
||||
|
||||
#if FEATURE_MQTT
|
||||
// Setup MQTT Client
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
|
||||
if (Protocol[ProtocolIndex].usesMQTT)
|
||||
MQTTConnect();
|
||||
#endif
|
||||
|
||||
sendSysInfoUDP(3);
|
||||
|
||||
log = F("INIT : Boot OK");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
// Setup timers
|
||||
byte bootMode = 0;
|
||||
if (bootMode == 0)
|
||||
{
|
||||
for (byte x = 0; x < TASKS_MAX; x++)
|
||||
if (Settings.TaskDeviceTimer[x] !=0)
|
||||
timerSensor[x] = millis() + 30000 + (x * Settings.MessageDelay);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 (Settings.UseNTP)
|
||||
initTime();
|
||||
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("System#Boot");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Entered Rescue mode!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* MAIN LOOP
|
||||
\*********************************************************************************************/
|
||||
void loop()
|
||||
{
|
||||
loopCounter++;
|
||||
|
||||
if (Settings.UseSerial)
|
||||
if (Serial.available())
|
||||
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
|
||||
serial();
|
||||
|
||||
if (systemOK)
|
||||
{
|
||||
if (millis() > timer100ms)
|
||||
run10TimesPerSecond();
|
||||
|
||||
if (millis() > timer1s)
|
||||
runOncePerSecond();
|
||||
|
||||
if (millis() > timerwd)
|
||||
runEach30Seconds();
|
||||
|
||||
backgroundtasks();
|
||||
|
||||
}
|
||||
else
|
||||
delay(1);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Tasks that run 10 times per second
|
||||
\*********************************************************************************************/
|
||||
void run10TimesPerSecond()
|
||||
{
|
||||
start = micros();
|
||||
timer100ms = millis() + 100;
|
||||
PluginCall(PLUGIN_TEN_PER_SECOND, 0, dummyString);
|
||||
checkUDP();
|
||||
if (Settings.UseRules && eventBuffer.length() > 0)
|
||||
{
|
||||
rulesProcessing(eventBuffer);
|
||||
eventBuffer = "";
|
||||
}
|
||||
elapsed = micros() - start;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Tasks each second
|
||||
\*********************************************************************************************/
|
||||
void runOncePerSecond()
|
||||
{
|
||||
timer1s = millis() + 1000;
|
||||
|
||||
checkSensors();
|
||||
|
||||
if (Settings.ConnectionFailuresThreshold)
|
||||
if (connectionFailures > Settings.ConnectionFailuresThreshold)
|
||||
delayedReboot(60);
|
||||
|
||||
if (cmd_within_mainloop != 0)
|
||||
{
|
||||
switch (cmd_within_mainloop)
|
||||
{
|
||||
case CMD_REBOOT:
|
||||
{
|
||||
Reboot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd_within_mainloop = 0;
|
||||
}
|
||||
|
||||
// clock events
|
||||
if (Settings.UseNTP)
|
||||
checkTime();
|
||||
|
||||
unsigned long timer = micros();
|
||||
PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummyString);
|
||||
|
||||
checkSystemTimers();
|
||||
|
||||
if (Settings.UseRules)
|
||||
rulesTimers();
|
||||
|
||||
timer = micros() - timer;
|
||||
|
||||
if (SecuritySettings.Password[0] != 0)
|
||||
{
|
||||
if (WebLoggedIn)
|
||||
WebLoggedInTimer++;
|
||||
if (WebLoggedInTimer > 300)
|
||||
WebLoggedIn = false;
|
||||
}
|
||||
|
||||
// I2C Watchdog feed
|
||||
if (Settings.WDI2CAddress != 0)
|
||||
{
|
||||
Wire.beginTransmission(Settings.WDI2CAddress);
|
||||
Wire.write(0xA5);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
if (Settings.SerialLogLevel == 5)
|
||||
{
|
||||
Serial.print(F("10 ps:"));
|
||||
Serial.print(elapsed);
|
||||
Serial.print(F(" uS 1 ps:"));
|
||||
Serial.println(timer);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Tasks each 30 seconds
|
||||
\*********************************************************************************************/
|
||||
void runEach30Seconds()
|
||||
{
|
||||
wdcounter++;
|
||||
timerwd = millis() + 30000;
|
||||
String log = F("WD : Uptime ");
|
||||
log += wdcounter / 2;
|
||||
log += F(" ConnectFailures ");
|
||||
log += connectionFailures;
|
||||
log += F(" Freemem ");
|
||||
log += FreeMem();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendSysInfoUDP(1);
|
||||
refreshNodeList();
|
||||
loopCounterLast = loopCounter;
|
||||
loopCounter = 0;
|
||||
if (loopCounterLast > loopCounterMax)
|
||||
loopCounterMax = loopCounterLast;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Check sensor timers
|
||||
\*********************************************************************************************/
|
||||
void checkSensors()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* send all sensordata
|
||||
\*********************************************************************************************/
|
||||
void SensorSend()
|
||||
{
|
||||
for (byte x = 0; x < TASKS_MAX; x++)
|
||||
{
|
||||
SensorSendTask(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* send specific sensor task data
|
||||
\*********************************************************************************************/
|
||||
void SensorSendTask(byte TaskIndex)
|
||||
{
|
||||
if (Settings.TaskDeviceID[TaskIndex] != 0)
|
||||
{
|
||||
byte varIndex = TaskIndex * VARS_PER_TASK;
|
||||
|
||||
boolean success = false;
|
||||
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
|
||||
LoadTaskSettings(TaskIndex);
|
||||
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.TaskIndex = TaskIndex;
|
||||
TempEvent.BaseVarIndex = varIndex;
|
||||
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
|
||||
for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++)
|
||||
preValue[varNr] = UserVar[varIndex + varNr];
|
||||
|
||||
if(Settings.TaskDeviceDataFeed[TaskIndex] == 0) // only read local connected sensorsfeeds
|
||||
success = PluginCall(PLUGIN_READ, &TempEvent, dummyString);
|
||||
else
|
||||
success = true;
|
||||
|
||||
if (success)
|
||||
{
|
||||
for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++)
|
||||
{
|
||||
if (ExtraTaskSettings.TaskDeviceFormula[varNr][0] != 0)
|
||||
{
|
||||
String spreValue = String(preValue[varNr]);
|
||||
String formula = ExtraTaskSettings.TaskDeviceFormula[varNr];
|
||||
float value = UserVar[varIndex + varNr];
|
||||
float result = 0;
|
||||
String svalue = String(value);
|
||||
formula.replace("%pvalue%", spreValue);
|
||||
formula.replace("%value%", svalue);
|
||||
byte error = Calculate(formula.c_str(), &result);
|
||||
if (error == 0)
|
||||
UserVar[varIndex + varNr] = result;
|
||||
}
|
||||
}
|
||||
sendData(&TempEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* set global system timer
|
||||
\*********************************************************************************************/
|
||||
boolean setSystemTimer(unsigned long timer, byte plugin, byte Par1, byte Par2, byte Par3)
|
||||
{
|
||||
// plugin number and par1 form a unique key that can be used to restart a timer
|
||||
// first check if a timer is not already running for this request
|
||||
boolean reUse = false;
|
||||
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
|
||||
if (systemTimers[x].timer != 0)
|
||||
{
|
||||
if ((systemTimers[x].plugin == plugin) && (systemTimers[x].Par1 == Par1))
|
||||
{
|
||||
systemTimers[x].timer = millis() + timer;
|
||||
reUse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!reUse)
|
||||
{
|
||||
// find a new free timer slot...
|
||||
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
|
||||
if (systemTimers[x].timer == 0)
|
||||
{
|
||||
systemTimers[x].timer = millis() + timer;
|
||||
systemTimers[x].plugin = plugin;
|
||||
systemTimers[x].Par1 = Par1;
|
||||
systemTimers[x].Par2 = Par2;
|
||||
systemTimers[x].Par3 = Par3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* set global system command timer
|
||||
\*********************************************************************************************/
|
||||
boolean setSystemCMDTimer(unsigned long timer, String& action)
|
||||
{
|
||||
for (byte x = 0; x < SYSTEM_CMD_TIMER_MAX; x++)
|
||||
if (systemCMDTimers[x].timer == 0)
|
||||
{
|
||||
systemCMDTimers[x].timer = millis() + timer;
|
||||
systemCMDTimers[x].action = action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* check global system timers
|
||||
\*********************************************************************************************/
|
||||
boolean checkSystemTimers()
|
||||
{
|
||||
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
|
||||
if (systemTimers[x].timer != 0)
|
||||
{
|
||||
if (timeOut(systemTimers[x].timer))
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.Par1 = systemTimers[x].Par1;
|
||||
TempEvent.Par2 = systemTimers[x].Par2;
|
||||
TempEvent.Par3 = systemTimers[x].Par3;
|
||||
for (byte y = 0; y < PLUGIN_MAX; y++)
|
||||
if (Plugin_id[y] == systemTimers[x].plugin)
|
||||
Plugin_ptr[y](PLUGIN_TIMER_IN, &TempEvent, dummyString);
|
||||
systemTimers[x].timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (byte x = 0; x < SYSTEM_CMD_TIMER_MAX; x++)
|
||||
if (systemCMDTimers[x].timer != 0)
|
||||
if (timeOut(systemCMDTimers[x].timer))
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
parseCommandString(&TempEvent, systemCMDTimers[x].action);
|
||||
if (!PluginCall(PLUGIN_WRITE, &TempEvent, systemCMDTimers[x].action))
|
||||
ExecuteCommand(VALUE_SOURCE_SYSTEM, systemCMDTimers[x].action.c_str());
|
||||
systemCMDTimers[x].timer = 0;
|
||||
systemCMDTimers[x].action = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* run background tasks
|
||||
\*********************************************************************************************/
|
||||
void backgroundtasks()
|
||||
{
|
||||
WebServerHandleClient();
|
||||
#if FEATURE_MQTT
|
||||
MQTTclient.loop();
|
||||
#endif
|
||||
statusLED(false);
|
||||
checkUDP();
|
||||
}
|
||||
|
||||
281
Command.ino
Normal file
281
Command.ino
Normal file
@@ -0,0 +1,281 @@
|
||||
#define INPUT_COMMAND_SIZE 80
|
||||
void ExecuteCommand(byte source, const char *Line)
|
||||
{
|
||||
String status = "";
|
||||
boolean success = false;
|
||||
char TmpStr1[80];
|
||||
TmpStr1[0] = 0;
|
||||
char Command[80];
|
||||
Command[0] = 0;
|
||||
int Par1 = 0;
|
||||
int Par2 = 0;
|
||||
int Par3 = 0;
|
||||
|
||||
GetArgv(Line, Command, 1);
|
||||
if (GetArgv(Line, TmpStr1, 2)) Par1 = str2int(TmpStr1);
|
||||
if (GetArgv(Line, TmpStr1, 3)) Par2 = str2int(TmpStr1);
|
||||
if (GetArgv(Line, TmpStr1, 4)) Par3 = str2int(TmpStr1);
|
||||
|
||||
// ****************************************
|
||||
// commands for debugging
|
||||
// ****************************************
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("w5100")) == 0)
|
||||
{
|
||||
success = true;
|
||||
ShowSocketStatus();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("ntp")) == 0)
|
||||
{
|
||||
success = true;
|
||||
getNtpTime();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("sdcard")) == 0)
|
||||
{
|
||||
success = true;
|
||||
SelectSDCard(true);
|
||||
File root = SD.open("/");
|
||||
root.rewindDirectory();
|
||||
printDirectory(root, 0);
|
||||
root.close();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("sysload")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Serial.print(100 - (100 * loopCounterLast / loopCounterMax));
|
||||
Serial.print(F("% (LC="));
|
||||
Serial.print(int(loopCounterLast / 30));
|
||||
Serial.println(F(")"));
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("meminfo")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Serial.print(F("SecurityStruct : "));
|
||||
Serial.println(sizeof(SecuritySettings));
|
||||
Serial.print(F("SettingsStruct : "));
|
||||
Serial.println(sizeof(Settings));
|
||||
Serial.print(F("ExtraTaskSettingsStruct: "));
|
||||
Serial.println(sizeof(ExtraTaskSettings));
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskClear")) == 0)
|
||||
{
|
||||
success = true;
|
||||
taskClear(Par1 - 1, true);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("build")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Settings.Build = Par1;
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// commands for rules
|
||||
// ****************************************
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskValueSet")) == 0)
|
||||
{
|
||||
success = true;
|
||||
if (GetArgv(Line, TmpStr1, 4))
|
||||
{
|
||||
float result = 0;
|
||||
byte error = Calculate(TmpStr1, &result);
|
||||
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskRun")) == 0)
|
||||
{
|
||||
success = true;
|
||||
SensorSendTask(Par1 -1);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TimerSet")) == 0)
|
||||
{
|
||||
success = true;
|
||||
RulesTimer[Par1 - 1] = millis() + (1000 * Par2);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Delay")) == 0)
|
||||
{
|
||||
success = true;
|
||||
delayMillis(Par1);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Rules")) == 0)
|
||||
{
|
||||
success = true;
|
||||
if (Par1 == 1)
|
||||
Settings.UseRules = true;
|
||||
else
|
||||
Settings.UseRules = false;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Event")) == 0)
|
||||
{
|
||||
success = true;
|
||||
String event = Line;
|
||||
event = event.substring(6);
|
||||
event.replace("$", "#");
|
||||
if (Settings.UseRules)
|
||||
rulesProcessing(event);
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SendTo")) == 0)
|
||||
{
|
||||
success = true;
|
||||
String event = Line;
|
||||
event = event.substring(7);
|
||||
int index = event.indexOf(',');
|
||||
if (index > 0)
|
||||
{
|
||||
event = event.substring(index+1);
|
||||
SendUDPCommand(Par1, (char*)event.c_str(), event.length());
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SendToUDP")) == 0)
|
||||
{
|
||||
success = true;
|
||||
String strLine = Line;
|
||||
String ip = parseString(strLine,2);
|
||||
String port = parseString(strLine,3);
|
||||
int msgpos = getParamStartPos(strLine,4);
|
||||
String message = strLine.substring(msgpos);
|
||||
byte ipaddress[4];
|
||||
str2ip((char*)ip.c_str(), ipaddress);
|
||||
IPAddress UDP_IP(ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]);
|
||||
portUDP.beginPacket(UDP_IP, port.toInt());
|
||||
portUDP.write(message.c_str(), message.length());
|
||||
portUDP.endPacket();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SendToHTTP")) == 0)
|
||||
{
|
||||
success = true;
|
||||
String strLine = Line;
|
||||
String host = parseString(strLine,2);
|
||||
String port = parseString(strLine,3);
|
||||
int pathpos = getParamStartPos(strLine,4);
|
||||
String path = strLine.substring(pathpos);
|
||||
EthernetClient client;
|
||||
if (client.connect(host.c_str(), port.toInt()))
|
||||
{
|
||||
client.print(String("GET ") + path + " HTTP/1.1\r\n" +
|
||||
"Host: " + host + "\r\n" +
|
||||
"Connection: close\r\n\r\n");
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && millis() < timer)
|
||||
delay(1);
|
||||
|
||||
while (client.available()) {
|
||||
String line = client.readStringUntil('\n');
|
||||
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
|
||||
addLog(LOG_LEVEL_DEBUG, line);
|
||||
delay(1);
|
||||
}
|
||||
client.flush();
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// configure settings commands
|
||||
// ****************************************
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Reboot")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Reboot();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Restart")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Reboot();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Reset")) == 0)
|
||||
{
|
||||
success = true;
|
||||
ResetFactory();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Save")) == 0)
|
||||
{
|
||||
success = true;
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Load")) == 0)
|
||||
{
|
||||
success = true;
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Debug")) == 0)
|
||||
{
|
||||
success = true;
|
||||
Settings.SerialLogLevel = Par1;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("IP")) == 0)
|
||||
{
|
||||
success = true;
|
||||
if (GetArgv(Line, TmpStr1, 2))
|
||||
if (!str2ip(TmpStr1, Settings.IP))
|
||||
Serial.println("?");
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Settings")) == 0)
|
||||
{
|
||||
success = true;
|
||||
char str[20];
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("System Info"));
|
||||
IPAddress ip = Ethernet.localIP();
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
Serial.print(F(" IP Address : ")); Serial.println(str);
|
||||
Serial.print(F(" Build : ")); Serial.println((int)BUILD);
|
||||
Serial.print(F(" Unit : ")); Serial.println((int)Settings.Unit);
|
||||
Serial.print(F(" Free mem : ")); Serial.println(FreeMem());
|
||||
}
|
||||
|
||||
if (success)
|
||||
status += F("\nOk");
|
||||
else
|
||||
status += F("\nUnknown command!");
|
||||
SendStatus(source,status);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
169
Controller.ino
Normal file
169
Controller.ino
Normal file
@@ -0,0 +1,169 @@
|
||||
//********************************************************************************
|
||||
// Interface for Sending to Controllers
|
||||
//********************************************************************************
|
||||
boolean sendData(struct EventStruct *event)
|
||||
{
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(event->TaskIndex);
|
||||
|
||||
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
|
||||
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
|
||||
if (!Settings.TaskDeviceSendData[event->TaskIndex])
|
||||
return false;
|
||||
|
||||
if (Settings.MessageDelay != 0)
|
||||
{
|
||||
uint16_t dif = millis() - lastSend;
|
||||
if (dif < Settings.MessageDelay)
|
||||
{
|
||||
uint16_t delayms = Settings.MessageDelay - dif;
|
||||
char log[30];
|
||||
sprintf_P(log, PSTR("HTTP : Delay %u ms"), delayms);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
unsigned long timer = millis() + delayms;
|
||||
while (millis() < timer)
|
||||
backgroundtasks();
|
||||
}
|
||||
}
|
||||
|
||||
LoadTaskSettings(event->TaskIndex); // could have changed during background tasks.
|
||||
|
||||
if (Settings.Protocol)
|
||||
{
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
|
||||
CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString);
|
||||
}
|
||||
PluginCall(PLUGIN_EVENT_OUT, event, dummyString);
|
||||
lastSend = millis();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Send status info to request source
|
||||
\*********************************************************************************************/
|
||||
|
||||
void SendStatus(byte source, String status)
|
||||
{
|
||||
switch(source)
|
||||
{
|
||||
case VALUE_SOURCE_HTTP:
|
||||
if (printToWeb)
|
||||
printWebString += status;
|
||||
break;
|
||||
case VALUE_SOURCE_SERIAL:
|
||||
Serial.println(status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if FEATURE_MQTT
|
||||
/*********************************************************************************************\
|
||||
* Handle incoming MQTT messages
|
||||
\*********************************************************************************************/
|
||||
// handle MQTT messages
|
||||
void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
char log[256];
|
||||
char c_payload[256];
|
||||
strncpy(c_payload,(char*)b_payload,length);
|
||||
c_payload[length] = 0;
|
||||
statusLED(true);
|
||||
|
||||
sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
sprintf_P(log, PSTR("%s%s"), "MQTT : Payload: ", c_payload);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.String1 = c_topic;
|
||||
TempEvent.String2 = c_payload;
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
|
||||
CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Connect to MQTT message broker
|
||||
\*********************************************************************************************/
|
||||
void MQTTConnect()
|
||||
{
|
||||
IPAddress MQTTBrokerIP(Settings.Controller_IP);
|
||||
MQTTclient.setServer(MQTTBrokerIP, Settings.ControllerPort);
|
||||
MQTTclient.setCallback(callback);
|
||||
|
||||
// MQTT needs a unique clientname to subscribe to broker
|
||||
String clientid = "ESPClient";
|
||||
clientid += Settings.Unit;
|
||||
String subscribeTo = "";
|
||||
|
||||
String LWTTopic = Settings.MQTTsubscribe;
|
||||
LWTTopic.replace("/#", "/status");
|
||||
LWTTopic.replace("%sysname%", Settings.Name);
|
||||
|
||||
for (byte x = 1; x < 3; x++)
|
||||
{
|
||||
String log = "";
|
||||
boolean MQTTresult = false;
|
||||
|
||||
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
|
||||
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");
|
||||
|
||||
if (MQTTresult)
|
||||
{
|
||||
log = F("MQTT : Connected to broker");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
subscribeTo = Settings.MQTTsubscribe;
|
||||
subscribeTo.replace("%sysname%", Settings.Name);
|
||||
MQTTclient.subscribe(subscribeTo.c_str());
|
||||
log = F("Subscribed to: ");
|
||||
log += subscribeTo;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
break; // end loop if succesfull
|
||||
}
|
||||
else
|
||||
{
|
||||
log = F("MQTT : Failed to connected to broker");
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Check connection MQTT message broker
|
||||
\*********************************************************************************************/
|
||||
void MQTTCheck()
|
||||
{
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol);
|
||||
if (Protocol[ProtocolIndex].usesMQTT)
|
||||
if (!MQTTclient.connected())
|
||||
{
|
||||
String log = F("MQTT : Connection lost");
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
connectionFailures += 2;
|
||||
MQTTclient.disconnect();
|
||||
delay(1000);
|
||||
MQTTConnect();
|
||||
}
|
||||
else if (connectionFailures)
|
||||
connectionFailures--;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Send status info back to channel where request came from
|
||||
\*********************************************************************************************/
|
||||
void MQTTStatus(String& status)
|
||||
{
|
||||
String pubname = Settings.MQTTsubscribe;
|
||||
pubname.replace("/#", "/status");
|
||||
pubname.replace("%sysname%", Settings.Name);
|
||||
MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
|
||||
}
|
||||
#endif
|
||||
|
||||
55
Hardware.ino
Normal file
55
Hardware.ino
Normal file
@@ -0,0 +1,55 @@
|
||||
/********************************************************************************************\
|
||||
* 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;
|
||||
}
|
||||
|
||||
String log = F("INIT : I2C");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
Wire.begin();
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
369
Networking.ino
Normal file
369
Networking.ino
Normal file
@@ -0,0 +1,369 @@
|
||||
/*********************************************************************************************\
|
||||
Syslog client
|
||||
\*********************************************************************************************/
|
||||
void syslog(const char *message)
|
||||
{
|
||||
if (Settings.Syslog_IP[0] != 0)
|
||||
{
|
||||
IPAddress broadcastIP(Settings.Syslog_IP[0], Settings.Syslog_IP[1], Settings.Syslog_IP[2], Settings.Syslog_IP[3]);
|
||||
portUDP.beginPacket(broadcastIP, 514);
|
||||
char str[256];
|
||||
str[0] = 0;
|
||||
snprintf_P(str, sizeof(str), PSTR("<7>ESP Unit: %u : %s"), Settings.Unit, message);
|
||||
portUDP.write(str);
|
||||
portUDP.endPacket();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Structs for UDP messaging
|
||||
\*********************************************************************************************/
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
/*********************************************************************************************\
|
||||
Check UDP messages
|
||||
\*********************************************************************************************/
|
||||
void checkUDP()
|
||||
{
|
||||
if (Settings.UDPPort == 0)
|
||||
return;
|
||||
|
||||
// UDP events
|
||||
int packetSize = portUDP.parsePacket();
|
||||
if (packetSize)
|
||||
{
|
||||
statusLED(true);
|
||||
|
||||
IPAddress remoteIP = portUDP.remoteIP();
|
||||
if (portUDP.remotePort() == 123)
|
||||
{
|
||||
// unexpected NTP reply, drop for now...
|
||||
return;
|
||||
}
|
||||
byte packetBuffer[128];
|
||||
int len = portUDP.read(packetBuffer, 128);
|
||||
if (packetBuffer[0] != 255)
|
||||
{
|
||||
packetBuffer[len] = 0;
|
||||
addLog(LOG_LEVEL_DEBUG, (char*)packetBuffer);
|
||||
struct EventStruct TempEvent;
|
||||
String request = (char*)packetBuffer;
|
||||
parseCommandString(&TempEvent, request);
|
||||
TempEvent.Source = VALUE_SOURCE_SYSTEM;
|
||||
if (!PluginCall(PLUGIN_WRITE, &TempEvent, request))
|
||||
ExecuteCommand(VALUE_SOURCE_SYSTEM, (char*)packetBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetBuffer[1] > 1 && packetBuffer[1] < 6)
|
||||
{
|
||||
String log = (F("UDP : Sensor msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)packetBuffer[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
// binary data!
|
||||
switch (packetBuffer[1])
|
||||
{
|
||||
case 1: // sysinfo message
|
||||
{
|
||||
byte mac[6];
|
||||
byte ip[4];
|
||||
byte unit = packetBuffer[12];
|
||||
for (byte x = 0; x < 6; x++)
|
||||
mac[x] = packetBuffer[x + 2];
|
||||
for (byte x = 0; x < 4; x++)
|
||||
ip[x] = packetBuffer[x + 8];
|
||||
|
||||
if (unit < UNIT_MAX)
|
||||
{
|
||||
for (byte x = 0; x < 4; x++)
|
||||
Nodes[unit].ip[x] = packetBuffer[x + 8];
|
||||
Nodes[unit].age = 0; // reset 'age counter'
|
||||
if (len >20) // extended packet size
|
||||
{
|
||||
Nodes[unit].build = packetBuffer[13] + 256*packetBuffer[14];
|
||||
}
|
||||
}
|
||||
|
||||
char macaddress[20];
|
||||
sprintf_P(macaddress, PSTR("%02x:%02x:%02x:%02x:%02x:%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
char ipaddress[16];
|
||||
sprintf_P(ipaddress, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
char log[80];
|
||||
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)&packetBuffer, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
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]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)&packetBuffer, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.Data = (byte*)packetBuffer;
|
||||
TempEvent.Par1 = remoteIP[3];
|
||||
PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task info using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
infoReply.destUnit = x;
|
||||
sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task data using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
dataReply.destUnit = x;
|
||||
sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send event using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPCommand(byte destUnit, char* data, byte dataLength)
|
||||
{
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
sendUDP(x, (byte*)data, dataLength);
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send UDP message
|
||||
\*********************************************************************************************/
|
||||
void sendUDP(byte unit, byte* data, byte size)
|
||||
{
|
||||
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(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();
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Refresh aging for remote units, drop if too old...
|
||||
\*********************************************************************************************/
|
||||
void refreshNodeList()
|
||||
{
|
||||
for (byte counter = 0; counter < UNIT_MAX; counter++)
|
||||
{
|
||||
if (Nodes[counter].ip[0] != 0)
|
||||
{
|
||||
Nodes[counter].age++; // increment age counter
|
||||
if (Nodes[counter].age > 10) // if entry to old, clear this node ip from the list.
|
||||
for (byte x = 0; x < 4; x++)
|
||||
Nodes[counter].ip[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendSysInfoUDP(byte repeats)
|
||||
{
|
||||
char log[80];
|
||||
if (Settings.UDPPort == 0)
|
||||
return;
|
||||
|
||||
// 1 byte 'binary token 255'
|
||||
// 1 byte id '1'
|
||||
// 6 byte mac
|
||||
// 4 byte ip
|
||||
// 1 byte unit
|
||||
// 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);
|
||||
for (byte counter = 0; counter < repeats; counter++)
|
||||
{
|
||||
byte data[80];
|
||||
data[0] = 255;
|
||||
data[1] = 1;
|
||||
for (byte x = 0; x < 6; x++)
|
||||
data[x + 2] = mac[x];
|
||||
IPAddress ip = Ethernet.localIP();
|
||||
for (byte x = 0; x < 4; x++)
|
||||
data[x + 8] = ip[x];
|
||||
data[12] = Settings.Unit;
|
||||
data[13] = Settings.Build & 0xff;
|
||||
data[14] = Settings.Build >> 8;
|
||||
memcpy((byte*)data+15,Settings.Name,25);
|
||||
data[40] = NODE_TYPE_ID;
|
||||
statusLED(true);
|
||||
|
||||
IPAddress broadcastIP(255, 255, 255, 255);
|
||||
portUDP.beginPacket(broadcastIP, Settings.UDPPort);
|
||||
portUDP.write(data, 80);
|
||||
portUDP.endPacket();
|
||||
if (counter < (repeats - 1))
|
||||
delay(500);
|
||||
}
|
||||
|
||||
// store my own info also in the list...
|
||||
if (Settings.Unit < UNIT_MAX)
|
||||
{
|
||||
IPAddress ip = Ethernet.localIP();
|
||||
for (byte x = 0; x < 4; x++)
|
||||
Nodes[Settings.Unit].ip[x] = ip[x];
|
||||
Nodes[Settings.Unit].age = 0;
|
||||
Nodes[Settings.Unit].build = Settings.Build;
|
||||
}
|
||||
}
|
||||
|
||||
43
Serial.ino
Normal file
43
Serial.ino
Normal file
@@ -0,0 +1,43 @@
|
||||
/********************************************************************************************\
|
||||
* Get data from Serial Interface
|
||||
\*********************************************************************************************/
|
||||
#define INPUT_BUFFER_SIZE 128
|
||||
|
||||
byte SerialInByte;
|
||||
int SerialInByteCounter = 0;
|
||||
char InputBuffer_Serial[INPUT_BUFFER_SIZE + 2];
|
||||
|
||||
void serial()
|
||||
{
|
||||
while (Serial.available())
|
||||
{
|
||||
SerialInByte = Serial.read();
|
||||
if (SerialInByte == 255) // binary data...
|
||||
{
|
||||
Serial.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isprint(SerialInByte))
|
||||
{
|
||||
if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits
|
||||
InputBuffer_Serial[SerialInByteCounter++] = SerialInByte;
|
||||
}
|
||||
|
||||
if (SerialInByte == '\n')
|
||||
{
|
||||
InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed
|
||||
Serial.write('>');
|
||||
Serial.println(InputBuffer_Serial);
|
||||
String action = InputBuffer_Serial;
|
||||
struct EventStruct TempEvent;
|
||||
parseCommandString(&TempEvent, action);
|
||||
TempEvent.Source = VALUE_SOURCE_SERIAL;
|
||||
if (!PluginCall(PLUGIN_WRITE, &TempEvent, action))
|
||||
ExecuteCommand(VALUE_SOURCE_SERIAL, InputBuffer_Serial);
|
||||
SerialInByteCounter = 0;
|
||||
InputBuffer_Serial[0] = 0; // serial data processed, clear buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2085
WebServer.ino
Normal file
2085
WebServer.ino
Normal file
File diff suppressed because it is too large
Load Diff
170
_C001.ino
Normal file
170
_C001.ino
Normal file
@@ -0,0 +1,170 @@
|
||||
//#######################################################################################################
|
||||
//########################### 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))
|
||||
{
|
||||
// todo 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
|
||||
EthernetClient client;
|
||||
if (!client.connect(host, Settings.ControllerPort))
|
||||
{
|
||||
connectionFailures++;
|
||||
strcpy_P(log, PSTR("HTTP : connection failed"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
#if socketdebug
|
||||
ShowSocketStatus();
|
||||
#endif
|
||||
statusLED(true);
|
||||
if (connectionFailures)
|
||||
connectionFailures--;
|
||||
|
||||
// We now create a URI for the request
|
||||
String url = F("/json.htm?type=command¶m=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 += ";0";
|
||||
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 += ";0;";
|
||||
url += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
url += ";0";
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
url = F("/json.htm?type=command¶m=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¶m=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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
227
_C002.ino
Normal file
227
_C002.ino
Normal file
@@ -0,0 +1,227 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 002: Domoticz MQTT ######################################
|
||||
//#######################################################################################################
|
||||
|
||||
#if FEATURE_MQTT_DOM
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
110
_C005.ino
Normal file
110
_C005.ino
Normal file
@@ -0,0 +1,110 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 005: OpenHAB MQTT #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
#define CPLUGIN_005
|
||||
#define CPLUGIN_ID_005 5
|
||||
#define CPLUGIN_NAME_005 "OpenHAB MQTT"
|
||||
|
||||
boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_005;
|
||||
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_005);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_TEMPLATE:
|
||||
{
|
||||
strcpy_P(Settings.MQTTsubscribe, PSTR("/%sysname%/#"));
|
||||
strcpy_P(Settings.MQTTpublish, PSTR("/%sysname%/%tskname%/%valname%"));
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_RECV:
|
||||
{
|
||||
// Split topic into array
|
||||
String tmpTopic = event->String1.substring(1);
|
||||
String topicSplit[10];
|
||||
int SlashIndex = tmpTopic.indexOf('/');
|
||||
byte count = 0;
|
||||
while (SlashIndex > 0 && count < 10 - 1)
|
||||
{
|
||||
topicSplit[count] = tmpTopic.substring(0, SlashIndex);
|
||||
tmpTopic = tmpTopic.substring(SlashIndex + 1);
|
||||
SlashIndex = tmpTopic.indexOf('/');
|
||||
count++;
|
||||
}
|
||||
topicSplit[count] = tmpTopic;
|
||||
|
||||
String cmd = "";
|
||||
struct EventStruct TempEvent;
|
||||
|
||||
if (topicSplit[count] == "cmd")
|
||||
{
|
||||
cmd = event->String2;
|
||||
parseCommandString(&TempEvent, cmd);
|
||||
TempEvent.Source = VALUE_SOURCE_MQTT;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = topicSplit[count - 1];
|
||||
TempEvent.Par1 = topicSplit[count].toInt();
|
||||
TempEvent.Par2 = event->String2.toFloat();
|
||||
TempEvent.Par3 = 0;
|
||||
}
|
||||
// in case of event, store to buffer and return...
|
||||
String command = parseString(cmd, 1);
|
||||
if (command == F("event"))
|
||||
eventBuffer = cmd.substring(6);
|
||||
else
|
||||
PluginCall(PLUGIN_WRITE, &TempEvent, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
statusLED(true);
|
||||
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
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]);
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
{
|
||||
String tmppubname = pubname;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
346
_P001_Switch.ino
Normal file
346
_P001_Switch.ino
Normal file
@@ -0,0 +1,346 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 001: Input Switch #########################################
|
||||
//#######################################################################################################
|
||||
|
||||
// Adapted from ESP Easy, changes:
|
||||
// WebServer.arg() -> WebServerarg()
|
||||
// Changed pin limit from 0-16 to 2-13
|
||||
|
||||
#define PLUGIN_001
|
||||
#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;
|
||||
static byte switchstate[TASKS_MAX];
|
||||
static byte outputstate[TASKS_MAX];
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_001;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = true;
|
||||
Device[deviceCount].InverseLogicOption = true;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].TimerOptional = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_001);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_001));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[2];
|
||||
options[0] = F("Switch");
|
||||
options[1] = F("Dimmer");
|
||||
int optionValues[2];
|
||||
optionValues[0] = 1;
|
||||
optionValues[1] = 2;
|
||||
string += F("<TR><TD>Switch Type:<TD><select name='plugin_001_type'>");
|
||||
for (byte x = 0; x < 2; x++)
|
||||
{
|
||||
string += F("<option value='");
|
||||
string += optionValues[x];
|
||||
string += "'";
|
||||
if (choice == optionValues[x])
|
||||
string += F(" selected");
|
||||
string += ">";
|
||||
string += options[x];
|
||||
string += F("</option>");
|
||||
}
|
||||
string += F("</select>");
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
|
||||
{
|
||||
char tmpString[128];
|
||||
sprintf_P(tmpString, PSTR("<TR><TD>Dim value:<TD><input type='text' name='plugin_001_dimvalue' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
|
||||
string += tmpString;
|
||||
}
|
||||
|
||||
choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
String buttonOptions[3];
|
||||
buttonOptions[0] = F("Normal Switch");
|
||||
buttonOptions[1] = F("Push Button Active Low");
|
||||
buttonOptions[2] = F("Push Button Active High");
|
||||
int buttonOptionValues[3];
|
||||
buttonOptionValues[0] = 0;
|
||||
buttonOptionValues[1] = 1;
|
||||
buttonOptionValues[2] = 2;
|
||||
string += F("<TR><TD>Switch Button Type:<TD><select name='plugin_001_button'>");
|
||||
for (byte x = 0; x < 3; x++)
|
||||
{
|
||||
string += F("<option value='");
|
||||
string += buttonOptionValues[x];
|
||||
string += "'";
|
||||
if (choice == buttonOptionValues[x])
|
||||
string += F(" selected");
|
||||
string += ">";
|
||||
string += buttonOptions[x];
|
||||
string += F("</option>");
|
||||
}
|
||||
string += F("</select>");
|
||||
|
||||
string += F("<TR><TD>Send Boot state:<TD>");
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][3])
|
||||
string += F("<input type=checkbox name=plugin_001_boot checked>");
|
||||
else
|
||||
string += F("<input type=checkbox name=plugin_001_boot>");
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
String plugin1 = WebServerarg(F("plugin_001_type"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
|
||||
{
|
||||
String plugin2 = WebServerarg(F("plugin_001_dimvalue"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
|
||||
}
|
||||
String plugin3 = WebServerarg(F("plugin_001_button"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();
|
||||
|
||||
String plugin4 = WebServerarg(F("plugin_001_boot"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3] = (plugin4 == "on");
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (Settings.TaskDevicePin1PullUp[event->TaskIndex])
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
|
||||
else
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT);
|
||||
|
||||
setPinState(PLUGIN_ID_001, Settings.TaskDevicePin1[event->TaskIndex], PIN_MODE_INPUT, 0);
|
||||
|
||||
switchstate[event->TaskIndex] = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
outputstate[event->TaskIndex] = switchstate[event->TaskIndex];
|
||||
|
||||
// if boot state must be send, inverse default state
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][3])
|
||||
{
|
||||
switchstate[event->TaskIndex] = !switchstate[event->TaskIndex];
|
||||
outputstate[event->TaskIndex] = !outputstate[event->TaskIndex];
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
byte state = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
if (state != switchstate[event->TaskIndex])
|
||||
{
|
||||
switchstate[event->TaskIndex] = state;
|
||||
byte currentOutputState = outputstate[event->TaskIndex];
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 0) //normal switch
|
||||
outputstate[event->TaskIndex] = state;
|
||||
else
|
||||
{
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 1) // active low push button
|
||||
{
|
||||
if (state == 0)
|
||||
outputstate[event->TaskIndex] = !outputstate[event->TaskIndex];
|
||||
}
|
||||
else // active high push button
|
||||
{
|
||||
if (state == 1)
|
||||
outputstate[event->TaskIndex] = !outputstate[event->TaskIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// send if output needs to be changed
|
||||
if (currentOutputState != outputstate[event->TaskIndex])
|
||||
{
|
||||
byte sendState = outputstate[event->TaskIndex];
|
||||
if (Settings.TaskDevicePin1Inversed[event->TaskIndex])
|
||||
sendState = !outputstate[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex] = sendState;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
if ((sendState == 1) && (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2))
|
||||
{
|
||||
event->sensorType = SENSOR_TYPE_DIMMER;
|
||||
UserVar[event->BaseVarIndex] = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
}
|
||||
String log = F("SW : State ");
|
||||
log += sendState;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendData(event);
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
// We do not actually read the pin state as this is already done 10x/second
|
||||
// Instead we just send the last known state stored in Uservar
|
||||
String log = F("SW : State ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
String log = "";
|
||||
String command = parseString(string, 1);
|
||||
|
||||
if (command == F("gpio"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 2 && event->Par1 <= 13)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("pwm"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 2 && event->Par1 <= 13)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
|
||||
if(event->Par3 != 0)
|
||||
{
|
||||
byte prev_mode;
|
||||
uint16_t prev_value;
|
||||
getPinState(PLUGIN_ID_001, event->Par1, &prev_mode, &prev_value);
|
||||
if(prev_mode != PIN_MODE_PWM)
|
||||
prev_value = 0;
|
||||
|
||||
int32_t step_value = ((event->Par2 - prev_value) << 12) / event->Par3;
|
||||
int32_t curr_value = prev_value << 12;
|
||||
int16_t new_value;
|
||||
int i = event->Par3;
|
||||
while(i--){
|
||||
curr_value += step_value;
|
||||
new_value = (uint16_t)(curr_value >> 12);
|
||||
analogWrite(event->Par1, new_value);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
analogWrite(event->Par1, event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_PWM, event->Par2);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("pulse"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 2 && event->Par1 <= 13)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
delay(event->Par3);
|
||||
digitalWrite(event->Par1, !event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Pulsed for ")) + String(event->Par3) + String(F(" mS"));
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("longpulse"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 2 && event->Par1 <= 13)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_001, event->Par1, !event->Par2, 0);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S"));
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("servo"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 0 && event->Par1 <= 2)
|
||||
switch (event->Par1)
|
||||
{
|
||||
case 1:
|
||||
// todo myservo1.attach(event->Par2);
|
||||
// todo myservo1.write(event->Par3);
|
||||
break;
|
||||
case 2:
|
||||
// todo myservo2.attach(event->Par2);
|
||||
// todo myservo2.write(event->Par3);
|
||||
break;
|
||||
}
|
||||
setPinState(PLUGIN_ID_001, event->Par2, PIN_MODE_SERVO, event->Par3);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par2) + String(F(" Servo set to ")) + String(event->Par3);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par2, log, 0));
|
||||
}
|
||||
|
||||
if (command == F("status"))
|
||||
{
|
||||
if (parseString(string, 2) == F("gpio"))
|
||||
{
|
||||
success = true;
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par2, dummyString, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("inputswitchstate"))
|
||||
{
|
||||
success = true;
|
||||
UserVar[event->Par1 * VARS_PER_TASK] = event->Par2;
|
||||
outputstate[event->Par1] = event->Par2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TIMER_IN:
|
||||
{
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
62
_P002_ADC.ino
Normal file
62
_P002_ADC.ino
Normal file
@@ -0,0 +1,62 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 002: Analog ###############################################
|
||||
//#######################################################################################################
|
||||
|
||||
// Adapted from ESP Easy, changes:
|
||||
// WebServer.arg() -> WebServerarg()
|
||||
// port selection as we have a lot of analog ports here...
|
||||
|
||||
#define PLUGIN_002
|
||||
#define PLUGIN_ID_002 2
|
||||
#define PLUGIN_NAME_002 "Analog input"
|
||||
#define PLUGIN_VALUENAME1_002 "Analog"
|
||||
boolean Plugin_002(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_002;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_ANALOG;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].Ports = 1;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = true;
|
||||
Device[deviceCount].ValueCount = 1;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_002);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_002));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
int value = analogRead(Settings.TaskDevicePort[event->TaskIndex]);
|
||||
UserVar[event->BaseVarIndex] = (float)value;
|
||||
String log = F("ADC : Analog port ");
|
||||
log += Settings.TaskDevicePort[event->TaskIndex];
|
||||
log += F(" value: ");
|
||||
log += value;
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
260
_P003_Pulse.ino
Normal file
260
_P003_Pulse.ino
Normal file
@@ -0,0 +1,260 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 003: Pulse ###############################################
|
||||
//#######################################################################################################
|
||||
|
||||
// Adapted from ESP Easy, changes:
|
||||
// WebServer.arg() -> WebServerarg()
|
||||
|
||||
#define PLUGIN_003
|
||||
#define PLUGIN_ID_003 3
|
||||
#define PLUGIN_NAME_003 "Pulse Counter"
|
||||
#define PLUGIN_VALUENAME1_003 "Count"
|
||||
#define PLUGIN_VALUENAME2_003 "Total"
|
||||
#define PLUGIN_VALUENAME3_003 "Time"
|
||||
|
||||
unsigned long Plugin_003_pulseCounter[TASKS_MAX];
|
||||
unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX];
|
||||
unsigned long Plugin_003_pulseTime[TASKS_MAX];
|
||||
unsigned long Plugin_003_pulseTimePrevious[TASKS_MAX];
|
||||
|
||||
boolean Plugin_003(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_003;
|
||||
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 = 3;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_003);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_003));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_003));
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_003));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
char tmpString[128];
|
||||
sprintf_P(tmpString, PSTR("<TR><TD>Debounce Time (mSec):<TD><input type='text' name='plugin_003' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
string += tmpString;
|
||||
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
String options[3];
|
||||
options[0] = F("Delta");
|
||||
options[1] = F("Delta/Total/Time");
|
||||
options[2] = F("Total");
|
||||
int optionValues[3];
|
||||
optionValues[0] = 0;
|
||||
optionValues[1] = 1;
|
||||
optionValues[2] = 2;
|
||||
string += F("<TR><TD>Counter Type:<TD><select name='plugin_003_countertype'>");
|
||||
for (byte x = 0; x < 3; x++)
|
||||
{
|
||||
string += F("<option value='");
|
||||
string += optionValues[x];
|
||||
string += "'";
|
||||
if (choice == optionValues[x])
|
||||
string += F(" selected");
|
||||
string += ">";
|
||||
string += options[x];
|
||||
string += F("</option>");
|
||||
}
|
||||
string += F("</select>");
|
||||
|
||||
if (choice !=0)
|
||||
string += F("<span style=\"color:red\">Total count is not persistent!</span>");
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
String plugin1 = WebServerarg(F("plugin_003"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
|
||||
String plugin2 = WebServerarg(F("plugin_003_countertype"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SHOW_VALUES:
|
||||
{
|
||||
string += F("<div class=\"div_l\">");
|
||||
string += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
string += F(":</div><div class=\"div_r\">");
|
||||
string += Plugin_003_pulseCounter[event->TaskIndex];
|
||||
string += F("</div><div class=\"div_br\"></div><div class=\"div_l\">");
|
||||
string += ExtraTaskSettings.TaskDeviceValueNames[1];
|
||||
string += F(":</div><div class=\"div_r\">");
|
||||
string += Plugin_003_pulseTotalCounter[event->TaskIndex];
|
||||
string += F("</div><div class=\"div_br\"></div><div class=\"div_l\">");
|
||||
string += ExtraTaskSettings.TaskDeviceValueNames[2];
|
||||
string += F(":</div><div class=\"div_r\">");
|
||||
string += Plugin_003_pulseTime[event->TaskIndex];
|
||||
string += F("</div>");
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
String log = F("INIT : Pulse ");
|
||||
log += Settings.TaskDevicePin1[event->TaskIndex];
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
|
||||
Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex];
|
||||
|
||||
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
event->sensorType = SENSOR_TYPE_SINGLE;
|
||||
UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
event->sensorType = SENSOR_TYPE_TRIPLE;
|
||||
UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
|
||||
UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
event->sensorType = SENSOR_TYPE_SINGLE;
|
||||
UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
Plugin_003_pulseCounter[event->TaskIndex] = 0;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Check Pulse Counters (called from irq handler)
|
||||
\*********************************************************************************************/
|
||||
void Plugin_003_pulsecheck(byte Index)
|
||||
{
|
||||
unsigned long PulseTime=millis() - Plugin_003_pulseTimePrevious[Index];
|
||||
if(PulseTime > Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task
|
||||
{
|
||||
Plugin_003_pulseCounter[Index]++;
|
||||
Plugin_003_pulseTotalCounter[Index]++;
|
||||
Plugin_003_pulseTime[Index] = PulseTime;
|
||||
Plugin_003_pulseTimePrevious[Index]=millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Pulse Counter IRQ handlers
|
||||
\*********************************************************************************************/
|
||||
void Plugin_003_pulse_interrupt1()
|
||||
{
|
||||
Plugin_003_pulsecheck(0);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt2()
|
||||
{
|
||||
Plugin_003_pulsecheck(1);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt3()
|
||||
{
|
||||
Plugin_003_pulsecheck(2);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt4()
|
||||
{
|
||||
Plugin_003_pulsecheck(3);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt5()
|
||||
{
|
||||
Plugin_003_pulsecheck(4);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt6()
|
||||
{
|
||||
Plugin_003_pulsecheck(5);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt7()
|
||||
{
|
||||
Plugin_003_pulsecheck(6);
|
||||
}
|
||||
void Plugin_003_pulse_interrupt8()
|
||||
{
|
||||
Plugin_003_pulsecheck(7);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Init Pulse Counters
|
||||
\*********************************************************************************************/
|
||||
void Plugin_003_pulseinit(byte Par1, byte Index)
|
||||
{
|
||||
// Init IO pins
|
||||
String log = F("PULSE: Init");
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
|
||||
switch (Index)
|
||||
{
|
||||
case 0:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt1, FALLING);
|
||||
break;
|
||||
case 1:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt2, FALLING);
|
||||
break;
|
||||
case 2:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt3, FALLING);
|
||||
break;
|
||||
case 3:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt4, FALLING);
|
||||
break;
|
||||
case 4:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt5, FALLING);
|
||||
break;
|
||||
case 5:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt6, FALLING);
|
||||
break;
|
||||
case 6:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt7, FALLING);
|
||||
break;
|
||||
case 7:
|
||||
attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt8, FALLING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
115
_P033_Dummy.ino
Normal file
115
_P033_Dummy.ino
Normal file
@@ -0,0 +1,115 @@
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 033: Dummy ################################################
|
||||
//#######################################################################################################
|
||||
|
||||
// Adapted from ESP Easy, changes:
|
||||
// WebServer.arg() -> WebServerarg()
|
||||
|
||||
#define PLUGIN_033
|
||||
#define PLUGIN_ID_033 33
|
||||
#define PLUGIN_NAME_033 "Dummy Device"
|
||||
#define PLUGIN_VALUENAME1_033 "Dummy"
|
||||
|
||||
boolean Plugin_033(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_033;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_DUMMY;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].DecimalsOnly = true;
|
||||
Device[deviceCount].ValueCount = 4;
|
||||
Device[deviceCount].SendDataOption = true;
|
||||
Device[deviceCount].TimerOption = true;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_033);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES:
|
||||
{
|
||||
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_033));
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
String options[9];
|
||||
options[0] = F("SENSOR_TYPE_SINGLE");
|
||||
options[1] = F("SENSOR_TYPE_TEMP_HUM");
|
||||
options[2] = F("SENSOR_TYPE_TEMP_BARO");
|
||||
options[3] = F("SENSOR_TYPE_TEMP_HUM_BARO");
|
||||
options[4] = F("SENSOR_TYPE_DUAL");
|
||||
options[5] = F("SENSOR_TYPE_TRIPLE");
|
||||
options[6] = F("SENSOR_TYPE_QUAD");
|
||||
options[7] = F("SENSOR_TYPE_SWITCH");
|
||||
options[8] = F("SENSOR_TYPE_DIMMER");
|
||||
int optionValues[9];
|
||||
optionValues[0] = SENSOR_TYPE_SINGLE;
|
||||
optionValues[1] = SENSOR_TYPE_TEMP_HUM;
|
||||
optionValues[2] = SENSOR_TYPE_TEMP_BARO;
|
||||
optionValues[3] = SENSOR_TYPE_TEMP_HUM_BARO;
|
||||
optionValues[4] = SENSOR_TYPE_DUAL;
|
||||
optionValues[5] = SENSOR_TYPE_TRIPLE;
|
||||
optionValues[6] = SENSOR_TYPE_QUAD;
|
||||
optionValues[7] = SENSOR_TYPE_SWITCH;
|
||||
optionValues[8] = SENSOR_TYPE_DIMMER;
|
||||
string += F("<TR><TD>Simulate Data Type:<TD><select name='plugin_033_sensortype'>");
|
||||
for (byte x = 0; x < 9; x++)
|
||||
{
|
||||
string += F("<option value='");
|
||||
string += optionValues[x];
|
||||
string += "'";
|
||||
if (choice == optionValues[x])
|
||||
string += F(" selected");
|
||||
string += ">";
|
||||
string += options[x];
|
||||
string += F("</option>");
|
||||
}
|
||||
string += F("</select>");
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
String plugin1 = WebServerarg(F("plugin_033_sensortype"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
event->sensorType =Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
for (byte x=0; x<4;x++)
|
||||
{
|
||||
String log = F("Dummy: value ");
|
||||
log += x+1;
|
||||
log += F(": ");
|
||||
log += UserVar[event->BaseVarIndex+x];
|
||||
addLog(LOG_LEVEL_INFO,log);
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
142
__CPlugin.ino
Normal file
142
__CPlugin.ino
Normal file
@@ -0,0 +1,142 @@
|
||||
//********************************************************************************
|
||||
// Initialize all Controller CPlugins that where defined earlier
|
||||
// and initialize the function call pointer into the CCPlugin array
|
||||
//********************************************************************************
|
||||
void CPluginInit(void)
|
||||
{
|
||||
byte x;
|
||||
|
||||
// Clear pointer table for all plugins
|
||||
for (x = 0; x < CPLUGIN_MAX; x++)
|
||||
{
|
||||
CPlugin_ptr[x] = 0;
|
||||
CPlugin_id[x] = 0;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
|
||||
#ifdef CPLUGIN_001
|
||||
CPlugin_id[x] = 1; CPlugin_ptr[x++] = &CPlugin_001;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_002
|
||||
CPlugin_id[x] = 2; CPlugin_ptr[x++] = &CPlugin_002;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_003
|
||||
CPlugin_id[x] = 3; CPlugin_ptr[x++] = &CPlugin_003;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_004
|
||||
CPlugin_id[x] = 4; CPlugin_ptr[x++] = &CPlugin_004;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_005
|
||||
CPlugin_id[x] = 5; CPlugin_ptr[x++] = &CPlugin_005;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_006
|
||||
CPlugin_id[x] = 6; CPlugin_ptr[x++] = &CPlugin_006;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_007
|
||||
CPlugin_id[x] = 7; CPlugin_ptr[x++] = &CPlugin_007;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_008
|
||||
CPlugin_id[x] = 8; CPlugin_ptr[x++] = &CPlugin_008;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_009
|
||||
CPlugin_id[x] = 9; CPlugin_ptr[x++] = &CPlugin_009;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_010
|
||||
CPlugin_id[x] = 10; CPlugin_ptr[x++] = &CPlugin_010;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_011
|
||||
CPlugin_id[x] = 11; CPlugin_ptr[x++] = &CPlugin_011;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_012
|
||||
CPlugin_id[x] = 12; CPlugin_ptr[x++] = &CPlugin_012;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_013
|
||||
CPlugin_id[x] = 13; CPlugin_ptr[x++] = &CPlugin_013;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_014
|
||||
CPlugin_id[x] = 14; CPlugin_ptr[x++] = &CPlugin_014;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_015
|
||||
CPlugin_id[x] = 15; CPlugin_ptr[x++] = &CPlugin_015;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_016
|
||||
CPlugin_id[x] = 16; CPlugin_ptr[x++] = &CPlugin_016;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_017
|
||||
CPlugin_id[x] = 17; CPlugin_ptr[x++] = &CPlugin_017;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_018
|
||||
CPlugin_id[x] = 18; CPlugin_ptr[x++] = &CPlugin_018;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_019
|
||||
CPlugin_id[x] = 19; CPlugin_ptr[x++] = &CPlugin_019;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_020
|
||||
CPlugin_id[x] = 20; CPlugin_ptr[x++] = &CPlugin_020;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_021
|
||||
CPlugin_id[x] = 21; CPlugin_ptr[x++] = &CPlugin_021;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_022
|
||||
CPlugin_id[x] = 22; CPlugin_ptr[x++] = &CPlugin_022;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_023
|
||||
CPlugin_id[x] = 23; CPlugin_ptr[x++] = &CPlugin_023;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_024
|
||||
CPlugin_id[x] = 24; CPlugin_ptr[x++] = &CPlugin_024;
|
||||
#endif
|
||||
|
||||
#ifdef CPLUGIN_025
|
||||
CPlugin_id[x] = 25; CPlugin_ptr[x++] = &CPlugin_025;
|
||||
#endif
|
||||
|
||||
CPluginCall(CPLUGIN_PROTOCOL_ADD, 0);
|
||||
}
|
||||
|
||||
byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
{
|
||||
int x;
|
||||
struct EventStruct TempEvent;
|
||||
|
||||
if (event == 0)
|
||||
event=&TempEvent;
|
||||
|
||||
switch (Function)
|
||||
{
|
||||
// Unconditional calls to all plugins
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
for (x = 0; x < CPLUGIN_MAX; x++)
|
||||
if (CPlugin_id[x] != 0)
|
||||
CPlugin_ptr[x](Function, event, dummyString);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
1156
__Plugin.ino
Normal file
1156
__Plugin.ino
Normal file
File diff suppressed because it is too large
Load Diff
13
__ReleaseNotes.ino
Normal file
13
__ReleaseNotes.ino
Normal file
@@ -0,0 +1,13 @@
|
||||
// R147 08-12-2016
|
||||
// First alpha version (Proof Of Concept!)
|
||||
// Based on ESP Easy R147
|
||||
|
||||
// Limited on several features:
|
||||
// SSDP is not implemented
|
||||
// No SPIFFS but using SD card instead. So it does not run without an SD card fitted!
|
||||
// Reused existing UDP socket for NTP, due to shortage of W5100 sockets.
|
||||
|
||||
// Known issues:
|
||||
// WD message was incorrect, failures reported as freemem, freemem is missing, workaround is using string object...
|
||||
// when timed reboot, system does not reboot ???
|
||||
|
||||
Reference in New Issue
Block a user