diff --git a/tasmota/tasmota.ino.cpp b/tasmota/tasmota.ino.cpp deleted file mode 100644 index 7d5161bcb..000000000 --- a/tasmota/tasmota.ino.cpp +++ /dev/null @@ -1,86679 +0,0 @@ -# 1 "/var/folders/rp/3lmq1lbj0bl553yncz6xs3nr0000gn/T/tmpoDJJjn" -#include -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota.ino" -# 34 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota.ino" -#include -#include "tasmota_compat.h" -#include "tasmota_version.h" -#include "tasmota.h" -#include "my_user_config.h" -#ifdef USE_MQTT_TLS - #include -#endif -#include "tasmota_globals.h" -#include "i18n.h" -#include "tasmota_template.h" - -#ifdef ARDUINO_ESP8266_RELEASE_2_4_0 -#include "lwip/init.h" -#if LWIP_VERSION_MAJOR != 1 - #error Please use stable lwIP v1.4 -#endif -#endif - - -#include -#include -#include -#include -#ifdef USE_ARDUINO_OTA - #include - #ifndef USE_DISCOVERY - #define USE_DISCOVERY - #endif -#endif -#ifdef USE_DISCOVERY - #include -#endif -#ifdef USE_I2C - #include -#endif -#ifdef USE_SPI - #include -#endif - - -#include "settings.h" - - - - - -WiFiUDP PortUdp; - -unsigned long feature_drv1; -unsigned long feature_drv2; -unsigned long feature_sns1; -unsigned long feature_sns2; -unsigned long feature5; -unsigned long feature6; -unsigned long serial_polling_window = 0; -unsigned long state_second = 0; -unsigned long state_50msecond = 0; -unsigned long state_100msecond = 0; -unsigned long state_250msecond = 0; -unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; -unsigned long blink_timer = 0; -unsigned long backlog_delay = 0; -power_t power = 0; -power_t last_power = 0; -power_t blink_power; -power_t blink_mask = 0; -power_t blink_powersave; -power_t latching_power = 0; -power_t rel_inverted = 0; -int serial_in_byte_counter = 0; -int ota_state_flag = 0; -int ota_result = 0; -int restart_flag = 0; -int wifi_state_flag = WIFI_RESTART; -int blinks = 201; -uint32_t uptime = 0; -uint32_t loop_load_avg = 0; -uint32_t global_update = 0; -uint32_t web_log_index = 1; -float global_temperature = 9999; -float global_humidity = 0; -float global_pressure = 0; -uint16_t tele_period = 9999; -uint16_t blink_counter = 0; -uint16_t seriallog_timer = 0; -uint16_t syslog_timer = 0; -int16_t save_data_counter; -RulesBitfield rules_flag; -uint8_t mqtt_cmnd_blocked = 0; -uint8_t mqtt_cmnd_blocked_reset = 0; -uint8_t state_250mS = 0; -uint8_t latching_relay_pulse = 0; -uint8_t ssleep; -uint8_t blinkspeed = 1; -uint8_t pin[GPIO_MAX]; -uint8_t active_device = 1; -uint8_t leds_present = 0; -uint8_t led_inverted = 0; -uint8_t led_power = 0; -uint8_t ledlnk_inverted = 0; -uint8_t pwm_inverted = 0; -uint8_t energy_flg = 0; -uint8_t light_flg = 0; -uint8_t light_type = 0; -uint8_t serial_in_byte; -uint8_t ota_retry_counter = OTA_ATTEMPTS; -uint8_t devices_present = 0; -uint8_t seriallog_level; -uint8_t syslog_level; -uint8_t my_module_type; -uint8_t my_adc0; -uint8_t last_source = 0; -uint8_t shutters_present = 0; -uint8_t prepped_loglevel = 0; - -bool serial_local = false; -bool fallback_topic_flag = false; -bool backlog_mutex = false; -bool interlock_mutex = false; -bool stop_flash_rotate = false; -bool blinkstate = false; - -bool pwm_present = false; -bool i2c_flg = false; -bool spi_flg = false; -bool soft_spi_flg = false; -bool ntp_force_sync = false; -bool is_8285 = false; -bool skip_light_fade; -myio my_module; -gpio_flag my_module_flag; -StateBitfield global_state; -char my_version[33]; -char my_image[33]; -char my_hostname[33]; -char mqtt_client[TOPSZ]; -char mqtt_topic[TOPSZ]; -char serial_in_buffer[INPUT_BUFFER_SIZE]; -char mqtt_data[MESSZ]; -char log_data[LOGSZ]; -char web_log[WEB_LOG_SIZE] = {'\0'}; -#ifdef SUPPORT_IF_STATEMENT - #include - LinkedList backlog; - #define BACKLOG_EMPTY (backlog.size() == 0) -#else - uint8_t backlog_index = 0; - uint8_t backlog_pointer = 0; - String backlog[MAX_BACKLOG]; - #define BACKLOG_EMPTY (backlog_pointer == backlog_index) -#endif -void setup(void); -void BacklogLoop(void); -void loop(void); -uint16_t SendMail(char *buffer); -uint32_t GetRtcSettingsCrc(void); -void RtcSettingsSave(void); -void RtcSettingsLoad(void); -bool RtcSettingsValid(void); -uint32_t GetRtcRebootCrc(void); -void RtcRebootSave(void); -void RtcRebootReset(void); -void RtcRebootLoad(void); -bool RtcRebootValid(void); -void SetFlashModeDout(void); -bool VersionCompatible(void); -void SettingsBufferFree(void); -bool SettingsBufferAlloc(void); -uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size); -uint16_t GetSettingsCrc(void); -uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size); -uint32_t GetSettingsCrc32(void); -void SettingsSaveAll(void); -void UpdateQuickPowerCycle(bool update); -uint32_t GetSettingsTextLen(void); -bool SettingsUpdateText(uint32_t index, const char* replace_me); -char* SettingsText(uint32_t index); -void UpdateBackwardCompatibility(void); -uint32_t GetSettingsAddress(void); -void SettingsSave(uint8_t rotate); -void SettingsLoad(void); -void EspErase(uint32_t start_sector, uint32_t end_sector); -void SettingsErase(uint8_t type); -void SettingsSdkErase(void); -void SettingsDefault(void); -void SettingsDefaultSet1(void); -void SettingsDefaultSet2(void); -void SettingsResetStd(void); -void SettingsResetDst(void); -void SettingsDefaultWebColor(void); -void SettingsEnableAllI2cDrivers(void); -void SettingsDelta(void); -void OsWatchTicker(void); -void OsWatchInit(void); -void OsWatchLoop(void); -bool OsWatchBlockedLoop(void); -uint32_t ResetReason(void); -String GetResetReason(void); -size_t strchrspn(const char *str1, int character); -char* subStr(char* dest, char* str, const char *delim, int index); -float CharToFloat(const char *str); -int TextToInt(char *str); -char* ulltoa(unsigned long long value, char *str, int radix); -char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween); -char* Uint64toHex(uint64_t value, char *str, uint16_t bits); -char* dtostrfd(double number, unsigned char prec, char *s); -char* Unescape(char* buffer, uint32_t* size); -char* RemoveSpace(char* p); -char* ReplaceCommaWithDot(char* p); -char* LowerCase(char* dest, const char* source); -char* UpperCase(char* dest, const char* source); -char* UpperCase_P(char* dest, const char* source); -char* Trim(char* p); -char* RemoveAllSpaces(char* p); -char* NoAlNumToUnderscore(char* dest, const char* source); -char IndexSeparator(void); -void SetShortcutDefault(void); -uint8_t Shortcut(void); -bool ValidIpAddress(const char* str); -bool ParseIp(uint32_t* addr, const char* str); -uint32_t ParseParameters(uint32_t count, uint32_t *params); -bool NewerVersion(char* version_str); -char* GetPowerDevice(char* dest, uint32_t idx, size_t size, uint32_t option); -char* GetPowerDevice(char* dest, uint32_t idx, size_t size); -void GetEspHardwareType(void); -String GetDeviceHardware(void); -float ConvertTemp(float c); -float ConvertTempToCelsius(float c); -char TempUnit(void); -float ConvertHumidity(float h); -float CalcTempHumToDew(float t, float h); -float ConvertPressure(float p); -String PressureUnit(void); -float ConvertSpeed(float s); -String SpeedUnit(void); -void ResetGlobalValues(void); -uint32_t SqrtInt(uint32_t num); -uint32_t RoundSqrtInt(uint32_t num); -char* GetTextIndexed(char* destination, size_t destination_size, uint32_t index, const char* haystack); -int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack); -int GetStateNumber(char *state_text); -String GetSerialConfig(void); -void SetSerialBegin(); -void SetSerialConfig(uint32_t serial_config); -void SetSerialBaudrate(uint32_t baudrate); -void SetSerial(uint32_t baudrate, uint32_t serial_config); -void ClaimSerial(void); -void SerialSendRaw(char *codes); -uint32_t GetHash(const char *buffer, size_t size); -void ShowSource(uint32_t source); -void WebHexCode(uint32_t i, const char* code); -uint32_t WebColor(uint32_t i); -char* ResponseGetTime(uint32_t format, char* time_str); -int Response_P(const char* format, ...); -int ResponseTime_P(const char* format, ...); -int ResponseAppend_P(const char* format, ...); -int ResponseAppendTimeFormat(uint32_t format); -int ResponseAppendTime(void); -int ResponseAppendTHD(float f_temperature, float f_humidity); -int ResponseJsonEnd(void); -int ResponseJsonEndEnd(void); -void DigitalWrite(uint32_t gpio_pin, uint32_t state); -uint8_t ModuleNr(void); -bool ValidTemplateModule(uint32_t index); -bool ValidModule(uint32_t index); -String AnyModuleName(uint32_t index); -String ModuleName(void); -void ModuleGpios(myio *gp); -gpio_flag ModuleFlag(void); -void ModuleDefault(uint32_t module); -void SetModuleType(void); -bool FlashPin(uint32_t pin); -uint8_t ValidPin(uint32_t pin, uint32_t gpio); -bool ValidGPIO(uint32_t pin, uint32_t gpio); -bool ValidAdc(void); -bool GetUsedInModule(uint32_t val, uint8_t *arr); -bool JsonTemplate(const char* dataBuf); -void TemplateJson(void); -inline int32_t TimeDifference(uint32_t prev, uint32_t next); -int32_t TimePassedSince(uint32_t timestamp); -bool TimeReached(uint32_t timer); -void SetNextTimeInterval(unsigned long& timer, const unsigned long step); -int32_t TimePassedSinceUsec(uint32_t timestamp); -bool TimeReachedUsec(uint32_t timer); -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size); -bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg); -bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg); -bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg); -bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg); -bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg); -bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg); -uint8_t I2cRead8(uint8_t addr, uint8_t reg); -uint16_t I2cRead16(uint8_t addr, uint8_t reg); -int16_t I2cReadS16(uint8_t addr, uint8_t reg); -uint16_t I2cRead16LE(uint8_t addr, uint8_t reg); -int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg); -int32_t I2cRead24(uint8_t addr, uint8_t reg); -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size); -bool I2cWrite8(uint8_t addr, uint8_t reg, uint16_t val); -bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val); -int8_t I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len); -int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len); -void I2cScan(char *devs, unsigned int devs_len); -void I2cSetActiveFound(uint32_t addr, const char *types); -bool I2cActive(uint32_t addr); -bool I2cSetDevice(uint32_t addr); -void SetSeriallog(uint32_t loglevel); -void SetSyslog(uint32_t loglevel); -void GetLog(uint32_t idx, char** entry_pp, size_t* len_p); -void Syslog(void); -void AddLog(uint32_t loglevel); -void AddLog_P(uint32_t loglevel, const char *formatP); -void AddLog_P(uint32_t loglevel, const char *formatP, const char *formatP2); -void PrepLog_P2(uint32_t loglevel, PGM_P formatP, ...); -void AddLog_P2(uint32_t loglevel, PGM_P formatP, ...); -void AddLog_Debug(PGM_P formatP, ...); -void AddLogBuffer(uint32_t loglevel, uint8_t *buffer, uint32_t count); -void AddLogSerial(uint32_t loglevel); -void AddLogMissed(const char *sensor, uint32_t misses); -void ButtonPullupFlag(uint8 button_bit); -void ButtonInvertFlag(uint8 button_bit); -void ButtonInit(void); -uint8_t ButtonSerial(uint8_t serial_in_byte); -void ButtonHandler(void); -void ButtonLoop(void); -void ButtonPullupFlag(uint8 button_bit); -void ButtonInvertFlag(uint8 button_bit); -void ButtonInit(void); -uint8_t ButtonSerial(uint8_t serial_in_byte); -void ButtonHandler(void); -void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold); -void ButtonLoop(void); -void ResponseCmndNumber(int value); -void ResponseCmndFloat(float value, uint32_t decimals); -void ResponseCmndIdxNumber(int value); -void ResponseCmndChar_P(const char* value); -void ResponseCmndChar(const char* value); -void ResponseCmndStateText(uint32_t value); -void ResponseCmndDone(void); -void ResponseCmndIdxChar(const char* value); -void ResponseCmndAll(uint32_t text_index, uint32_t count); -void ExecuteCommand(const char *cmnd, uint32_t source); -void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len); -void CmndBacklog(void); -void CmndDelay(void); -void CmndPower(void); -void CmndStatus(void); -void CmndState(void); -void CmndTempOffset(void); -void CmndHumOffset(void); -void CmndGlobalTemp(void); -void CmndGlobalHum(void); -void CmndSleep(void); -void CmndUpgrade(void); -void CmndOtaUrl(void); -void CmndSeriallog(void); -void CmndRestart(void); -void CmndPowerOnState(void); -void CmndPulsetime(void); -void CmndBlinktime(void); -void CmndBlinkcount(void); -void CmndSavedata(void); -void CmndSetoption(void); -void CmndTemperatureResolution(void); -void CmndHumidityResolution(void); -void CmndPressureResolution(void); -void CmndPowerResolution(void); -void CmndVoltageResolution(void); -void CmndFrequencyResolution(void); -void CmndCurrentResolution(void); -void CmndEnergyResolution(void); -void CmndWeightResolution(void); -void CmndSpeedUnit(void); -void CmndModule(void); -void CmndModules(void); -void CmndGpio(void); -void CmndGpios(void); -void CmndTemplate(void); -void CmndPwm(void); -void CmndPwmfrequency(void); -void CmndPwmrange(void); -void CmndButtonDebounce(void); -void CmndSwitchDebounce(void); -void CmndBaudrate(void); -void CmndSerialConfig(void); -void CmndSerialSend(void); -void CmndSerialDelimiter(void); -void CmndSyslog(void); -void CmndLoghost(void); -void CmndLogport(void); -void CmndIpAddress(void); -void CmndNtpServer(void); -void CmndAp(void); -void CmndSsid(void); -void CmndPassword(void); -void CmndHostname(void); -void CmndWifiConfig(void); -void CmndFriendlyname(void); -void CmndSwitchMode(void); -void CmndInterlock(void); -void CmndTeleperiod(void); -void CmndReset(void); -void CmndTime(void); -void CmndTimezone(void); -void CmndTimeStdDst(uint32_t ts); -void CmndTimeStd(void); -void CmndTimeDst(void); -void CmndAltitude(void); -void CmndLedPower(void); -void CmndLedState(void); -void CmndLedMask(void); -void CmndWifiPower(void); -void CmndI2cScan(void); -void CmndI2cDriver(void); -void CmndDevGroupName(void); -void CmndDevGroupSend(void); -void CmndDevGroupShare(void); -void CmndDevGroupStatus(void); -void CmndSensor(void); -void CmndDriver(void); -void CmndCrash(void); -void CmndWDT(void); -void CmndBlockedLoop(void); -void CrashDumpClear(void); -bool CrashFlag(void); -void CrashDump(void); -void DeviceGroupsInit(void); -bool DeviceGroupItemShared(bool incoming, uint8_t item); -void SendDeviceGroupPacket(IPAddress ip, char * packet, int len, const char * label); -void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType message_type, ...); -void ProcessDeviceGroupMessage(char * packet, int packet_length); -void DeviceGroupStatus(uint8_t device_group_index); -void DeviceGroupsLoop(void); -void SettingsErase(uint8_t type); -void SettingsLoad(const char *sNvsName, const char *sName, void *pSettings, unsigned nSettingsLen); -void SettingsSave(const char *sNvsName, const char *sName, const void *pSettings, unsigned nSettingsLen); -void ESP32_flashRead(uint32_t offset, uint32_t *data, size_t size); -void ESP32_flashReadHeader(uint32_t offset, uint32_t *data, size_t size); -void SettingsSaveMain(const void *pSettings, unsigned nSettingsLen); -void SettingsLoadUpg(void *pSettings, unsigned nSettingsLen); -void SettingsLoadUpgH(void *pSettings, unsigned nSettingsLen); -void SntpInit(); -uint32_t SntpGetCurrentTimestamp(void); -void CrashDump(void); -bool CrashFlag(void); -void CrashDumpClear(void); -void CmndCrash(void); -void CmndWDT(void); -void CmndBlockedLoop(void); -static bool spiflash_is_ready(void); -static void spi_write_enable(void); -bool EsptoolEraseSector(uint32_t sector); -void EsptoolErase(uint32_t start_sector, uint32_t end_sector); -void GetFeatures(void); -float fmodf(float x, float y); -double FastPrecisePow(double a, double b); -float FastPrecisePowf(const float x, const float y); -double TaylorLog(double x); -inline float sinf(float x); -inline float cosf(float x); -inline float tanf(float x); -inline float atanf(float x); -inline float asinf(float x); -inline float acosf(float x); -inline float sqrtf(float x); -inline float powf(float x, float y); -float cos_52s(float x); -float cos_52(float x); -float sin_52(float x); -float tan_56s(float x); -float tan_56(float x); -float atan_66s(float x); -float atan_66(float x); -float asinf1(float x); -float acosf1(float x); -float sqrt1(const float x); -uint16_t changeUIntScale(uint16_t inum, uint16_t ifrom_min, uint16_t ifrom_max, - uint16_t ito_min, uint16_t ito_max); -void* memchr(const void* ptr, int value, size_t num); -size_t strcspn(const char *str1, const char *str2); -char* strpbrk(const char *s1, const char *s2); -void* memmove_P(void *dest, const void *src, size_t n); -void resetPins(); -void update_rotary(void); -bool RotaryButtonPressed(void); -void RotaryInit(void); -void RotaryHandler(void); -void RotaryLoop(void); -uint32_t UtcTime(void); -uint32_t LocalTime(void); -uint32_t Midnight(void); -bool MidnightNow(void); -bool IsDst(void); -String GetBuildDateAndTime(void); -String GetMinuteTime(uint32_t minutes); -String GetTimeZone(void); -String GetDuration(uint32_t time); -String GetDT(uint32_t time); -String GetDateAndTime(uint8_t time_type); -uint32_t UpTime(void); -uint32_t MinutesUptime(void); -String GetUptime(void); -uint32_t MinutesPastMidnight(void); -void BreakTime(uint32_t time_input, TIME_T &tm); -uint32_t MakeTime(TIME_T &tm); -uint32_t RuleToTime(TimeRule r, int yr); -void RtcSecond(void); -void RtcSetTime(uint32_t epoch); -void RtcInit(void); -String GetStatistics(void); -String GetStatistics(void); -void SwitchPullupFlag(uint16 switch_bit); -void SwitchSetVirtual(uint32_t index, uint8_t state); -uint8_t SwitchGetVirtual(uint32_t index); -uint8_t SwitchLastState(uint32_t index); -bool SwitchState(uint32_t index); -void SwitchProbe(void); -void SwitchInit(void); -void SwitchHandler(uint8_t mode); -void SwitchLoop(void); -char* Format(char* output, const char* input, int size); -char* GetOtaUrl(char *otaurl, size_t otaurl_size); -char* GetTopic_P(char *stopic, uint32_t prefix, char *topic, const char* subtopic); -char* GetGroupTopic_P(char *stopic, const char* subtopic, uint32_t itopic); -char* GetFallbackTopic_P(char *stopic, const char* subtopic); -char* GetStateText(uint32_t state); -void SetLatchingRelay(power_t lpower, uint32_t state); -void SetDevicePower(power_t rpower, uint32_t source); -void RestorePower(bool publish_power, uint32_t source); -void SetAllPower(uint32_t state, uint32_t source); -void SetPowerOnState(void); -void SetLedPowerIdx(uint32_t led, uint32_t state); -void SetLedPower(uint32_t state); -void SetLedPowerAll(uint32_t state); -void SetLedLink(uint32_t state); -void SetPulseTimer(uint32_t index, uint32_t time); -uint32_t GetPulseTimer(uint32_t index); -bool SendKey(uint32_t key, uint32_t device, uint32_t state); -void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source); -void StopAllPowerBlink(void); -void MqttShowPWMState(void); -void MqttShowState(void); -void MqttPublishTeleState(void); -void TempHumDewShow(bool json, bool pass_on, const char *types, float f_temperature, float f_humidity); -bool MqttShowSensor(void); -void MqttPublishSensor(void); -void PerformEverySecond(void); -void Every100mSeconds(void); -void Every250mSeconds(void); -void ArduinoOTAInit(void); -void ArduinoOtaLoop(void); -void SerialInput(void); -void ResetPwm(void); -void GpioInit(void); -bool UdpDisconnect(void); -bool UdpConnect(void); -void PollUdp(void); -int WifiGetRssiAsQuality(int rssi); -bool WifiConfigCounter(void); -void WifiConfig(uint8_t type); -void WifiSetMode(WiFiMode_t wifi_mode); -void WiFiSetSleepMode(void); -void WifiBegin(uint8_t flag, uint8_t channel); -void WifiBeginAfterScan(void); -uint16_t WifiLinkCount(void); -String WifiDowntime(void); -void WifiSetState(uint8_t state); -bool WifiCheckIPv6(void); -String WifiGetIPv6(void); -bool WifiCheckIPAddrStatus(void); -void WifiCheckIp(void); -void WifiCheck(uint8_t param); -int WifiState(void); -String WifiGetOutputPower(void); -void WifiSetOutputPower(void); -void WifiConnect(void); -void EspRestart(void); -void stationKeepAliveNow(void); -void wifiKeepAlive(void); -static void WebGetArg(const char* arg, char* out, size_t max); -static bool WifiIsInManagerMode(); -void ShowWebSource(uint32_t source); -void ExecuteWebCommand(char* svalue, uint32_t source); -void StartWebserver(int type, IPAddress ipweb); -void StopWebserver(void); -void WifiManagerBegin(bool reset_only); -void PollDnsWebserver(void); -bool WebAuthenticate(void); -void HttpHeaderCors(void); -void WSHeaderSend(void); -void WSSend(int code, int ctype, const String& content); -void WSContentBegin(int code, int ctype); -void _WSContentSend(const String& content); -void WSContentFlush(void); -void _WSContentSendBuffer(void); -void WSContentSend_P(const char* formatP, ...); -void WSContentSend_PD(const char* formatP, ...); -void WSContentStart_P(const char* title, bool auth); -void WSContentStart_P(const char* title); -void WSContentSendStyle_P(const char* formatP, ...); -void WSContentSendStyle(void); -void WSContentButton(uint32_t title_index); -void WSContentSpaceButton(uint32_t title_index); -void WSContentSend_THD(const char *types, float f_temperature, float f_humidity); -void WSContentEnd(void); -void WSContentStop(void); -void WebRestart(uint32_t type); -void HandleWifiLogin(void); -void WebSliderColdWarm(void); -void HandleRoot(void); -bool HandleRootStatusRefresh(void); -int32_t IsShutterWebButton(uint32_t idx); -void HandleConfiguration(void); -void HandleTemplateConfiguration(void); -void TemplateSaveSettings(void); -void HandleModuleConfiguration(void); -void ModuleSaveSettings(void); -String HtmlEscape(const String unescaped); -void HandleWifiConfiguration(void); -void WifiSaveSettings(void); -void HandleLoggingConfiguration(void); -void LoggingSaveSettings(void); -void HandleOtherConfiguration(void); -void OtherSaveSettings(void); -void HandleBackupConfiguration(void); -void HandleResetConfiguration(void); -void HandleRestoreConfiguration(void); -void HandleInformation(void); -void HandleUpgradeFirmware(void); -void HandleUpgradeFirmwareStart(void); -void HandleUploadDone(void); -void HandleUploadLoop(void); -void HandlePreflightRequest(void); -void HandleHttpCommand(void); -void HandleConsole(void); -void HandleConsoleRefresh(void); -void HandleNotFound(void); -bool CaptivePortal(void); -String UrlEncode(const String& text); -int WebSend(char *buffer); -bool JsonWebColor(const char* dataBuf); -void CmndEmulation(void); -void CmndSendmail(void); -void CmndWebServer(void); -void CmndWebPassword(void); -void CmndWeblog(void); -void CmndWebRefresh(void); -void CmndWebSend(void); -void CmndWebColor(void); -void CmndWebSensor(void); -void CmndWebButton(void); -void CmndCors(void); -bool Xdrv01(uint8_t function); -bool is_fingerprint_mono_value(uint8_t finger[20], uint8_t value); -void MakeValidMqtt(uint32_t option, char* str); -void MqttDiscoverServer(void); -void MqttInit(void); -bool MqttIsConnected(void); -void MqttDisconnect(void); -void MqttSubscribeLib(const char *topic); -void MqttUnsubscribeLib(const char *topic); -bool MqttPublishLib(const char* topic, bool retained); -void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len); -void MqttRetryCounter(uint8_t value); -void MqttSubscribe(const char *topic); -void MqttUnsubscribe(const char *topic); -void MqttPublishLogging(const char *mxtime); -void MqttPublish(const char* topic, bool retained); -void MqttPublish(const char* topic); -void MqttPublishPrefixTopic_P(uint32_t prefix, const char* subtopic, bool retained); -void MqttPublishPrefixTopic_P(uint32_t prefix, const char* subtopic); -void MqttPublishTeleSensor(void); -void MqttPublishPowerState(uint32_t device); -void MqttPublishAllPowerState(void); -void MqttPublishPowerBlinkState(uint32_t device); -uint16_t MqttConnectCount(void); -void MqttDisconnected(int state); -void MqttConnected(void); -void MqttReconnect(void); -void MqttCheck(void); -bool KeyTopicActive(uint32_t key); -void CmndMqttFingerprint(void); -void CmndMqttUser(void); -void CmndMqttPassword(void); -void CmndMqttlog(void); -void CmndMqttHost(void); -void CmndMqttPort(void); -void CmndMqttRetry(void); -void CmndStateText(void); -void CmndMqttClient(void); -void CmndFullTopic(void); -void CmndPrefix(void); -void CmndPublish(void); -void CmndGroupTopic(void); -void CmndTopic(void); -void CmndButtonTopic(void); -void CmndSwitchTopic(void); -void CmndButtonRetain(void); -void CmndSwitchRetain(void); -void CmndPowerRetain(void); -void CmndSensorRetain(void); -inline void TlsEraseBuffer(uint8_t *buffer); -void loadTlsDir(void); -void CmndTlsKey(void); -uint32_t bswap32(uint32_t x); -void CmndTlsDump(void); -void HandleMqttConfiguration(void); -void MqttSaveSettings(void); -bool Xdrv02(uint8_t function); -bool EnergyTariff1Active(); -void EnergyUpdateToday(void); -void EnergyUpdateTotal(float value, bool kwh); -void Energy200ms(void); -void EnergySaveState(void); -bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag); -void EnergyMarginCheck(void); -void EnergyMqttShow(void); -void EnergyEverySecond(void); -void EnergyCommandCalResponse(uint32_t nvalue); -void CmndEnergyReset(void); -void CmndTariff(void); -void CmndPowerCal(void); -void CmndVoltageCal(void); -void CmndCurrentCal(void); -void CmndPowerSet(void); -void CmndVoltageSet(void); -void CmndCurrentSet(void); -void CmndFrequencySet(void); -void CmndModuleAddress(void); -void CmndPowerDelta(void); -void CmndPowerLow(void); -void CmndPowerHigh(void); -void CmndVoltageLow(void); -void CmndVoltageHigh(void); -void CmndCurrentLow(void); -void CmndCurrentHigh(void); -void CmndMaxPower(void); -void CmndMaxPowerHold(void); -void CmndMaxPowerWindow(void); -void CmndSafePower(void); -void CmndSafePowerHold(void); -void CmndSafePowerWindow(void); -void CmndMaxEnergy(void); -void CmndMaxEnergyStart(void); -void EnergySnsInit(void); -void EnergyShow(bool json); -bool Xdrv03(uint8_t function); -bool Xsns03(uint8_t function); -power_t LightPower(void); -power_t LightPowerIRAM(void); -uint8_t LightDevice(void); -static uint32_t min3(uint32_t a, uint32_t b, uint32_t c); -uint16_t change8to10(uint8_t v); -uint8_t change10to8(uint16_t v); -uint16_t ledGamma_internal(uint16_t v, const struct gamma_table_t *gt_ptr); -uint16_t ledGammaReverse_internal(uint16_t vg, const struct gamma_table_t *gt_ptr); -uint16_t ledGamma10_10(uint16_t v); -uint16_t ledGamma10(uint8_t v); -uint8_t ledGamma(uint8_t v); -void LightPwmOffset(uint32_t offset); -bool LightModuleInit(void); -void LightCalcPWMRange(void); -void LightInit(void); -void LightUpdateColorMapping(void); -uint8_t LightGetDimmer(uint8_t dimmer); -void LightSetDimmer(uint8_t dimmer); -void LightGetHSB(uint16_t *hue, uint8_t *sat, uint8_t *bri); -void LightHsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b); -uint8_t LightGetBri(uint8_t device); -void LightSetBri(uint8_t device, uint8_t bri); -void LightSetColorTemp(uint16_t ct); -uint16_t LightGetColorTemp(void); -void LightSetSignal(uint16_t lo, uint16_t hi, uint16_t value); -void LightPowerOn(void); -void LightState(uint8_t append); -void LightSetPaletteEntry(void); -void LightCycleColor(int8_t direction); -void LightSetPower(void); -void LightAnimate(void); -bool isChannelGammaCorrected(uint32_t channel); -bool isChannelCT(uint32_t channel); -uint16_t fadeGamma(uint32_t channel, uint16_t v); -uint16_t fadeGammaReverse(uint32_t channel, uint16_t vg); -bool LightApplyFade(void); -void LightApplyPower(uint8_t new_color[LST_MAX], power_t power); -void LightSetOutputs(const uint16_t *cur_col_10); -void calcGammaMultiChannels(uint16_t cur_col_10[5]); -void calcGammaBulbs(uint16_t cur_col_10[5]); -void LightSendDeviceGroupStatus(bool force); -void LightHandleDevGroupItem(void); -void LightUpdateScheme(void); -bool LightColorEntry(char *buffer, uint32_t buffer_length); -void CmndSupportColor(void); -void CmndColor(void); -void CmndWhite(void); -void CmndChannel(void); -void CmndHsbColor(void); -void CmndScheme(void); -void CmndWakeup(void); -void CmndColorTemperature(void); -void CmndDimmer(void); -void CmndDimmerRange(void); -void CmndLedTable(void); -void CmndRgbwwTable(void); -void CmndFade(void); -void CmndSpeed(void); -void CmndWakeupDuration(void); -void CmndPalette(void); -void CmndUndocA(void); -bool Xdrv04(uint8_t function); -void IrSendInit(void); -void IrReceiveUpdateThreshold(void); -void IrReceiveInit(void); -void IrReceiveCheck(void); -uint32_t IrRemoteCmndIrSendJson(void); -void CmndIrSend(void); -void IrRemoteCmndResponse(uint32_t error); -bool Xdrv05(uint8_t function); -void IrSendInit(void); -uint8_t reverseBitsInByte(uint8_t b); -uint64_t reverseBitsInBytes64(uint64_t b); -void IrReceiveUpdateThreshold(void); -void IrReceiveInit(void); -String sendIRJsonState(const struct decode_results &results); -void IrReceiveCheck(void); -String listSupportedProtocols(bool hvac); -uint32_t IrRemoteCmndIrHvacJson(void); -void CmndIrHvac(void); -uint32_t IrRemoteCmndIrSendJson(void); -uint32_t IrRemoteCmndIrSendRaw(void); -void CmndIrSend(void); -void IrRemoteCmndResponse(uint32_t error); -bool Xdrv05(uint8_t function); -ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size); -ssize_t rf_find_hex_record_end(uint8_t *buf, size_t size); -ssize_t rf_glue_remnant_with_new_data_and_write(const uint8_t *remnant_data, uint8_t *new_data, size_t new_data_len); -ssize_t rf_decode_and_write(uint8_t *record, size_t size); -ssize_t rf_search_and_write(uint8_t *buf, size_t size); -uint8_t rf_erase_flash(void); -uint8_t SnfBrUpdateInit(void); -void SonoffBridgeReceivedRaw(void); -void SonoffBridgeLearnFailed(void); -void SonoffBridgeReceived(void); -bool SonoffBridgeSerialInput(void); -void SonoffBridgeSendCommand(uint8_t code); -void SonoffBridgeSendAck(void); -void SonoffBridgeSendCode(uint32_t code); -void SonoffBridgeSend(uint8_t idx, uint8_t key); -void SonoffBridgeLearn(uint8_t key); -void CmndRfBridge(void); -void CmndRfKey(void); -void CmndRfRaw(void); -bool Xdrv06(uint8_t function); -int DomoticzBatteryQuality(void); -int DomoticzRssiQuality(void); -void MqttPublishDomoticzFanState(void); -void DomoticzUpdateFanState(void); -void MqttPublishDomoticzPowerState(uint8_t device); -void DomoticzUpdatePowerState(uint8_t device); -void DomoticzMqttUpdate(void); -void DomoticzMqttSubscribe(void); -bool DomoticzMqttData(void); -bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg); -uint8_t DomoticzHumidityState(float h); -void DomoticzSensor(uint8_t idx, char *data); -void DomoticzSensor(uint8_t idx, uint32_t value); -void DomoticzTempHumPressureSensor(float temp, float hum, float baro); -void DomoticzSensorPowerEnergy(int power, char *energy); -void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int power); -void CmndDomoticzIdx(void); -void CmndDomoticzKeyIdx(void); -void CmndDomoticzSwitchIdx(void); -void CmndDomoticzSensorIdx(void); -void CmndDomoticzUpdateTimer(void); -void HandleDomoticzConfiguration(void); -void DomoticzSaveSettings(void); -bool Xdrv07(uint8_t function); -void SerialBridgeInput(void); -void SerialBridgeInit(void); -void CmndSSerialSend(void); -void CmndSBaudrate(void); -bool Xdrv08(uint8_t function); -float JulianischesDatum(void); -float InPi(float x); -float eps(float T); -float BerechneZeitgleichung(float *DK,float T); -void DuskTillDawn(uint8_t *hour_up,uint8_t *minute_up, uint8_t *hour_down, uint8_t *minute_down); -void ApplyTimerOffsets(Timer *duskdawn); -String GetSun(uint32_t dawn); -uint16_t SunMinutes(uint32_t dawn); -void TimerSetRandomWindow(uint32_t index); -void TimerSetRandomWindows(void); -void TimerEverySecond(void); -void PrepShowTimer(uint32_t index); -void CmndTimer(void); -void CmndTimers(void); -void CmndLongitude(void); -void CmndLatitude(void); -void HandleTimerConfiguration(void); -void TimerSaveSettings(void); -bool Xdrv09(uint8_t function); -bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule); -int8_t parseCompareExpression(String &expr, String &leftExpr, String &rightExpr); -void RulesVarReplace(String &commands, const String &sfind, const String &replace); -bool RuleSetProcess(uint8_t rule_set, String &event_saved); -bool RulesProcessEvent(char *json_event); -bool RulesProcess(void); -void RulesInit(void); -void RulesEvery50ms(void); -void RulesEvery100ms(void); -void RulesEverySecond(void); -void RulesSaveBeforeRestart(void); -void RulesSetPower(void); -void RulesTeleperiod(void); -bool RulesMqttData(void); -void CmndSubscribe(void); -void CmndUnsubscribe(void); -bool findNextNumber(char * &pNumber, float &value); -bool findNextVariableValue(char * &pVarname, float &value); -bool findNextObjectValue(char * &pointer, float &value); -bool findNextOperator(char * &pointer, int8_t &op); -float calculateTwoValues(float v1, float v2, uint8_t op); -float evaluateExpression(const char * expression, unsigned int len); -void CmndIf(void); -bool evaluateComparisonExpression(const char *expression, int len); -bool findNextLogicOperator(char * &pointer, int8_t &op); -bool findNextLogicObjectValue(char * &pointer, bool &value); -bool evaluateLogicalExpression(const char * expression, int len); -int8_t findIfBlock(char * &pointer, int &lenWord, int8_t block_type); -void ExecuteCommandBlock(const char * commands, int len); -void ProcessIfStatement(const char* statements); -void RulesPreprocessCommand(char *pCommands); -void CmndRule(void); -void CmndRuleTimer(void); -void CmndEvent(void); -void CmndVariable(void); -void CmndMemory(void); -void CmndCalcResolution(void); -void CmndAddition(void); -void CmndSubtract(void); -void CmndMultiply(void); -void CmndScale(void); -float map_double(float x, float in_min, float in_max, float out_min, float out_max); -bool Xdrv10(uint8_t function); -void SaveFile(const char *name,const uint8_t *buf,uint32_t len); -void LoadFile(const char *name,uint8_t *buf,uint32_t len); -void ScriptEverySecond(void); -void RulesTeleperiod(void); -int16_t Init_Scripter(void); -void ws2812_set_array(float *array ,uint8_t len); -float median_array(float *array,uint8_t len); -float Get_MFVal(uint8_t index,uint8_t bind); -void Set_MFVal(uint8_t index,uint8_t bind,float val); -float Get_MFilter(uint8_t index); -void Set_MFilter(uint8_t index, float invar); -float DoMedian5(uint8_t index, float in); -uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value); -uint16_t GetStack(void); -uint16_t GetStack(void); -uint16_t GetStack(void); -void Replace_Cmd_Vars(char *srcbuf,char *dstbuf,uint16_t dstsize); -void toLog(const char *str); -void toLogN(const char *cp,uint8_t len); -void toLogEOL(const char *s1,const char *str); -void toSLog(const char *str); -int16_t Run_Scripter(const char *type, int8_t tlen, char *js); -void ScripterEvery100ms(void); -void Scripter_save_pvars(void); -void ListDir(char *path, uint8_t depth); -void Script_FileUploadConfiguration(void); -void ScriptFileUploadSuccess(void); -void script_upload(void); -uint8_t DownloadFile(char *file); -void HandleScriptTextareaConfiguration(void); -void HandleScriptConfiguration(void); -void ScriptSaveSettings(void); -void Script_HueStatus(String *response, uint16_t hue_devs); -void Script_Check_Hue(String *response); -void Script_Handle_Hue(String *path); -bool Script_SubCmd(void); -void execute_script(char *script); -bool ScriptCommand(void); -uint16_t xFAT_DATE(uint16_t year, uint8_t month, uint8_t day); -uint16_t xFAT_TIME(uint8_t hour, uint8_t minute, uint8_t second); -void dateTime(uint16_t* date, uint16_t* time); -bool ScriptMqttData(void); -String ScriptSubscribe(const char *data, int data_len); -String ScriptUnsubscribe(const char * data, int data_len); -void Script_Check_HTML_Setvars(void); -void ScriptGetVarname(char *nbuf,char *sp, uint32_t blen); -void ScriptWebShow(void); -void ScriptJsonAppend(void); -bool Xdrv10(uint8_t function); -void KNX_ADD_GA( uint8_t GAop, uint8_t GA_FNUM, uint8_t GA_AREA, uint8_t GA_FDEF ); -void KNX_DEL_GA( uint8_t GAnum ); -void KNX_ADD_CB( uint8_t CBop, uint8_t CB_FNUM, uint8_t CB_AREA, uint8_t CB_FDEF ); -void KNX_DEL_CB( uint8_t CBnum ); -bool KNX_CONFIG_NOT_MATCH(void); -void KNXStart(void); -void KNX_INIT(void); -void KNX_CB_Action(message_t const &msg, void *arg); -void KnxUpdatePowerState(uint8_t device, power_t state); -void KnxSendButtonPower(void); -void KnxSensor(uint8_t sensor_type, float value); -void HandleKNXConfiguration(void); -void KNX_Save_Settings(void); -void CmndKnxTxCmnd(void); -void CmndKnxTxVal(void); -void CmndKnxEnabled(void); -void CmndKnxEnhanced(void); -void CmndKnxPa(void); -void CmndKnxGa(void); -void CmndKnxCb(void); -bool Xdrv11(uint8_t function); -void TryResponseAppend_P(const char *format, ...); -void HAssAnnounceRelayLight(void); -void HAssAnnouncerTriggers(uint8_t device, uint8_t present, uint8_t key, uint8_t toggle, uint8_t hold); -void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint8_t toggle, uint8_t pir); -void HAssAnnounceSwitches(void); -void HAssAnnounceButtons(void); -void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const char *MultiSubName, uint8_t subqty, uint8_t subidx, uint8_t nested, const char* SubKey); -void HAssAnnounceSensors(void); -void HAssAnnounceStatusSensor(void); -void HAssPublishStatus(void); -void HAssDiscovery(void); -void HAssDiscover(void); -void HAssAnyKey(void); -bool Xdrv12(uint8_t function); -void DisplayInit(uint8_t mode); -void DisplayClear(void); -void DisplayDrawHLine(uint16_t x, uint16_t y, int16_t len, uint16_t color); -void DisplayDrawVLine(uint16_t x, uint16_t y, int16_t len, uint16_t color); -void DisplayDrawLine(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color); -void DisplayDrawCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color); -void DisplayDrawFilledCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color); -void DisplayDrawRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color); -void DisplayDrawFilledRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color); -void DisplayDrawFrame(void); -void DisplaySetSize(uint8_t size); -void DisplaySetFont(uint8_t font); -void DisplaySetRotation(uint8_t rotation); -void DisplayDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag); -void DisplayOnOff(uint8_t on); -uint8_t fatoiv(char *cp,float *res); -uint8_t atoiv(char *cp, int16_t *res); -uint8_t atoiV(char *cp, uint16_t *res); -void alignright(char *string); -uint32_t decode_te(char *line); -void DisplayText(void); -void DisplayClearScreenBuffer(void); -void DisplayFreeScreenBuffer(void); -void DisplayAllocScreenBuffer(void); -void DisplayReAllocScreenBuffer(void); -void DisplayFillScreen(uint32_t line); -void DisplayClearLogBuffer(void); -void DisplayFreeLogBuffer(void); -void DisplayAllocLogBuffer(void); -void DisplayReAllocLogBuffer(void); -void DisplayLogBufferAdd(char* txt); -char* DisplayLogBuffer(char temp_code); -void DisplayLogBufferInit(void); -void DisplayJsonValue(const char* topic, const char* device, const char* mkey, const char* value); -void DisplayAnalyzeJson(char *topic, char *json); -void DisplayMqttSubscribe(void); -bool DisplayMqttData(void); -void DisplayLocalSensor(void); -void DisplayInitDriver(void); -void DisplaySetPower(void); -void CmndDisplay(void); -void CmndDisplayModel(void); -void CmndDisplayWidth(void); -void CmndDisplayHeight(void); -void CmndDisplayMode(void); -void CmndDisplayDimmer(void); -void CmndDisplaySize(void); -void CmndDisplayFont(void); -void CmndDisplayRotate(void); -void CmndDisplayText(void); -void CmndDisplayAddress(void); -void CmndDisplayRefresh(void); -void CmndDisplayColumns(void); -void CmndDisplayRows(void); -void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp); -void DrawAClock(uint16_t rad); -void ClrGraph(uint16_t num); -void DefineGraph(uint16_t num,uint16_t xp,uint16_t yp,int16_t xs,uint16_t ys,int16_t dec,float ymin, float ymax,uint8_t icol); -void DisplayCheckGraph(); -void Save_graph(uint8_t num, char *path); -void Restore_graph(uint8_t num, char *path); -void RedrawGraph(uint8_t num, uint8_t flags); -void AddGraph(uint8_t num,uint8_t val); -void AddValue(uint8_t num,float fval); -bool Xdrv13(uint8_t function); -uint16_t MP3_Checksum(uint8_t *array); -void MP3PlayerInit(void); -void MP3_CMD(uint8_t mp3cmd,uint16_t val); -bool MP3PlayerCmd(void); -bool Xdrv14(uint8_t function); -void PCA9685_Detect(void); -void PCA9685_Reset(void); -void PCA9685_SetPWMfreq(double freq); -void PCA9685_SetPWM_Reg(uint8_t pin, uint16_t on, uint16_t off); -void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted); -bool PCA9685_Command(void); -void PCA9685_OutputTelemetry(bool telemetry); -bool Xdrv15(uint8_t function); -void CmndTuyaSend(void); -void CmndTuyaMcu(void); -void TuyaAddMcuFunc(uint8_t fnId, uint8_t dpId); -void UpdateDevices(); -inline bool TuyaFuncIdValid(uint8_t fnId); -uint8_t TuyaGetFuncId(uint8_t dpid); -uint8_t TuyaGetDpId(uint8_t fnId); -void TuyaSendState(uint8_t id, uint8_t type, uint8_t* value); -void TuyaSendBool(uint8_t id, bool value); -void TuyaSendValue(uint8_t id, uint32_t value); -void TuyaSendEnum(uint8_t id, uint32_t value); -void TuyaSendString(uint8_t id, char data[]); -bool TuyaSetPower(void); -bool TuyaSetChannels(void); -void LightSerialDuty(uint16_t duty); -void TuyaRequestState(void); -void TuyaResetWifi(void); -void TuyaProcessStatePacket(void); -void TuyaLowPowerModePacketProcess(void); -void TuyaHandleProductInfoPacket(void); -void TuyaSendLowPowerSuccessIfNeeded(void); -void TuyaNormalPowerModePacketProcess(void); -bool TuyaModuleSelected(void); -void TuyaInit(void); -void TuyaSerialInput(void); -bool TuyaButtonPressed(void); -uint8_t TuyaGetTuyaWifiState(void); -void TuyaSetWifiLed(void); -bool Xnrg16(uint8_t function); -bool Xdrv16(uint8_t function); -void RfReceiveCheck(void); -void RfInit(void); -void CmndRfSend(void); -bool Xdrv17(uint8_t function); -bool ArmtronixSetChannels(void); -void LightSerial2Duty(uint8_t duty1, uint8_t duty2); -void ArmtronixRequestState(void); -bool ArmtronixModuleSelected(void); -void ArmtronixInit(void); -void ArmtronixSerialInput(void); -void ArmtronixSetWifiLed(void); -bool Xdrv18(uint8_t function); -void PS16DZSerialSend(const char *tx_buffer); -void PS16DZSerialSendOk(void); -void PS16DZSerialSendUpdateCommand(void); -void PS16DZSerialInput(void); -bool PS16DZSerialSendUpdateCommandIfRequired(void); -void PS16DZInit(void); -bool PS16DZModuleSelected(void); -bool Xdrv19(uint8_t function); -String HueBridgeId(void); -String HueSerialnumber(void); -String HueUuid(void); -void HueRespondToMSearch(void); -String GetHueDeviceId(uint16_t id); -String GetHueUserId(void); -void HandleUpnpSetupHue(void); -void HueNotImplemented(String *path); -void HueConfigResponse(String *response); -void HueConfig(String *path); -uint8_t getLocalLightSubtype(uint8_t device); -void HueLightStatus1(uint8_t device, String *response); -bool HueActive(uint8_t device); -void HueLightStatus2(uint8_t device, String *response); -uint32_t findEchoGeneration(void); -void HueGlobalConfig(String *path); -void HueAuthentication(String *path); -void CheckHue(String * response, bool &appending); -void HueLightsCommand(uint8_t device, uint32_t device_id, String &response); -void HueLights(String *path); -void HueGroups(String *path); -void HandleHueApi(String *path); -bool Xdrv20(uint8_t function); -String WemoSerialnumber(void); -String WemoUuid(void); -void WemoRespondToMSearch(int echo_type); -void HandleUpnpEvent(void); -void HandleUpnpService(void); -void HandleUpnpMetaService(void); -void HandleUpnpSetupWemo(void); -bool Xdrv21(uint8_t function); -bool IsModuleIfan(void); -uint8_t MaxFanspeed(void); -uint8_t GetFanspeed(void); -void SonoffIFanSetFanspeed(uint8_t fanspeed, bool sequence); -void SonoffIfanReceived(void); -bool SonoffIfanSerialInput(void); -void CmndFanspeed(void); -bool SonoffIfanInit(void); -void SonoffIfanUpdate(void); -bool Xdrv22(uint8_t function); -String getZigbeeStatusMessage(uint8_t status); -void CopyJsonVariant(JsonObject &to, const String &key, const JsonVariant &val); -void CopyJsonArray(JsonArray &to, const JsonArray &arr); -void CopyJsonObject(JsonObject &to, const JsonObject &from); -void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, String *response); -void HueLightStatus2Zigbee(uint16_t shortaddr, String *response); -void ZigbeeHueStatus(String * response, uint16_t shortaddr); -void ZigbeeCheckHue(String * response, bool &appending); -void ZigbeeHueGroups(String * lights); -void ZigbeeHuePower(uint16_t shortaddr, bool power); -void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer); -void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct); -void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y); -void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat); -void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response); -uint16_t fromClusterCode(uint8_t c); -uint8_t toClusterCode(uint16_t c); -class SBuffer hibernateDevice(const struct Z_Device &device); -class SBuffer hibernateDevices(void); -void hydrateDevices(const SBuffer &buf); -void loadZigbeeDevices(void); -void saveZigbeeDevices(void); -void eraseZigbeeDevices(void); -uint8_t Z_getDatatypeLen(uint8_t t); -uint8_t toPercentageCR2032(uint32_t voltage); -uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer &buf, - uint32_t offset, uint32_t buflen); -uint16_t CxToCluster(uint8_t cx); -int32_t Z_ManufKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_ModelKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_Remove(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_Copy(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_AddPressureUnit(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_FloatDiv100(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_FloatDiv10(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_FloatDiv2(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value); -int32_t Z_AqaraCube(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_AqaraVibration(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_AqaraSensor(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -int32_t Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value); -int32_t Z_Unreachable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value); -void zigbeeSetCommandTimer(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint); -inline bool isXYZ(char c); -inline int8_t hexValue(char c); -void parseXYZ(const char *model, const SBuffer &payload, struct Z_XYZ_Var *xyz); -void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t cmd, bool direction); -void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, bool direction, const SBuffer &payload); -const __FlashStringHelper* zigbeeFindCommand(const char *command, uint16_t *cluster, uint16_t *cmd); -inline char hexDigit(uint32_t h); -String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z); -uint32_t ZigbeeAliasOrNumber(const char *state_text); -void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h); -uint8_t ZigbeeGetInstructionSize(uint8_t instr); -void ZigbeeGotoLabel(uint8_t label); -void ZigbeeStateMachine_Run(void); -int32_t ZigbeeProcessInput(class SBuffer &buf); -int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf); -int32_t Z_CheckNVWrite(int32_t res, class SBuffer &buf); -int32_t Z_Reboot(int32_t res, class SBuffer &buf); -int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf); -bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match); -int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf); -int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf); -int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf); -int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf); -int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf); -int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf); -int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf); -int32_t Z_BindRsp(int32_t res, const class SBuffer &buf); -int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf); -int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf); -void Z_SendIEEEAddrReq(uint16_t shortaddr); -void Z_SendActiveEpReq(uint16_t shortaddr); -void Z_SendAFInfoRequest(uint16_t shortaddr); -void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, const JsonObject &json); -int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value); -int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf); -int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf); -int32_t Z_Load_Devices(uint8_t value); -void Z_Query_Bulb(uint16_t shortaddr, uint32_t &wait_ms); -int32_t Z_Query_Bulbs(uint8_t value); -int32_t Z_State_Ready(uint8_t value); -void ZigbeeInputLoop(void); -void ZigbeeInit(void); -uint32_t strToUInt(const JsonVariant &val); -void CmndZbReset(void); -void CmndZbZNPSendOrReceive(bool send); -void CmndZbZNPReceive(void); -void CmndZbZNPSend(void); -void ZigbeeZNPSend(const uint8_t *msg, size_t len); -void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, uint16_t manuf, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId); -void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, bool clusterSpecific, uint16_t manuf, - uint16_t cluster, uint8_t cmd, const char *param); -void CmndZbSend(void); -void ZbBindUnbind(bool unbind); -void CmndZbBind(void); -void CmndZbUnbind(void); -void CmndZbBindState(void); -void CmndZbProbe(void); -void CmndZbProbeOrPing(boolean probe); -void CmndZbPing(void); -void CmndZbName(void); -void CmndZbModelId(void); -void CmndZbLight(void); -void CmndZbForget(void); -void CmndZbSave(void); -void CmndZbRestore(void); -void CmndZbRead(void); -void CmndZbPermitJoin(void); -void CmndZbStatus(void); -void CmndZbConfig(void); -bool Xdrv23(uint8_t function); -void BuzzerOff(void); -void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune, uint32_t mode); -void BuzzerSetStateToLed(uint32_t state); -void BuzzerBeep(uint32_t count); -void BuzzerEnabledBeep(uint32_t count, uint32_t duration); -bool BuzzerPinState(void); -void BuzzerInit(void); -void BuzzerEvery100mSec(void); -void CmndBuzzer(void); -bool Xdrv24(uint8_t function); -void A4988Init(void); -void CmndDoMove(void); -void CmndDoRotate(void); -void CmndDoTurn(void); -void CmndSetMIS(void); -void CmndSetSPR(void); -void CmndSetRPM(void); -bool Xdrv25(uint8_t function); -void AriluxRfInterrupt(void); -void AriluxRfHandler(void); -void AriluxRfInit(void); -void AriluxRfDisable(void); -bool Xdrv26(uint8_t function); -void ShutterLogPos(uint32_t i); -void ShutterRtc50mS(void); -int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index); -uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index); -void ShutterInit(void); -void ShutterReportPosition(bool always); -void ShutterLimitRealAndTargetPositions(uint32_t i); -void ShutterUpdatePosition(void); -bool ShutterState(uint32_t device); -void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos); -void ShutterWaitForMotorStop(uint32_t i); -int32_t ShutterCounterBasedPosition(uint32_t i); -void ShutterRelayChanged(void); -bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index); -void ShutterButtonHandler(void); -void ShutterSetPosition(uint32_t device, uint32_t position); -void CmndShutterOpen(void); -void CmndShutterStopOpen(void); -void CmndShutterClose(void); -void CmndShutterStopClose(void); -void CmndShutterToggle(void); -void CmndShutterStopToggle(void); -void CmndShutterStop(void); -void CmndShutterPosition(void); -void CmndShutterStopPosition(void); -void CmndShutterOpenTime(void); -void CmndShutterCloseTime(void); -void CmndShutterMotorDelay(void); -void CmndShutterRelay(void); -void CmndShutterButton(void); -void CmndShutterSetHalfway(void); -void CmndShutterFrequency(void); -void CmndShutterSetClose(void); -void CmndShutterInvert(void); -void CmndShutterCalibration(void); -void CmndShutterLock(void); -void CmndShutterEnableEndStopTime(void); -void CmndShutterInvertWebButtons(void); -bool Xdrv27(uint8_t function); -void Pcf8574SwitchRelay(void); -void Pcf8574Init(void); -void HandlePcf8574(void); -void Pcf8574SaveSettings(void); -bool Xdrv28(uint8_t function); -bool DeepSleepEnabled(void); -void DeepSleepReInit(void); -void DeepSleepPrepare(void); -void DeepSleepStart(void); -void DeepSleepEverySecond(void); -void CmndDeepsleepTime(void); -bool Xdrv29(uint8_t function); -uint8_t crc8(const uint8_t *p, uint8_t len); -void ExsSendCmd(uint8_t cmd, uint8_t value); -uint8_t ExsSetPower(uint8_t device, uint8_t power); -uint8_t ExsSetBri(uint8_t device, uint8_t bri); -uint8_t ExsSyncState(uint8_t device); -bool ExsSyncState(); -void ExsDebugState(); -void ExsPacketProcess(void); -bool ExsModuleSelected(void); -bool ExsSetChannels(void); -bool ExsSetPower(void); -void EsxMcuStart(void); -void ExsInit(void); -void ExsSerialInput(void); -void CmndExsDimm(void); -void CmndExsDimmTbl(void); -void CmndExsDimmVal(void); -void CmndExsDimms(void); -void CmndExsChLock(void); -void CmndExsState(void); -bool Xdrv30(uint8_t function); -uint32_t TasmotaSlave_FlashStart(void); -uint8_t TasmotaSlave_UpdateInit(void); -void TasmotaSlave_Reset(void); -uint8_t TasmotaSlave_waitForSerialData(int dataCount, int timeout); -uint8_t TasmotaSlave_sendBytes(uint8_t* bytes, int count); -uint8_t TasmotaSlave_execCmd(uint8_t cmd); -uint8_t TasmotaSlave_execParam(uint8_t cmd, uint8_t* params, int count); -uint8_t TasmotaSlave_exitProgMode(void); -uint8_t TasmotaSlave_SetupFlash(void); -uint8_t TasmotaSlave_loadAddress(uint8_t adrHi, uint8_t adrLo); -void TasmotaSlave_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data); -void TasmotaSlave_Flash(void); -void TasmotaSlave_SetFlagFlashing(bool value); -bool TasmotaSlave_GetFlagFlashing(void); -void TasmotaSlave_WriteBuffer(uint8_t *buf, size_t size); -void TasmotaSlave_Init(void); -void TasmotaSlave_Show(void); -void TasmotaSlave_sendCmnd(uint8_t cmnd, uint8_t param); -void CmndTasmotaSlaveReset(void); -void CmndTasmotaSlaveSend(void); -void TasmotaSlave_ProcessIn(void); -bool Xdrv31(uint8_t function); -void HotPlugInit(void); -void HotPlugEverySecond(void); -void CmndHotPlugTime(void); -bool Xdrv32(uint8_t function); -bool NRF24initRadio(); -bool NRF24Detect(void); -bool Xdrv33(uint8_t function); -void WMotorV1Detect(void); -void WMotorV1Reset(void); -void WMotorV1SetFrequency(uint32_t freq); -void WMotorV1SetMotor(uint8_t motor, uint8_t dir, float pwm_val); -bool WMotorV1Command(void); -bool Xdrv34(uint8_t function); -void PWMModulePreInit(void); -void PWMDimmerSetBrightnessLeds(int32_t operation); -void PWMDimmerSetPoweredOffLed(void); -void PWMDimmerSetPower(void); -void PWMDimmerHandleDevGroupItem(void); -void PWMDimmerHandleButton(void); -void CmndBriPreset(void); -bool Xdrv35(uint8_t function); -void CmdSet(void); -void GenerateDeviceCryptKey(); -void CmdSendButton(void); -void SendBit(byte bitToSend); -void CmndSendRaw(void); -void enterrx(); -void entertx(); -void SendSyncPreamble(int l); -void CreateKeeloqPacket(); -void KeeloqInit(); -bool Xdrv36(uint8_t function); -void SonoffD1Received(void); -bool SonoffD1SerialInput(void); -void SonoffD1Send(); -bool SonoffD1SendPower(void); -bool SonoffD1SendDimmer(void); -bool SonoffD1ModuleSelected(void); -bool Xdrv37(uint8_t function); -void PingResponsePoll(void); -void CmndPing(void); -bool Xdrv38(uint8_t function); -void ThermostatInit(void); -bool ThermostatMinuteCounter(void); -inline bool ThermostatSwitchIdValid(uint8_t switchId); -inline bool ThermostatRelayIdValid(uint8_t relayId); -uint8_t ThermostatSwitchStatus(uint8_t input_switch); -void ThermostatSignalProcessingSlow(void); -void ThermostatSignalProcessingFast(void); -void ThermostatCtrState(void); -void ThermostatHybridCtrPhase(void); -bool HeatStateAutoToManual(void); -bool HeatStateManualToAuto(void); -bool HeatStateAllToOff(void); -void ThermostatState(void); -void ThermostatOutputRelay(bool active); -void ThermostatCalculatePI(void); -void ThermostatWorkAutomaticPI(void); -void ThermostatWorkAutomaticRampUp(void); -void ThermostatCtrWork(void); -void ThermostatWork(void); -void ThermostatDiagnostics(void); -void ThermostatController(void); -bool ThermostatTimerArm(int16_t tempVal); -void ThermostatTimerDisarm(void); -void ThermostatVirtualSwitch(void); -void ThermostatVirtualSwitchCtrState(void); -void CmndThermostatModeSet(void); -void CmndTempFrostProtectSet(void); -void CmndControllerModeSet(void); -void CmndInputSwitchSet(void); -void CmndOutputRelaySet(void); -void CmndTimeAllowRampupSet(void); -void CmndTempMeasuredSet(void); -void CmndTempTargetSet(void); -void CmndTempTargetRead(void); -void CmndTempMeasuredRead(void); -void CmndTempMeasuredGrdRead(void); -void CmndTempSensNumberSet(void); -void CmndStateEmergencySet(void); -void CmndPowerMaxSet(void); -void CmndTimeManualToAutoSet(void); -void CmndTimeOnLimitSet(void); -void CmndPropBandSet(void); -void CmndTimeResetSet(void); -void CmndTimePiCycleSet(void); -void CmndTempAntiWindupResetSet(void); -void CmndTempHystSet(void); -void CmndTimeMaxActionSet(void); -void CmndTimeMinActionSet(void); -void CmndTimeSensLostSet(void); -void CmndTimeMinTurnoffActionSet(void); -void CmndTempRupDeltInSet(void); -void CmndTempRupDeltOutSet(void); -void CmndTimeRampupMaxSet(void); -void CmndTimeRampupCycleSet(void); -void CmndTempRampupPiAccErrSet(void); -void CmndTimePiProportRead(void); -void CmndTimePiIntegrRead(void); -bool Xdrv39(uint8_t function); -void ExceptionTest(uint8_t type); -void CpuLoadLoop(void); -void DebugFreeMem(void); -void DebugFreeMem(void); -void DebugFreeMem(void); -void DebugRtcDump(char* parms); -void DebugCfgDump(char* parms); -void DebugCfgPeek(char* parms); -void DebugCfgPoke(char* parms); -void SetFlashMode(uint8_t mode); -void CmndHelp(void); -void CmndRtcDump(void); -void CmndCfgDump(void); -void CmndCfgPeek(void); -void CmndCfgPoke(void); -void CmndCfgXor(void); -void CmndException(void); -void CmndCpuCheck(void); -void CmndFreemem(void); -void CmndSetSensor(void); -void CmndFlashMode(void); -uint32_t DebugSwap32(uint32_t x); -void CmndFlashDump(void); -void CmndI2cWrite(void); -void CmndI2cRead(void); -void CmndI2cStretch(void); -void CmndI2cClock(void); -bool Xdrv99(uint8_t function); -void XsnsDriverState(void); -bool XdrvRulesProcess(void); -void ShowFreeMem(const char *where); -bool XdrvCallDriver(uint32_t driver, uint8_t Function); -bool XdrvCall(uint8_t Function); -void LcdInitMode(void); -void LcdInit(uint8_t mode); -void LcdInitDriver(void); -void LcdDrawStringAt(void); -void LcdDisplayOnOff(uint8_t on); -void LcdCenter(uint8_t row, char* txt); -bool LcdPrintLog(void); -void LcdTime(void); -void LcdRefresh(void); -bool Xdsp01(uint8_t function); -void SSD1306InitDriver(void); -void Ssd1306PrintLog(void); -void Ssd1306Time(void); -void Ssd1306Refresh(void); -bool Xdsp02(byte function); -void MatrixWrite(void); -void MatrixClear(void); -void MatrixFixed(char* txt); -void MatrixCenter(char* txt); -void MatrixScrollLeft(char* txt, int loop); -void MatrixScrollUp(char* txt, int loop); -void MatrixInitMode(void); -void MatrixInit(uint8_t mode); -void MatrixInitDriver(void); -void MatrixOnOff(void); -void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag); -void MatrixPrintLog(uint8_t direction); -void MatrixRefresh(void); -bool Xdsp03(uint8_t function); -void Ili9341InitMode(void); -void Ili9341Init(uint8_t mode); -void Ili9341InitDriver(void); -void Ili9341Clear(void); -void Ili9341DrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag); -void Ili9341DisplayOnOff(uint8_t on); -void Ili9341OnOff(void); -void Ili9341PrintLog(void); -void Ili9341Refresh(void); -bool Xdsp04(uint8_t function); -void EpdInitDriver29(); -void EpdPrintLog29(void); -void EpdRefresh29(void); -bool Xdsp05(uint8_t function); -void EpdInitDriver42(); -void EpdRefresh42(); -bool Xdsp06(uint8_t function); -void SH1106InitDriver(); -void SH1106PrintLog(void); -void SH1106Time(void); -void SH1106Refresh(void); -bool Xdsp07(uint8_t function); -void ILI9488_InitDriver(); -void ILI9488_MQTT(uint8_t count,const char *cp); -void ILI9488_RDW_BUTT(uint32_t count,uint32_t pwr); -void FT6236Check(); -bool Xdsp08(uint8_t function); -void SSD1351_InitDriver(); -void SSD1351PrintLog(void); -void SSD1351Time(void); -void SSD1351Refresh(void); -bool Xdsp09(uint8_t function); -void RA8876_InitDriver(); -void RA8876_MQTT(uint8_t count,const char *cp); -void RA8876_RDW_BUTT(uint32_t count,uint32_t pwr); -void FT5316Check(); -bool Xdsp10(uint8_t function); -void SevensegWrite(void); -void SevensegClear(void); -void SevensegInitMode(void); -void SevensegInit(uint8_t mode); -void SevensegInitDriver(void); -void SevensegOnOff(void); -void SevensegDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag); -void SevensegTime(boolean time_24); -void SevensegRefresh(void); -bool Xdsp11(uint8_t function); -uint8_t XdspPresent(void); -bool XdspCall(uint8_t Function); -void Ws2812StripShow(void); -int mod(int a, int b); -void Ws2812UpdatePixelColor(int position, struct WsColor hand_color, float offset); -void Ws2812UpdateHand(int position, uint32_t index); -void Ws2812Clock(void); -void Ws2812GradientColor(uint32_t schemenr, struct WsColor* mColor, uint32_t range, uint32_t gradRange, uint32_t i); -void Ws2812Gradient(uint32_t schemenr); -void Ws2812Bars(uint32_t schemenr); -void Ws2812Clear(void); -void Ws2812SetColor(uint32_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white); -char* Ws2812GetColor(uint32_t led, char* scolor); -void Ws2812ForceSuspend (void); -void Ws2812ForceUpdate (void); -bool Ws2812SetChannels(void); -void Ws2812ShowScheme(void); -void Ws2812ModuleSelected(void); -void CmndLed(void); -void CmndPixels(void); -void CmndRotation(void); -void CmndWidth(void); -bool Xlgt01(uint8_t function); -void LightDiPulse(uint8_t times); -void LightDckiPulse(uint8_t times); -void LightMy92x1Write(uint8_t data); -void LightMy92x1Init(void); -void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c); -bool My92x1SetChannels(void); -void My92x1ModuleSelected(void); -bool Xlgt02(uint8_t function); -void SM16716_SendBit(uint8_t v); -void SM16716_SendByte(uint8_t v); -void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b); -void SM16716_Init(void); -bool Sm16716SetChannels(void); -void Sm16716ModuleSelected(void); -bool Xlgt03(uint8_t function); -uint8_t Sm2135Write(uint8_t data); -void Sm2135Send(uint8_t *buffer, uint8_t size); -bool Sm2135SetChannels(void); -void Sm2135ModuleSelected(void); -bool Xlgt04(uint8_t function); -void SnfL1Send(const char *buffer); -void SnfL1SerialSendOk(void); -bool SnfL1SerialInput(void); -bool SnfL1SetChannels(void); -void SnfL1ModuleSelected(void); -bool Xlgt05(uint8_t function); -bool ElectriqMoodLSetChannels(void); -void ElectriqMoodLModuleSelected(void); -bool Xlgt06(uint8_t function); -bool XlgtCall(uint8_t function); -void HlwCfInterrupt(void); -void HlwCf1Interrupt(void); -void HlwEvery200ms(void); -void HlwEverySecond(void); -void HlwSnsInit(void); -void HlwDrvInit(void); -bool HlwCommand(void); -bool Xnrg01(uint8_t function); -void CseReceived(void); -bool CseSerialInput(void); -void CseEverySecond(void); -void CseSnsInit(void); -void CseDrvInit(void); -bool CseCommand(void); -bool Xnrg02(uint8_t function); -uint8_t PzemCrc(uint8_t *data); -void PzemSend(uint8_t cmd); -bool PzemReceiveReady(void); -bool PzemRecieve(uint8_t resp, float *data); -void PzemEvery250ms(void); -void PzemSnsInit(void); -void PzemDrvInit(void); -bool PzemCommand(void); -bool Xnrg03(uint8_t function); -uint8_t McpChecksum(uint8_t *data); -unsigned long McpExtractInt(char *data, uint8_t offset, uint8_t size); -void McpSetInt(unsigned long value, uint8_t *data, uint8_t offset, size_t size); -void McpSend(uint8_t *data); -void McpGetAddress(void); -void McpAddressReceive(void); -void McpGetCalibration(void); -void McpParseCalibration(void); -bool McpCalibrationCalc(struct mcp_cal_registers_type *cal_registers, uint8_t range_shift); -void McpSetCalibration(struct mcp_cal_registers_type *cal_registers); -void McpSetSystemConfiguration(uint16 interval); -void McpGetFrequency(void); -void McpParseFrequency(void); -void McpSetFrequency(uint16_t line_frequency_ref, uint16_t gain_line_frequency); -void McpGetData(void); -void McpParseData(void); -void McpSerialInput(void); -void McpEverySecond(void); -void McpSnsInit(void); -void McpDrvInit(void); -bool McpCommand(void); -bool Xnrg04(uint8_t function); -void PzemAcEverySecond(void); -void PzemAcSnsInit(void); -void PzemAcDrvInit(void); -bool PzemAcCommand(void); -bool Xnrg05(uint8_t function); -void PzemDcEverySecond(void); -void PzemDcSnsInit(void); -void PzemDcDrvInit(void); -bool PzemDcCommand(void); -bool Xnrg06(uint8_t function); -int Ade7953RegSize(uint16_t reg); -void Ade7953Write(uint16_t reg, uint32_t val); -int32_t Ade7953Read(uint16_t reg); -void Ade7953Init(void); -void Ade7953GetData(void); -void Ade7953EnergyEverySecond(void); -void Ade7953DrvInit(void); -bool Ade7953Command(void); -bool Xnrg07(uint8_t function); -void SDM120Every250ms(void); -void Sdm120SnsInit(void); -void Sdm120DrvInit(void); -void Sdm220Reset(void); -void Sdm220Show(bool json); -bool Xnrg08(uint8_t function); -void Dds2382EverySecond(void); -void Dds2382SnsInit(void); -void Dds2382DrvInit(void); -bool Xnrg09(uint8_t function); -void SDM630Every250ms(void); -void Sdm630SnsInit(void); -void Sdm630DrvInit(void); -bool Xnrg10(uint8_t function); -void DDSU666Every250ms(void); -void Ddsu666SnsInit(void); -void Ddsu666DrvInit(void); -bool Xnrg11(uint8_t function); -bool solaxX1_RS485ReceiveReady(void); -void solaxX1_RS485Send(uint16_t msgLen); -uint8_t solaxX1_RS485Receive(uint8_t *value); -uint16_t solaxX1_calculateCRC(uint8_t *bExternTxPackage, uint8_t bLen); -void solaxX1_SendInverterAddress(void); -void solaxX1_QueryLiveData(void); -uint8_t solaxX1_ParseErrorCode(uint32_t code); -void solaxX1250MSecond(void); -void solaxX1SnsInit(void); -void solaxX1DrvInit(void); -void solaxX1Show(bool json); -bool Xnrg12(uint8_t function); -void FifLEEvery250ms(void); -void FifLESnsInit(void); -void FifLEDrvInit(void); -void FifLEReset(void); -void FifLEShow(bool json); -bool Xnrg13(uint8_t function); -bool XnrgCall(uint8_t function); -void CounterUpdate(uint8_t index); -void CounterUpdate1(void); -void CounterUpdate2(void); -void CounterUpdate3(void); -void CounterUpdate4(void); -bool CounterPinState(void); -void CounterInit(void); -void CounterEverySecond(void); -void CounterSaveState(void); -void CounterShow(bool json); -void CmndCounter(void); -void CmndCounterType(void); -void CmndCounterDebounce(void); -void CmndCounterDebounceLow(void); -void CmndCounterDebounceHigh(void); -bool Xsns01(uint8_t function); -void AdcInit(void); -uint16_t AdcRead(uint8_t factor); -void AdcEvery250ms(void); -uint16_t AdcGetLux(void); -uint16_t AdcGetRange(void); -void AdcGetCurrentPower(uint8_t factor); -void AdcEverySecond(void); -void AdcShow(bool json); -void CmndAdc(void); -void CmndAdcs(void); -void CmndAdcParam(void); -bool Xsns02(uint8_t function); -void SonoffScSend(const char *data); -void SonoffScInit(void); -void SonoffScSerialInput(char *rcvstat); -void SonoffScShow(bool json); -bool Xsns04(uint8_t function); -uint8_t OneWireReset(void); -void OneWireWriteBit(uint8_t v); -uint8_t OneWire1ReadBit(void); -uint8_t OneWire2ReadBit(void); -void OneWireWrite(uint8_t v); -uint8_t OneWireRead(void); -void OneWireSelect(const uint8_t rom[8]); -void OneWireResetSearch(void); -uint8_t OneWireSearch(uint8_t *newAddr); -bool OneWireCrc8(uint8_t *addr); -void Ds18x20Init(void); -void Ds18x20Convert(void); -bool Ds18x20Read(uint8_t sensor); -void Ds18x20Name(uint8_t sensor); -void Ds18x20EverySecond(void); -void Ds18x20Show(bool json); -bool Xsns05(uint8_t function); -bool DhtWaitState(uint32_t sensor, uint32_t level); -bool DhtRead(uint32_t sensor); -bool DhtPinState(); -void DhtInit(void); -void DhtEverySecond(void); -void DhtShow(bool json); -bool Xsns06(uint8_t function); -bool ShtReset(void); -bool ShtSendCommand(const uint8_t cmd); -bool ShtAwaitResult(void); -int ShtReadData(void); -bool ShtRead(void); -void ShtDetect(void); -void ShtEverySecond(void); -void ShtShow(bool json); -bool Xsns07(uint8_t function); -uint8_t HtuCheckCrc8(uint16_t data); -uint8_t HtuReadDeviceId(void); -void HtuSetResolution(uint8_t resolution); -void HtuReset(void); -void HtuHeater(uint8_t heater); -void HtuInit(void); -bool HtuRead(void); -void HtuDetect(void); -void HtuEverySecond(void); -void HtuShow(bool json); -bool Xsns08(uint8_t function); -bool Bmp180Calibration(uint8_t bmp_idx); -void Bmp180Read(uint8_t bmp_idx); -bool Bmx280Calibrate(uint8_t bmp_idx); -void Bme280Read(uint8_t bmp_idx); -static void BmeDelayMs(uint32_t ms); -bool Bme680Init(uint8_t bmp_idx); -void Bme680Read(uint8_t bmp_idx); -void BmpDetect(void); -void BmpRead(void); -void BmpShow(bool json); -void BMP_EnterSleep(void); -bool Xsns09(uint8_t function); -bool Bh1750SetResolution(void); -bool Bh1750SetMTreg(void); -bool Bh1750Read(void); -void Bh1750Detect(void); -void Bh1750EverySecond(void); -bool Bh1750CommandSensor(void); -void Bh1750Show(bool json); -bool Xsns10(uint8_t function); -void Veml6070Detect(void); -void Veml6070UvTableInit(void); -void Veml6070EverySecond(void); -void Veml6070ModeCmd(bool mode_cmd); -uint16_t Veml6070ReadUv(void); -double Veml6070UvRiskLevel(uint16_t uv_level); -double Veml6070UvPower(double uvrisk); -void Veml6070Show(bool json); -bool Xsns11(uint8_t function); -void Ads1115StartComparator(uint8_t channel, uint16_t mode); -int16_t Ads1115GetConversion(uint8_t channel); -void Ads1115Detect(void); -void Ads1115Show(bool json); -bool Xsns12(uint8_t function); -bool Ina219SetCalibration(uint8_t mode, uint16_t addr); -float Ina219GetShuntVoltage_mV(uint16_t addr); -float Ina219GetBusVoltage_V(uint16_t addr); -bool Ina219Read(void); -bool Ina219CommandSensor(void); -void Ina219Detect(void); -void Ina219EverySecond(void); -void Ina219Show(bool json); -bool Xsns13(uint8_t function); -bool Sht3xRead(float &t, float &h, uint8_t sht3x_address); -void Sht3xDetect(void); -void Sht3xShow(bool json); -bool Xsns14(uint8_t function); -uint8_t MhzCalculateChecksum(uint8_t *array); -size_t MhzSendCmd(uint8_t command_id); -bool MhzCheckAndApplyFilter(uint16_t ppm, uint8_t s); -void MhzEverySecond(void); -bool MhzCommandSensor(void); -void MhzInit(void); -void MhzShow(bool json); -bool Xsns15(uint8_t function); -bool Tsl2561Read(void); -void Tsl2561Detect(void); -void Tsl2561EverySecond(void); -void Tsl2561Show(bool json); -bool Xsns16(uint8_t function); -void Senseair250ms(void); -void SenseairInit(void); -void SenseairShow(bool json); -bool Xsns17(uint8_t function); -size_t PmsSendCmd(uint8_t command_id); -bool PmsReadData(void); -bool PmsCommandSensor(void); -void PmsSecond(void); -void PmsInit(void); -void PmsShow(bool json); -bool Xsns18(uint8_t function); -void MGSInit(void); -void MGSPrepare(void); -char* measure_gas(int gas_type, char* buffer); -void MGSShow(bool json); -bool Xsns19(uint8_t function); -bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensorid, uint8_t *buffer); -void NovaSdsSetWorkPeriod(void); -bool NovaSdsReadData(void); -void NovaSdsSecond(void); -bool NovaSdsCommandSensor(void); -void NovaSdsInit(void); -void NovaSdsShow(bool json); -bool Xsns20(uint8_t function); -void sgp30_Init(void); -float sgp30_AbsoluteHumidity(float temperature, float humidity,char tempUnit); -void Sgp30Update(void); -void Sgp30Show(bool json); -bool Xsns21(uint8_t function); -uint8_t Sr04TModeDetect(void); -uint16_t Sr04TMiddleValue(uint16_t first, uint16_t second, uint16_t third); -uint16_t Sr04TMode3Distance(); -uint16_t Sr04TMode2Distance(void); -void Sr04TReading(void); -void Sr04Show(bool json); -bool Xsns22(uint8_t function); -uint8_t Si1145ReadByte(uint8_t reg); -uint16_t Si1145ReadHalfWord(uint8_t reg); -bool Si1145WriteByte(uint8_t reg, uint16_t val); -uint8_t Si1145WriteParamData(uint8_t p, uint8_t v); -bool Si1145Present(void); -void Si1145Reset(void); -void Si1145DeInit(void); -bool Si1145Begin(void); -uint16_t Si1145ReadUV(void); -uint16_t Si1145ReadVisible(void); -uint16_t Si1145ReadIR(void); -bool Si1145Read(void); -void Si1145Detect(void); -void Si1145Update(void); -void Si1145Show(bool json); -bool Xsns24(uint8_t function); -void LM75ADDetect(void); -float LM75ADGetTemp(void); -void LM75ADShow(bool json); -bool Xsns26(uint8_t function); -int8_t wireReadDataBlock( uint8_t reg, - uint8_t *val, - uint16_t len); -void calculateColorTemperature(void); -bool APDS9960_init(void); -uint8_t getMode(void); -void setMode(uint8_t mode, uint8_t enable); -void enableLightSensor(void); -void disableLightSensor(void); -void enableProximitySensor(void); -void disableProximitySensor(void); -void enableGestureSensor(void); -void disableGestureSensor(void); -bool isGestureAvailable(void); -int16_t readGesture(void); -void enablePower(void); -void disablePower(void); -void readAllColorAndProximityData(void); -void resetGestureParameters(void); -bool processGestureData(void); -bool decodeGesture(void); -void handleGesture(void); -void APDS9960_adjustATime(void); -void APDS9960_loop(void); -void APDS9960_detect(void); -void APDS9960_show(bool json); -bool APDS9960CommandSensor(void); -bool Xsns27(uint8_t function); -void Tm16XXSend(uint8_t data); -void Tm16XXSendCommand(uint8_t cmd); -void TM16XXSendData(uint8_t address, uint8_t data); -uint8_t Tm16XXReceive(void); -void Tm16XXClearDisplay(void); -void Tm1638SetLED(uint8_t color, uint8_t pos); -void Tm1638SetLEDs(word leds); -uint8_t Tm1638GetButtons(void); -void TmInit(void); -void TmLoop(void); -bool Xsns28(uint8_t function); -void MCP230xx_CheckForIntCounter(void); -void MCP230xx_CheckForIntRetainer(void); -const char* IntModeTxt(uint8_t intmo); -uint8_t MCP230xx_readGPIO(uint8_t port); -void MCP230xx_ApplySettings(void); -void MCP230xx_Detect(void); -void MCP230xx_CheckForInterrupt(void); -void MCP230xx_Show(bool json); -void MCP230xx_SetOutPin(uint8_t pin,uint8_t pinstate); -void MCP230xx_Reset(uint8_t pinmode); -bool MCP230xx_Command(void); -void MCP230xx_UpdateWebData(void); -void MCP230xx_OutputTelemetry(void); -void MCP230xx_Interrupt_Counter_Report(void); -void MCP230xx_Interrupt_Retain_Report(void); -bool Xsns29(uint8_t function); -void Mpr121Init(struct mpr121 *pS, bool initial); -void Mpr121Show(struct mpr121 *pS, uint8_t function); -bool Xsns30(uint8_t function); -void CCS811Detect(void); -void CCS811Update(void); -void CCS811Show(bool json); -bool Xsns31(uint8_t function); -void MPU_6050PerformReading(void); -void MPU_6050Detect(void); -void MPU_6050Show(bool json); -bool Xsns32(uint8_t function); -void DS3231Detect(void); -uint8_t bcd2dec(uint8_t n); -uint8_t dec2bcd(uint8_t n); -uint32_t ReadFromDS3231(void); -void SetDS3231Time (uint32_t epoch_time); -void DS3231EverySecond(void); -bool Xsns33(uint8_t function); -bool HxIsReady(uint16_t timeout); -long HxRead(void); -void HxResetPart(void); -void HxReset(void); -void HxCalibrationStateTextJson(uint8_t msg_id); -void SetWeightDelta(); -bool HxCommand(void); -long HxWeight(void); -void HxInit(void); -void HxEvery100mSecond(void); -void HxSaveBeforeRestart(void); -void HxShow(bool json); -void HandleHxAction(void); -void HxSaveSettings(void); -void HxLogUpdates(void); -bool Xsns34(uint8_t function); -void TX2xStartRead(void); -bool Tx2xAvailable(void); -float atan2f(float a, float b); -void Tx2xCheckSampleCount(void); -void Tx2xResetStat(void); -void Tx2xResetStatData(void); -void Tx2xRead(void); -void Tx2xInit(void); -int32_t Tx2xNormalize(int32_t value); -void Tx2xShow(bool json); -bool Xsns35(uint8_t function); -void MGC3130_handleSensorData(); -void MGC3130_sendMessage(uint8_t data[], uint8_t length); -void MGC3130_handleGesture(); -bool MGC3130_handleTouch(); -void MGC3130_handleAirWheel(); -void MGC3130_handleSystemStatus(); -bool MGC3130_receiveMessage(); -bool MGC3130_readData(); -void MGC3130_nextMode(); -void MGC3130_loop(); -void MGC3130_detect(void); -void MGC3130_show(bool json); -bool MGC3130CommandSensor(); -bool Xsns36(uint8_t function); -bool RfSnsFetchSignal(uint8_t DataPin, bool StateSignal); -void RfSnsInitTheoV2(void); -void RfSnsAnalyzeTheov2(void); -void RfSnsTheoV2Show(bool json); -void RfSnsInitAlectoV2(void); -void RfSnsAnalyzeAlectov2(); -void RfSnsAlectoResetRain(void); -uint8_t RfSnsAlectoCRC8(uint8_t *addr, uint8_t len); -void RfSnsAlectoV2Show(bool json); -void RfSnsInit(void); -void RfSnsAnalyzeRawSignal(void); -void RfSnsEverySecond(void); -void RfSnsShow(bool json); -bool Xsns37(uint8_t function); -void AzEverySecond(void); -void AzInit(void); -void AzShow(bool json); -bool Xsns38(uint8_t function); -void MAX31855_Init(void); -void MAX31855_GetResult(void); -float MAX31855_GetProbeTemperature(int32_t RawData); -float MAX31855_GetReferenceTemperature(int32_t RawData); -int32_t MAX31855_ShiftIn(uint8_t Length); -void MAX31855_Show(bool Json); -bool Xsns39(uint8_t function); -void PN532_Init(void); -int8_t PN532_receive(uint8_t *buf, int len, uint16_t timeout); -int8_t PN532_readAckFrame(void); -uint32_t PN532_getFirmwareVersion(void); -void PN532_wakeup(void); -bool PN532_setPassiveActivationRetries(uint8_t maxRetries); -bool PN532_SAMConfig(void); -uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData); -uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data); -uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data); -void PN532_ScanForTag(void); -bool PN532_Command(void); -bool Xsns40(uint8_t function); -bool Max4409Read_lum(void); -void Max4409Detect(void); -void Max4409EverySecond(void); -void Max4409Show(bool json); -bool Xsns41(uint8_t function); -void Scd30Detect(void); -void Scd30Update(void); -int Scd30GetCommand(int command_code, uint16_t *pvalue); -int Scd30SetCommand(int command_code, uint16_t value); -bool Scd30CommandSensor(); -void Scd30Show(bool json); -bool Xsns42(byte function); -int hreReadBit(); -char hreReadChar(int &parity_errors); -void hreInit(void); -void hreEvery50ms(void); -void hreShow(boolean json); -bool Xsns43(byte function); -uint8_t sps30_calc_CRC(uint8_t *data); -void sps30_get_data(uint16_t cmd, uint8_t *data, uint8_t dlen); -void sps30_cmd(uint16_t cmd); -void SPS30_Detect(void); -void SPS30_Every_Second(); -void SPS30_Show(bool json); -bool SPS30_cmd(void); -bool Xsns44(byte function); -void Vl53l0Detect(void); -void Vl53l0Every_250MSecond(void); -void Vl53l0Show(boolean json); -bool Xsns45(byte function); -void MLX90614_Init(void); -void MLX90614_Every_Second(void); -void MLX90614_Show(uint8_t json); -bool Xsns46(byte function); -void MAX31865_Init(void); -void MAX31865_GetResult(void); -void MAX31865_Show(bool Json); -bool Xsns47(uint8_t function); -void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg); -uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr); -void ChirpReset(uint8_t addr); -void ChirpResetAll(void); -void ChirpClockSet(); -void ChirpSleep(uint8_t addr); -void ChirpSelect(uint8_t sensor); -uint8_t ChirpReadVersion(uint8_t addr); -bool ChirpSet(uint8_t addr); -bool ChirpScan(); -void ChirpDetect(void); -void ChirpServiceAllSensors(uint8_t job); -void ChirpEvery100MSecond(void); -void ChirpShow(bool json); -bool ChirpCmd(void); -bool Xsns48(uint8_t function); -void PAJ7620SelectBank(uint8_t bank); -void PAJ7620DecodeGesture(void); -void PAJ7620ReadGesture(void); -void PAJ7620Detect(void); -void PAJ7620Init(void); -void PAJ7620Loop(void); -void PAJ7620Show(bool json); -bool PAJ7620CommandSensor(void); -bool Xsns50(uint8_t function); -void RDM6300_Init(); -void RDM6300_ScanForTag(); -uint8_t rm6300_hexnibble(char chr); -void rm6300_hstring_to_array(uint8_t array[], uint8_t len, char buffer[]); -void RDM6300_Show(void); -bool Xsns51(byte function); -void IBEACON_Init(); -void hm17_every_second(void); -void hm17_sbclr(void); -void hm17_sendcmd(uint8_t cmd); -uint32_t ibeacon_add(struct IBEACON *ib); -void hm17_decode(void); -void IBEACON_loop(); -void IBEACON_Show(void); -bool xsns52_cmd(void); -bool ibeacon_cmd(void); -void ib_sendbeep(void); -void ibeacon_mqtt(const char *mac,const char *rssi); -bool Xsns52(byte function); -double sml_median_array(double *array,uint8_t len); -double sml_median(struct SML_MEDIAN_FILTER* mf, double in); -void ADS1115_init(void); -bool Serial_available(); -uint8_t Serial_read(); -uint8_t Serial_peek(); -void Dump2log(void); -double sml_getvalue(unsigned char *cp,uint8_t index); -uint8_t hexnibble(char chr); -double CharToDouble(const char *str); -void ebus_esc(uint8_t *ebus_buffer, unsigned char len); -uint8_t ebus_crc8(uint8_t data, uint8_t crc_init); -uint8_t ebus_CalculateCRC( uint8_t *Data, uint16_t DataLen ); -void sml_empty_receiver(uint32_t meters); -void sml_shift_in(uint32_t meters,uint32_t shard); -void SML_Poll(void); -void SML_Decode(uint8_t index); -void SML_Immediate_MQTT(const char *mp,uint8_t index,uint8_t mindex); -void SML_Show(boolean json); -void SML_CounterUpd(uint8_t index); -void SML_CounterUpd1(void); -void SML_CounterUpd2(void); -void SML_CounterUpd3(void); -void SML_CounterUpd4(void); -bool Gpio_used(uint8_t gpiopin); -void SML_Init(void); -uint32_t SML_SetBaud(uint32_t meter, uint32_t br); -uint32_t SML_Status(uint32_t meter); -uint32_t SML_Write(uint32_t meter,char *hstr); -void SetDBGLed(uint8_t srcpin, uint8_t ledpin); -void SML_Counter_Poll(void); -void SML_Check_Send(void); -uint8_t sml_hexnibble(char chr); -void SML_Send_Seq(uint32_t meter,char *seq); -uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num); -uint8_t SML_PzemCrc(uint8_t *data, uint8_t len); -uint8_t CalcEvenParity(uint8_t data); -bool XSNS_53_cmd(void); -void InjektCounterValue(uint8_t meter,uint32_t counter); -void SML_CounterSaveState(void); -bool Xsns53(byte function); -static uint32_t _expand_r_shunt(uint16_t compact_r_shunt); -void Ina226SetCalibration(uint8_t slaveIndex); -bool Ina226TestPresence(uint8_t device); -void Ina226ResetActive(void); -void Ina226Init(); -float Ina226ReadBus_v(uint8_t device); -float Ina226ReadShunt_i(uint8_t device); -float Ina226ReadPower_w(uint8_t device); -void Ina226Read(uint8_t device); -void Ina226EverySecond(); -bool Ina226CommandSensor(); -void Ina226Show(bool json); -bool Xsns54(byte callback_id); -bool Hih6Read(void); -void Hih6Detect(void); -void Hih6EverySecond(void); -void Hih6Show(bool json); -bool Xsns55(uint8_t function); -void HpmaSecond(void); -void HpmaInit(void); -void HpmaShow(bool json); -bool Xsns56(uint8_t function); -void Tsl2591Init(void); -bool Tsl2591Read(void); -void Tsl2591EverySecond(void); -void Tsl2591Show(bool json); -bool Xsns57(uint8_t function); -bool Dht12Read(void); -void Dht12Detect(void); -void Dht12EverySecond(void); -void Dht12Show(bool json); -bool Xsns58(uint8_t function); -uint32_t DS1624_Idx2Addr(uint32_t idx); -int DS1624_Restart(uint8_t config, uint32_t idx); -void DS1624_HotPlugUp(uint32_t idx); -void DS1624_HotPlugDown(int idx); -bool DS1624GetTemp(float *value, int idx); -void DS1624HotPlugScan(void); -void DS1624EverySecond(void); -void DS1624Show(bool json); -bool Xsns59(uint8_t function); -void UBXcalcChecksum(char* CK, size_t msgSize); -bool UBXcompareMsgHeader(const char* msgHeader); -void UBXinitCFG(void); -void UBXsendCFGLine(uint8_t _line); -void UBXTriggerTele(void); -void UBXDetect(void); -uint32_t UBXprocessGPS(); -void UBXsendHeader(void); -void UBXsendRecord(uint8_t *buf); -void UBXsendFooter(void); -void UBXsendFile(void); -void UBXSetRate(uint16_t interval); -void UBXSelectMode(uint16_t mode); -bool UBXHandlePOSLLH(); -void UBXHandleSTATUS(); -void UBXHandleTIME(); -void UBXHandleOther(void); -void UBXLoop50msec(void); -void UBXLoop(void); -void UBXShow(bool json); -bool UBXCmd(void); -bool Xsns60(uint8_t function); -bool MINRFinitBLE(uint8_t _mode); -void MINRFhopChannel(); -bool MINRFreceivePacket(void); -void MINRFswapbuf(uint8_t *buf, uint8_t len); -void MINRFwhiten(uint8_t *buf, uint8_t len, uint8_t lfsr); -void MINRFhandleScan(void); -void MINRFstartBeacon(uint16_t entry); -void MINRFbeaconCounter(void); -void MINRFcomputeBeaconPDU(void); -void MINRFreverseMAC(uint8_t _mac[]); -void MINRFMACStringToBytes(char* _string, uint8_t _mac[]); -void MINRFcomputefirstUsedPacketMode(void); -void MINRFchangePacketModeTo(uint8_t _mode); -void MINRFpurgeFakeSensors(void); -void MINRFconfirmSensors(void); -void MINRFhandleMiBeaconPacket(void); -void MINRFhandleLYWSD03Packet(void); -void MINRFhandleCGD1Packet(void); -void MINRF_EVERY_50_MSECOND(); -bool NRFCmd(void); -void MINRFShow(bool json); -bool Xsns61(uint8_t function); -void HM10_Launchtask(uint8_t task, uint8_t slot, uint8_t delay); -void HM10_TaskReplaceInSlot(uint8_t task, uint8_t slot); -void HM10_ReverseMAC(uint8_t _mac[]); -void HM10_Reset(void); -void HM10_Discovery_Scan(void); -void HM10_Read_LYWSD03(void); -void HM10_Read_LYWSD02(void); -void HM10_Time_LYWSD02(void); -void HM10_Read_Flora(void); -void HM10_Read_CGD1(void); -void HM10_Read_MJ_HT_V1(void); -void HM10SerialInit(void); -void HM10parseMiBeacon(char * _buf, uint32_t _slot); -void HM10ParseResponse(char *buf, uint16_t bufsize); -void HM10readHT_LY(char *_buf); -void HM10readHT_CGD1(char *_buf); -void HM10readHT_MJ_HT_V1(char *_buf); -void HM10readTLMF(char *_buf); -bool HM10readBat(char *_buf); -bool HM10SerialHandleFeedback(); -void HM10_TaskEvery100ms(); -void HM10StatusInfo(); -void HM10EverySecond(bool restart); -bool HM10Cmd(void); -void HM10Show(bool json); -bool Xsns62(uint8_t function); -bool AHT1XWrite(uint8_t aht1x_idx); -bool AHT1XRead(uint8_t aht1x_idx); -void AHT1XPoll(void); -unsigned char AHT1XReadStatus(uint8_t aht1x_address); -void AHT1XReset(uint8_t aht1x_address); -bool AHT1XInit(uint8_t aht1x_address); -void AHT1XDetect(void); -void AHT1XShow(bool json); -bool Xsns63(uint8_t function); -void HRXLInit(void); -void HRXLEverySecond(void); -void HRXLShow(bool json); -bool Xsns64(uint8_t function); -uint16_t HdcReadDeviceId(void); -uint16_t HdcReadManufacturerId(void); -void HdcConfig(uint16_t config); -void HdcReset(void); -int8_t HdcTransactionOpen(uint8_t addr, uint8_t reg); -int8_t HdcTransactionClose(uint8_t addr, uint8_t *reg_data, uint16_t len); -void HdcInit(void); -bool HdcTriggerRead(void); -bool HdcRead(void); -void HdcDetect(void); -void HdcEverySecond(void); -void HdcShow(bool json); -bool Xsns65(uint8_t function); -void IAQ_Init(void); -void IAQ_Read(void); -void IAQ_Show(uint8_t json); -bool Xsns66(byte function); -void ICACHE_RAM_ATTR AS3935Isr(); -uint8_t AS3935ReadRegister(uint8_t reg, uint8_t mask, uint8_t shift); -void AS3935WriteRegister(uint8_t reg, uint8_t mask, uint8_t shift, uint8_t data); -void ICACHE_RAM_ATTR AS3935CountFreq(); -bool AS3935AutoTuneCaps(uint8_t irqpin); -void AS3935CalibrateRCO(); -uint8_t AS3935TransMinLights(uint8_t min_lights); -uint8_t AS3935TranslMinLightsInt(uint8_t min_lights); -uint8_t AS3935TranslIrq(uint8_t irq, uint8_t distance); -void AS3935CalcVrmsLevel(uint16_t &vrms, uint8_t &stage); -uint8_t AS3935GetIRQ(); -uint8_t AS3935GetDistance(); -int16_t AS3935CalcDistance(); -uint32_t AS3935GetIntensity(); -uint8_t AS3935GetTuneCaps(); -void AS3935SetTuneCaps(uint8_t tune); -uint8_t AS3935GetDisturber(); -uint8_t AS3935SetDisturber(uint8_t stat); -uint8_t AS3935GetMinLights(); -uint8_t AS3935SetMinLights(uint8_t stat); -uint8_t AS3935GetNoiseFloor(); -uint8_t AS3935SetNoiseFloor(uint8_t noise); -uint8_t AS3935GetGain(); -uint8_t AS3935SetGain(uint8_t room); -uint8_t AS3935GetGainInt(); -uint8_t AS3935GetSpikeRejection(); -void AS3935SetSpikeRejection(uint8_t rej); -uint8_t AS3935GetWdth(); -void AS3935SetWdth(uint8_t wdth); -bool AS3935AutoTune(); -bool AS3935LowerNoiseFloor(); -bool AS3935RaiseNoiseFloor(); -bool AS3935SetDefault(); -void AS3935InitSettings(); -void AS3935Setup(void); -bool AS3935init(); -void AS3935Detect(void); -void AS3935EverySecond(); -bool AS3935Cmd(void); -void AH3935Show(bool json); -bool Xsns67(uint8_t function); -void HandleMetrics(void); -bool Xsns91(uint8_t function); -bool XsnsEnabled(uint32_t sns_index); -void XsnsSensorState(void); -bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index); -bool XsnsCall(uint8_t Function); -bool I2cEnabled(uint32_t i2c_index); -void I2cDriverState(void); -#line 191 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota.ino" -void setup(void) -{ - global_state.data = 3; - -#ifdef ESP32 -#ifdef DISABLE_BROWNOUT - DisableBrownout(); -#endif -#endif - - RtcRebootLoad(); - if (!RtcRebootValid()) { - RtcReboot.fast_reboot_count = 0; - } - RtcReboot.fast_reboot_count++; - RtcRebootSave(); - - Serial.begin(APP_BAUDRATE); - seriallog_level = LOG_LEVEL_INFO; - - snprintf_P(my_version, sizeof(my_version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff); - if (VERSION & 0xff) { - snprintf_P(my_version, sizeof(my_version), PSTR("%s.%d"), my_version, VERSION & 0xff); - } - - snprintf_P(my_image, sizeof(my_image), PSTR("(%s)"), CODE_IMAGE_STR); - - SettingsLoad(); - SettingsDelta(); - - OsWatchInit(); - - GetFeatures(); - - if (1 == RtcReboot.fast_reboot_count) { - UpdateQuickPowerCycle(true); - XdrvCall(FUNC_SETTINGS_OVERRIDE); - } - - - seriallog_level = Settings.seriallog_level; - seriallog_timer = SERIALLOG_TIMER; - syslog_level = Settings.syslog_level; - stop_flash_rotate = Settings.flag.stop_flash_rotate; - save_data_counter = Settings.save_data; - ssleep = Settings.sleep; -#ifndef USE_EMULATION - Settings.flag2.emulation = 0; -#else -#ifndef USE_EMULATION_WEMO - if (EMUL_WEMO == Settings.flag2.emulation) { Settings.flag2.emulation = 0; } -#endif -#ifndef USE_EMULATION_HUE - if (EMUL_HUE == Settings.flag2.emulation) { Settings.flag2.emulation = 0; } -#endif -#endif - - if (Settings.param[P_BOOT_LOOP_OFFSET]) { - - if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET]) { - Settings.flag3.user_esp8285_enable = 0; - if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +1) { - for (uint32_t i = 0; i < MAX_RULE_SETS; i++) { - if (bitRead(Settings.rule_stop, i)) { - bitWrite(Settings.rule_enabled, i, 0); - } - } - } - if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +2) { - Settings.rule_enabled = 0; - } - if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +3) { - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - Settings.my_gp.io[i] = GPIO_NONE; - } - Settings.my_adc0 = ADC0_NONE; - } - if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +4) { -#ifdef ESP8266 - Settings.module = SONOFF_BASIC; - -#endif -#ifdef ESP32 - Settings.module = WEMOS; -#endif - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d)"), RtcReboot.fast_reboot_count); - } - } - - Format(mqtt_client, SettingsText(SET_MQTT_CLIENT), sizeof(mqtt_client)); - Format(mqtt_topic, SettingsText(SET_MQTT_TOPIC), sizeof(mqtt_topic)); - if (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) { - SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); - snprintf_P(my_hostname, sizeof(my_hostname)-1, SettingsText(SET_HOSTNAME), mqtt_topic, ESP_getChipId() & 0x1FFF); - } else { - snprintf_P(my_hostname, sizeof(my_hostname)-1, SettingsText(SET_HOSTNAME)); - } - - GetEspHardwareType(); - GpioInit(); - - - - WifiConnect(); - - SetPowerOnState(); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_CORE_RELEASE), PROJECT, SettingsText(SET_FRIENDLYNAME1), my_version, my_image); -#ifdef FIRMWARE_MINIMAL - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_WARNING_MINIMAL_VERSION)); -#endif - - memcpy_P(log_data, VERSION_MARKER, 1); - - RtcInit(); - -#ifdef USE_ARDUINO_OTA - ArduinoOTAInit(); -#endif - - XdrvCall(FUNC_INIT); - XsnsCall(FUNC_INIT); -} - -void BacklogLoop(void) -{ - if (TimeReached(backlog_delay)) { - if (!BACKLOG_EMPTY && !backlog_mutex) { -#ifdef SUPPORT_IF_STATEMENT - backlog_mutex = true; - String cmd = backlog.shift(); - backlog_mutex = false; - ExecuteCommand((char*)cmd.c_str(), SRC_BACKLOG); -#else - backlog_mutex = true; - ExecuteCommand((char*)backlog[backlog_pointer].c_str(), SRC_BACKLOG); - backlog_pointer++; - if (backlog_pointer >= MAX_BACKLOG) { backlog_pointer = 0; } - backlog_mutex = false; -#endif - } - } -} - -void loop(void) -{ - uint32_t my_sleep = millis(); - - XdrvCall(FUNC_LOOP); - XsnsCall(FUNC_LOOP); - - OsWatchLoop(); - - ButtonLoop(); - SwitchLoop(); -#ifdef ROTARY_V1 - RotaryLoop(); -#endif -#ifdef USE_DEVICE_GROUPS - DeviceGroupsLoop(); -#endif - BacklogLoop(); - - if (TimeReached(state_50msecond)) { - SetNextTimeInterval(state_50msecond, 50); - XdrvCall(FUNC_EVERY_50_MSECOND); - XsnsCall(FUNC_EVERY_50_MSECOND); - } - if (TimeReached(state_100msecond)) { - SetNextTimeInterval(state_100msecond, 100); - Every100mSeconds(); - XdrvCall(FUNC_EVERY_100_MSECOND); - XsnsCall(FUNC_EVERY_100_MSECOND); - } - if (TimeReached(state_250msecond)) { - SetNextTimeInterval(state_250msecond, 250); - Every250mSeconds(); - XdrvCall(FUNC_EVERY_250_MSECOND); - XsnsCall(FUNC_EVERY_250_MSECOND); - } - if (TimeReached(state_second)) { - SetNextTimeInterval(state_second, 1000); - PerformEverySecond(); - XdrvCall(FUNC_EVERY_SECOND); - XsnsCall(FUNC_EVERY_SECOND); - } - - if (!serial_local) { SerialInput(); } - -#ifdef USE_ARDUINO_OTA - ArduinoOtaLoop(); -#endif - - uint32_t my_activity = millis() - my_sleep; - - if (Settings.flag3.sleep_normal) { - - delay(ssleep); - } else { - if (my_activity < (uint32_t)ssleep) { - delay((uint32_t)ssleep - my_activity); - } else { - if (global_state.wifi_down) { - delay(my_activity /2); - } - } - } - - if (!my_activity) { my_activity++; } - uint32_t loop_delay = ssleep; - if (!loop_delay) { loop_delay++; } - uint32_t loops_per_second = 1000 / loop_delay; - uint32_t this_cycle_ratio = 100 * my_activity / loop_delay; - loop_load_avg = loop_load_avg - (loop_load_avg / loops_per_second) + (this_cycle_ratio / loops_per_second); -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/sendemail.ino" -#ifdef USE_SENDMAIL - -#include "sendemail.h" -# 25 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/sendemail.ino" -#ifndef SEND_MAIL_MINRAM -#define SEND_MAIL_MINRAM 12*1024 -#endif - -#define xPSTR(a) a - -uint16_t SendMail(char *buffer) { - char *params,*oparams; - const char *mserv; - uint16_t port; - const char *user; - const char *pstr; - const char *passwd; - const char *from; - const char *to; - const char *subject; - const char *cmd; - char auth=0; - uint16_t status=1; - SendEmail *mail=0; - uint16_t blen; - char *endcmd; - - - - uint16_t mem=ESP.getFreeHeap(); - if (memsend(from,to,subject,cmd); - delete mail; - if (result==true) status=0; - } - -exit: - if (oparams) free(oparams); - return status; -} - -#ifdef ESP8266 -void script_send_email_body(BearSSL::WiFiClientSecure_light *client); -SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) : - host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new BearSSL::WiFiClientSecure_light(1024,1024)) { -} -#else -void script_send_email_body(WiFiClient *client); -SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) : - host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new WiFiClientSecure()) { -} -#endif - -String SendEmail::readClient() { - delay(0); - String r = client->readStringUntil('\n'); - - r.trim(); - while (client->available()) { - delay(0); - r += client->readString(); - } - return r; -} - -bool SendEmail::send(const String& from, const String& to, const String& subject, const char *msg) { -bool status=false; -String buffer; - - if (!host.length()) { - return status; - } - - client->setTimeout(timeout); - -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("Connecting: %s on port %d"),host.c_str(),port); -#endif - - if (!client->connect(host.c_str(), port)) { -#ifdef DEBUG_EMAIL_PORT - AddLog_P(LOG_LEVEL_INFO, PSTR("Connection failed")); -#endif - goto exit; - } - - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("220"))) { - goto exit; - } - - buffer = F("EHLO "); - buffer += client->localIP().toString(); - - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("250"))) { - goto exit; - } - if (user.length()>0 && passwd.length()>0 ) { - - buffer = F("AUTH LOGIN"); - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("334"))) - { - goto exit; - } - base64 b; - buffer = b.encode(user); - - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("334"))) { - goto exit; - } - buffer = b.encode(passwd); - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("235"))) { - goto exit; - } - } - - - buffer = F("MAIL FROM:"); - buffer += from; - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("250"))) { - goto exit; - } - buffer = F("RCPT TO:"); - buffer += to; - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("250"))) { - goto exit; - } - - buffer = F("DATA"); - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = readClient(); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - if (!buffer.startsWith(F("354"))) { - goto exit; - } - buffer = F("From: "); - buffer += from; - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = F("To: "); - buffer += to; - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - buffer = F("Subject: "); - buffer += subject; - buffer += F("\r\n"); - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - -#ifdef USE_SCRIPT - if (*msg=='*' && *(msg+1)==0) { - script_send_email_body(client); - } else { - client->println(msg); - } -#else - client->println(msg); -#endif - client->println('.'); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - - buffer = F("QUIT"); - client->println(buffer); -#ifdef DEBUG_EMAIL_PORT - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str()); -#endif - - status=true; -exit: - - return status; -} - - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" -# 24 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" -const uint16_t RTC_MEM_VALID = 0xA55A; - -uint32_t rtc_settings_crc = 0; - -uint32_t GetRtcSettingsCrc(void) -{ - uint32_t crc = 0; - uint8_t *bytes = (uint8_t*)&RtcSettings; - - for (uint32_t i = 0; i < sizeof(RTCMEM); i++) { - crc += bytes[i]*(i+1); - } - return crc; -} - -void RtcSettingsSave(void) -{ - if (GetRtcSettingsCrc() != rtc_settings_crc) { - RtcSettings.valid = RTC_MEM_VALID; - ESP_rtcUserMemoryWrite(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); - rtc_settings_crc = GetRtcSettingsCrc(); - } -} - -void RtcSettingsLoad(void) -{ - ESP_rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); - if (RtcSettings.valid != RTC_MEM_VALID) { - memset(&RtcSettings, 0, sizeof(RTCMEM)); - RtcSettings.valid = RTC_MEM_VALID; - RtcSettings.energy_kWhtoday = Settings.energy_kWhtoday; - RtcSettings.energy_kWhtotal = Settings.energy_kWhtotal; - RtcSettings.energy_usage = Settings.energy_usage; - for (uint32_t i = 0; i < MAX_COUNTERS; i++) { - RtcSettings.pulse_counter[i] = Settings.pulse_counter[i]; - } - RtcSettings.power = Settings.power; - RtcSettingsSave(); - } - rtc_settings_crc = GetRtcSettingsCrc(); -} - -bool RtcSettingsValid(void) -{ - return (RTC_MEM_VALID == RtcSettings.valid); -} - - - -uint32_t rtc_reboot_crc = 0; - -uint32_t GetRtcRebootCrc(void) -{ - uint32_t crc = 0; - uint8_t *bytes = (uint8_t*)&RtcReboot; - - for (uint32_t i = 0; i < sizeof(RTCRBT); i++) { - crc += bytes[i]*(i+1); - } - return crc; -} - -void RtcRebootSave(void) -{ - if (GetRtcRebootCrc() != rtc_reboot_crc) { - RtcReboot.valid = RTC_MEM_VALID; - ESP_rtcUserMemoryWrite(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT)); - rtc_reboot_crc = GetRtcRebootCrc(); - } -} - -void RtcRebootReset(void) -{ - RtcReboot.fast_reboot_count = 0; - RtcRebootSave(); -} - -void RtcRebootLoad(void) -{ - ESP_rtcUserMemoryRead(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT)); - if (RtcReboot.valid != RTC_MEM_VALID) { - memset(&RtcReboot, 0, sizeof(RTCRBT)); - RtcReboot.valid = RTC_MEM_VALID; - - RtcRebootSave(); - } - rtc_reboot_crc = GetRtcRebootCrc(); -} - -bool RtcRebootValid(void) -{ - return (RTC_MEM_VALID == RtcReboot.valid); -} -# 139 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" -extern "C" { -#include "spi_flash.h" -} -#include "eboot_command.h" - -#ifdef ESP8266 - -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) || defined(ARDUINO_ESP8266_RELEASE_2_5_0) || defined(ARDUINO_ESP8266_RELEASE_2_5_1) || defined(ARDUINO_ESP8266_RELEASE_2_5_2) - -extern "C" uint32_t _SPIFFS_end; - -const uint32_t SPIFFS_END = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE; - -#else - -#if AUTOFLASHSIZE - -#include "flash_hal.h" - - -const uint32_t SPIFFS_END = (FS_end - 0x40200000) / SPI_FLASH_SEC_SIZE; - -#else - -extern "C" uint32_t _FS_end; - -const uint32_t SPIFFS_END = ((uint32_t)&_FS_end - 0x40200000) / SPI_FLASH_SEC_SIZE; - -#endif - -#endif - - -const uint32_t SETTINGS_LOCATION = SPIFFS_END; - -#endif - - -const uint8_t CFG_ROTATES = 8; - -uint32_t settings_location = SETTINGS_LOCATION; -uint32_t settings_crc32 = 0; -uint8_t *settings_buffer = nullptr; - - - - - -void SetFlashModeDout(void) -{ -#ifdef ESP8266 - uint8_t *_buffer; - uint32_t address; - - eboot_command ebcmd; - eboot_command_read(&ebcmd); - address = ebcmd.args[0]; - _buffer = new uint8_t[FLASH_SECTOR_SIZE]; - - if (ESP.flashRead(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE)) { - if (_buffer[2] != 3) { - _buffer[2] = 3; - if (ESP.flashEraseSector(address / FLASH_SECTOR_SIZE)) { - ESP.flashWrite(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); - } - } - } - delete[] _buffer; -#endif -} - -bool VersionCompatible(void) -{ -#ifdef ESP8266 - - if (Settings.flag3.compatibility_check) { - return true; - } - - eboot_command ebcmd; - eboot_command_read(&ebcmd); - uint32_t start_address = ebcmd.args[0]; - uint32_t end_address = start_address + (ebcmd.args[2] & 0xFFFFF000) + FLASH_SECTOR_SIZE; - uint32_t* buffer = new uint32_t[FLASH_SECTOR_SIZE / 4]; - - uint32_t version[3] = { 0 }; - bool found = false; - for (uint32_t address = start_address; address < end_address; address = address + FLASH_SECTOR_SIZE) { - ESP.flashRead(address, (uint32_t*)buffer, FLASH_SECTOR_SIZE); - if ((address == start_address) && (0x1F == (buffer[0] & 0xFF))) { - version[1] = 0xFFFFFFFF; - found = true; - } else { - for (uint32_t i = 0; i < (FLASH_SECTOR_SIZE / 4); i++) { - version[0] = version[1]; - version[1] = version[2]; - version[2] = buffer[i]; - if ((MARKER_START == version[0]) && (MARKER_END == version[2])) { - found = true; - break; - } - } - } - if (found) { break; } - } - delete[] buffer; - - if (!found) { version[1] = 0; } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("OTA: Version 0x%08X, Compatible 0x%08X"), version[1], VERSION_COMPATIBLE); - - if (version[1] < VERSION_COMPATIBLE) { - uint32_t eboot_magic = 0; - ESP.rtcUserMemoryWrite(0, (uint32_t*)&eboot_magic, sizeof(eboot_magic)); - return false; - } - -#endif - - return true; -} - -void SettingsBufferFree(void) -{ - if (settings_buffer != nullptr) { - free(settings_buffer); - settings_buffer = nullptr; - } -} - -bool SettingsBufferAlloc(void) -{ - SettingsBufferFree(); - if (!(settings_buffer = (uint8_t *)malloc(sizeof(Settings)))) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); - return false; - } - return true; -} - -uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size) -{ - uint16_t crc = 0; - - for (uint32_t i = 0; i < size; i++) { - if ((i < 14) || (i > 15)) { crc += bytes[i]*(i+1); } - } - return crc; -} - -uint16_t GetSettingsCrc(void) -{ - - uint32_t size = ((Settings.version < 0x06060007) || (Settings.version > 0x0606000A)) ? 3584 : sizeof(SYSCFG); - return GetCfgCrc16((uint8_t*)&Settings, size); -} - -uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size) -{ - - uint32_t crc = 0; - - while (size--) { - crc ^= *bytes++; - for (uint32_t j = 0; j < 8; j++) { - crc = (crc >> 1) ^ (-int(crc & 1) & 0xEDB88320); - } - } - return ~crc; -} - -uint32_t GetSettingsCrc32(void) -{ - return GetCfgCrc32((uint8_t*)&Settings, sizeof(SYSCFG) -4); -} - -void SettingsSaveAll(void) -{ - if (Settings.flag.save_state) { - Settings.power = power; - } else { - Settings.power = 0; - } - XsnsCall(FUNC_SAVE_BEFORE_RESTART); - XdrvCall(FUNC_SAVE_BEFORE_RESTART); - SettingsSave(0); -} - - - - - -void UpdateQuickPowerCycle(bool update) -{ - if (Settings.flag3.fast_power_cycle_disable) { return; } - - uint32_t pc_register; - uint32_t pc_location = SETTINGS_LOCATION - CFG_ROTATES; - - ESP.flashRead(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register)); - if (update && ((pc_register & 0xFFFFFFF0) == 0xFFA55AB0)) { - uint32_t counter = ((pc_register & 0xF) << 1) & 0xF; - if (0 == counter) { - SettingsErase(3); - EspRestart(); - } else { - pc_register = 0xFFA55AB0 | counter; - ESP.flashWrite(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register)); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("QPC: Flag %02X"), counter); - } - } - else if (pc_register != 0xFFA55ABF) { - pc_register = 0xFFA55ABF; - - if (ESP.flashEraseSector(pc_location)) { - ESP.flashWrite(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register)); - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("QPC: Reset")); - } -} - - - - - -uint32_t GetSettingsTextLen(void) -{ - char* position = Settings.text_pool; - for (uint32_t size = 0; size < SET_MAX; size++) { - while (*position++ != '\0') { } - } - return position - Settings.text_pool; -} - -bool SettingsUpdateText(uint32_t index, const char* replace_me) -{ - if (index >= SET_MAX) { - return false; - } - - - uint32_t replace_len = strlen(replace_me); - char replace[replace_len +1]; - memcpy(replace, replace_me, sizeof(replace)); - - uint32_t start_pos = 0; - uint32_t end_pos = 0; - char* position = Settings.text_pool; - for (uint32_t size = 0; size < SET_MAX; size++) { - while (*position++ != '\0') { } - if (1 == index) { - start_pos = position - Settings.text_pool; - } - else if (0 == index) { - end_pos = position - Settings.text_pool -1; - } - index--; - } - uint32_t char_len = position - Settings.text_pool; - - uint32_t current_len = end_pos - start_pos; - int diff = replace_len - current_len; - - - - - int too_long = (char_len + diff) - settings_text_size; - if (too_long > 0) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_CONFIG "Text overflow by %d char(s)"), too_long); - return false; - } - - if (diff != 0) { - - memmove_P(Settings.text_pool + start_pos + replace_len, Settings.text_pool + end_pos, char_len - end_pos); - } - - memmove_P(Settings.text_pool + start_pos, replace, replace_len); - - memset(Settings.text_pool + char_len + diff, 0x00, settings_text_size - char_len - diff); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "CR %d/%d"), GetSettingsTextLen(), settings_text_size); - - return true; -} - -char* SettingsText(uint32_t index) -{ - char* position = Settings.text_pool; - - if (index >= SET_MAX) { - position += settings_text_size -1; - } else { - for (;index > 0; index--) { - while (*position++ != '\0') { } - } - } - return position; -} - - - - - -void UpdateBackwardCompatibility(void) -{ - - strlcpy(Settings.user_template_name, SettingsText(SET_TEMPLATE_NAME), sizeof(Settings.user_template_name)); -} - -uint32_t GetSettingsAddress(void) -{ - return settings_location * SPI_FLASH_SEC_SIZE; -} - -void SettingsSave(uint8_t rotate) -{ -# 464 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" -#ifndef FIRMWARE_MINIMAL - UpdateBackwardCompatibility(); - if ((GetSettingsCrc32() != settings_crc32) || rotate) { - if (1 == rotate) { - stop_flash_rotate = 1; - } - if (2 == rotate) { - settings_location = SETTINGS_LOCATION +1; - } - if (stop_flash_rotate) { - settings_location = SETTINGS_LOCATION; - } else { - settings_location--; - if (settings_location <= (SETTINGS_LOCATION - CFG_ROTATES)) { - settings_location = SETTINGS_LOCATION; - } - } - - Settings.save_flag++; - if (UtcTime() > START_VALID_TIME) { - Settings.cfg_timestamp = UtcTime(); - } else { - Settings.cfg_timestamp++; - } - Settings.cfg_size = sizeof(SYSCFG); - Settings.cfg_crc = GetSettingsCrc(); - Settings.cfg_crc32 = GetSettingsCrc32(); - -#ifdef ESP8266 - if (ESP.flashEraseSector(settings_location)) { - ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG)); - } - - if (!stop_flash_rotate && rotate) { - for (uint32_t i = 1; i < CFG_ROTATES; i++) { - ESP.flashEraseSector(settings_location -i); - delay(1); - } - } -#else - SettingsSaveMain(&Settings, sizeof(SYSCFG)); -#endif - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), settings_location, Settings.save_flag, sizeof(SYSCFG)); - - settings_crc32 = Settings.cfg_crc32; - } -#endif - RtcSettingsSave(); -} - -void SettingsLoad(void) -{ - - struct SYSCFGH { - uint16_t cfg_holder; - uint16_t cfg_size; - unsigned long save_flag; - } _SettingsH; - unsigned long save_flag = 0; - - settings_location = 0; - uint32_t flash_location = SETTINGS_LOCATION +1; - uint16_t cfg_holder = 0; - for (uint32_t i = 0; i < CFG_ROTATES; i++) { - flash_location--; - ESP_flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG)); - bool valid = false; - if (Settings.version > 0x06000000) { - bool almost_valid = (Settings.cfg_crc32 == GetSettingsCrc32()); - if (Settings.version < 0x0606000B) { - almost_valid = (Settings.cfg_crc == GetSettingsCrc()); - } - - if (almost_valid && (0 == cfg_holder)) { cfg_holder = Settings.cfg_holder; } - valid = (cfg_holder == Settings.cfg_holder); - } else { - ESP_flashReadHeader((flash_location -1) * SPI_FLASH_SEC_SIZE, (uint32*)&_SettingsH, sizeof(SYSCFGH)); - valid = (Settings.cfg_holder == _SettingsH.cfg_holder); - } - if (valid) { - if (Settings.save_flag > save_flag) { - save_flag = Settings.save_flag; - settings_location = flash_location; - if (Settings.flag.stop_flash_rotate && (0 == i)) { - break; - } - } - } - - delay(1); - } - if (settings_location > 0) { - ESP_flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(SYSCFG)); - AddLog_P2(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings.save_flag); - } - -#ifndef FIRMWARE_MINIMAL - if (!settings_location || (Settings.cfg_holder != (uint16_t)CFG_HOLDER)) { - SettingsDefault(); - } - settings_crc32 = GetSettingsCrc32(); -#endif - - RtcSettingsLoad(); -} - -void EspErase(uint32_t start_sector, uint32_t end_sector) -{ - bool serial_output = (LOG_LEVEL_DEBUG_MORE <= seriallog_level); - for (uint32_t sector = start_sector; sector < end_sector; sector++) { - - bool result = ESP.flashEraseSector(sector); - - - - if (serial_output) { -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - Serial.printf(D_LOG_APPLICATION D_ERASED_SECTOR " %d %s\n", sector, (result) ? D_OK : D_ERROR); -#else - Serial.printf_P(PSTR(D_LOG_APPLICATION D_ERASED_SECTOR " %d %s\n"), sector, (result) ? D_OK : D_ERROR); -#endif - delay(10); - } else { - yield(); - } - OsWatchLoop(); - } -} - -#ifdef ESP8266 -void SettingsErase(uint8_t type) -{ -# 613 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" -#ifndef FIRMWARE_MINIMAL - uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1; - uint32_t _sectorEnd = ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE; - if (1 == type) { - - _sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4; - } - else if (2 == type) { - _sectorStart = SETTINGS_LOCATION - CFG_ROTATES; - _sectorEnd = SETTINGS_LOCATION +1; - } - else if (3 == type) { - _sectorStart = SETTINGS_LOCATION - CFG_ROTATES; - _sectorEnd = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; - } - else if (4 == type) { - - _sectorStart = SETTINGS_LOCATION +1; - _sectorEnd = _sectorStart +1; - } - - - - - - - else { - return; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " from 0x%08X to 0x%08X"), _sectorStart * SPI_FLASH_SEC_SIZE, (_sectorEnd * SPI_FLASH_SEC_SIZE) -1); - - - EsptoolErase(_sectorStart, _sectorEnd); -#endif -} -#endif - -void SettingsSdkErase(void) -{ - WiFi.disconnect(false); - SettingsErase(1); - delay(1000); -} - - - -void SettingsDefault(void) -{ - AddLog_P(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_USE_DEFAULTS)); - SettingsDefaultSet1(); - SettingsDefaultSet2(); - SettingsSave(2); -} - -void SettingsDefaultSet1(void) -{ - memset(&Settings, 0x00, sizeof(SYSCFG)); - - Settings.cfg_holder = (uint16_t)CFG_HOLDER; - Settings.cfg_size = sizeof(SYSCFG); - - Settings.version = VERSION; - - -} - -void SettingsDefaultSet2(void) -{ - memset((char*)&Settings +16, 0x00, sizeof(SYSCFG) -16); - - Settings.flag.stop_flash_rotate = APP_FLASH_CYCLE; - Settings.flag.global_state = APP_ENABLE_LEDLINK; - Settings.flag3.sleep_normal = APP_NORMAL_SLEEP; - Settings.flag3.no_power_feedback = APP_NO_RELAY_SCAN; - Settings.flag3.fast_power_cycle_disable = APP_DISABLE_POWERCYCLE; - Settings.flag3.bootcount_update = DEEPSLEEP_BOOTCOUNT; - Settings.flag3.compatibility_check = OTA_COMPATIBILITY; - Settings.save_data = SAVE_DATA; - Settings.param[P_BACKLOG_DELAY] = MIN_BACKLOG_DELAY; - Settings.param[P_BOOT_LOOP_OFFSET] = BOOT_LOOP_OFFSET; - Settings.param[P_RGB_REMAP] = RGB_REMAP_RGBW; - Settings.sleep = APP_SLEEP; - if (Settings.sleep < 50) { - Settings.sleep = 50; - } - - - - Settings.interlock[0] = 0xFF; - Settings.module = MODULE; - ModuleDefault(WEMOS); - - SettingsUpdateText(SET_FRIENDLYNAME1, FRIENDLY_NAME); - SettingsUpdateText(SET_FRIENDLYNAME2, FRIENDLY_NAME"2"); - SettingsUpdateText(SET_FRIENDLYNAME3, FRIENDLY_NAME"3"); - SettingsUpdateText(SET_FRIENDLYNAME4, FRIENDLY_NAME"4"); - SettingsUpdateText(SET_OTAURL, OTA_URL); - - - Settings.flag.save_state = SAVE_STATE; - Settings.power = APP_POWER; - Settings.poweronstate = APP_POWERON_STATE; - Settings.blinktime = APP_BLINKTIME; - Settings.blinkcount = APP_BLINKCOUNT; - Settings.ledstate = APP_LEDSTATE; - Settings.ledmask = APP_LEDMASK; - Settings.pulse_timer[0] = APP_PULSETIME; - - - - Settings.serial_config = TS_SERIAL_8N1; - Settings.baudrate = APP_BAUDRATE / 300; - Settings.sbaudrate = SOFT_BAUDRATE / 300; - Settings.serial_delimiter = 0xff; - Settings.seriallog_level = SERIAL_LOG_LEVEL; - - - Settings.flag3.use_wifi_scan = WIFI_SCAN_AT_RESTART; - Settings.flag3.use_wifi_rescan = WIFI_SCAN_REGULARLY; - Settings.wifi_output_power = 170; - Settings.param[P_ARP_GRATUITOUS] = WIFI_ARP_INTERVAL; - ParseIp(&Settings.ip_address[0], WIFI_IP_ADDRESS); - ParseIp(&Settings.ip_address[1], WIFI_GATEWAY); - ParseIp(&Settings.ip_address[2], WIFI_SUBNETMASK); - ParseIp(&Settings.ip_address[3], WIFI_DNS); - Settings.sta_config = WIFI_CONFIG_TOOL; - - SettingsUpdateText(SET_STASSID1, STA_SSID1); - SettingsUpdateText(SET_STASSID2, STA_SSID2); - SettingsUpdateText(SET_STAPWD1, STA_PASS1); - SettingsUpdateText(SET_STAPWD2, STA_PASS2); - SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); - - - SettingsUpdateText(SET_SYSLOG_HOST, SYS_LOG_HOST); - Settings.syslog_port = SYS_LOG_PORT; - Settings.syslog_level = SYS_LOG_LEVEL; - - - Settings.flag2.emulation = EMULATION; - Settings.flag3.gui_hostname_ip = GUI_SHOW_HOSTNAME; - Settings.flag3.mdns_enabled = MDNS_ENABLED; - Settings.webserver = WEB_SERVER; - Settings.weblog_level = WEB_LOG_LEVEL; - SettingsUpdateText(SET_WEBPWD, WEB_PASSWORD); - SettingsUpdateText(SET_CORS, CORS_DOMAIN); - - - Settings.flag.button_restrict = KEY_DISABLE_MULTIPRESS; - Settings.flag.button_swap = KEY_SWAP_DOUBLE_PRESS; - Settings.flag.button_single = KEY_ONLY_SINGLE_PRESS; - Settings.param[P_HOLD_TIME] = KEY_HOLD_TIME; - - - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { Settings.switchmode[i] = SWITCH_MODE; } - - - Settings.flag.mqtt_enabled = MQTT_USE; - Settings.flag.mqtt_response = MQTT_RESULT_COMMAND; - Settings.flag.mqtt_offline = MQTT_LWT_MESSAGE; - Settings.flag.mqtt_power_retain = MQTT_POWER_RETAIN; - Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN; - Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN; - Settings.flag.mqtt_sensor_retain = MQTT_SENSOR_RETAIN; - - Settings.flag.device_index_enable = MQTT_POWER_FORMAT; - Settings.flag3.time_append_timezone = MQTT_APPEND_TIMEZONE; - Settings.flag3.button_switch_force_local = MQTT_BUTTON_SWITCH_FORCE_LOCAL; - Settings.flag3.no_hold_retain = MQTT_NO_HOLD_RETAIN; - Settings.flag3.use_underscore = MQTT_INDEX_SEPARATOR; - Settings.flag3.grouptopic_mode = MQTT_GROUPTOPIC_FORMAT; - SettingsUpdateText(SET_MQTT_HOST, MQTT_HOST); - Settings.mqtt_port = MQTT_PORT; - SettingsUpdateText(SET_MQTT_CLIENT, MQTT_CLIENT_ID); - SettingsUpdateText(SET_MQTT_USER, MQTT_USER); - SettingsUpdateText(SET_MQTT_PWD, MQTT_PASS); - SettingsUpdateText(SET_MQTT_TOPIC, MQTT_TOPIC); - SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, MQTT_BUTTON_TOPIC); - SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, MQTT_SWITCH_TOPIC); - SettingsUpdateText(SET_MQTT_GRP_TOPIC, MQTT_GRPTOPIC); - SettingsUpdateText(SET_MQTT_FULLTOPIC, MQTT_FULLTOPIC); - Settings.mqtt_retry = MQTT_RETRY_SECS; - SettingsUpdateText(SET_MQTTPREFIX1, SUB_PREFIX); - SettingsUpdateText(SET_MQTTPREFIX2, PUB_PREFIX); - SettingsUpdateText(SET_MQTTPREFIX3, PUB_PREFIX2); - SettingsUpdateText(SET_STATE_TXT1, MQTT_STATUS_OFF); - SettingsUpdateText(SET_STATE_TXT2, MQTT_STATUS_ON); - SettingsUpdateText(SET_STATE_TXT3, MQTT_CMND_TOGGLE); - SettingsUpdateText(SET_STATE_TXT4, MQTT_CMND_HOLD); - char fingerprint[60]; - strlcpy(fingerprint, MQTT_FINGERPRINT1, sizeof(fingerprint)); - char *p = fingerprint; - for (uint32_t i = 0; i < 20; i++) { - Settings.mqtt_fingerprint[0][i] = strtol(p, &p, 16); - } - strlcpy(fingerprint, MQTT_FINGERPRINT2, sizeof(fingerprint)); - p = fingerprint; - for (uint32_t i = 0; i < 20; i++) { - Settings.mqtt_fingerprint[1][i] = strtol(p, &p, 16); - } - Settings.tele_period = TELE_PERIOD; - Settings.mqttlog_level = MQTT_LOG_LEVEL; - - - Settings.flag.no_power_on_check = ENERGY_VOLTAGE_ALWAYS; - Settings.flag2.current_resolution = 3; - - - Settings.flag2.energy_resolution = ENERGY_RESOLUTION; - Settings.flag3.dds2382_model = ENERGY_DDS2382_MODE; - Settings.flag3.hardware_energy_total = ENERGY_HARDWARE_TOTALS; - Settings.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY; - - Settings.energy_power_calibration = HLW_PREF_PULSE; - Settings.energy_voltage_calibration = HLW_UREF_PULSE; - Settings.energy_current_calibration = HLW_IREF_PULSE; -# 840 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" - Settings.energy_max_power_limit_hold = MAX_POWER_HOLD; - Settings.energy_max_power_limit_window = MAX_POWER_WINDOW; - - Settings.energy_max_power_safe_limit_hold = SAFE_POWER_HOLD; - Settings.energy_max_power_safe_limit_window = SAFE_POWER_WINDOW; - - - - RtcSettings.energy_kWhtotal = 0; - - memset((char*)&RtcSettings.energy_usage, 0x00, sizeof(RtcSettings.energy_usage)); - Settings.param[P_OVER_TEMP] = ENERGY_OVERTEMP; - - - Settings.flag.ir_receive_decimal = IR_DATA_RADIX; - Settings.flag3.receive_raw = IR_ADD_RAW_DATA; - Settings.param[P_IR_UNKNOW_THRESHOLD] = IR_RCV_MIN_UNKNOWN_SIZE; - - - Settings.flag.rf_receive_decimal = RF_DATA_RADIX; - - memcpy_P(Settings.rf_code[0], kDefaultRfCode, 9); - - - Settings.domoticz_update_timer = DOMOTICZ_UPDATE_TIMER; -# 875 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" - Settings.flag.temperature_conversion = TEMP_CONVERSION; - Settings.flag.pressure_conversion = PRESSURE_CONVERSION; - Settings.flag2.pressure_resolution = PRESSURE_RESOLUTION; - Settings.flag2.humidity_resolution = HUMIDITY_RESOLUTION; - Settings.flag2.temperature_resolution = TEMP_RESOLUTION; - Settings.flag3.ds18x20_internal_pullup = DS18X20_PULL_UP; - Settings.flag3.counter_reset_on_tele = COUNTER_RESET; - - - - - - - Settings.flag2.calc_resolution = CALC_RESOLUTION; - - - Settings.flag3.timers_enable = TIMERS_ENABLED; - - - Settings.flag.hass_light = HASS_AS_LIGHT; - Settings.flag.hass_discovery = HOME_ASSISTANT_DISCOVERY_ENABLE; - Settings.flag3.hass_tele_on_power = TELE_ON_POWER; - - - Settings.flag.knx_enabled = KNX_ENABLED; - Settings.flag.knx_enable_enhancement = KNX_ENHANCED; - - - Settings.flag.pwm_control = LIGHT_MODE; - Settings.flag.ws_clock_reverse = LIGHT_CLOCK_DIRECTION; - Settings.flag.light_signal = LIGHT_PAIRS_CO2; - Settings.flag.not_power_linked = LIGHT_POWER_CONTROL; - Settings.flag.decimal_text = LIGHT_COLOR_RADIX; - Settings.flag3.pwm_multi_channels = LIGHT_CHANNEL_MODE; - Settings.flag3.slider_dimmer_stay_on = LIGHT_SLIDER_POWER; - Settings.flag4.alexa_ct_range = LIGHT_ALEXA_CT_RANGE; - - Settings.pwm_frequency = PWM_FREQ; - Settings.pwm_range = PWM_RANGE; - for (uint32_t i = 0; i < MAX_PWMS; i++) { - Settings.light_color[i] = DEFAULT_LIGHT_COMPONENT; - - } - Settings.light_correction = 1; - Settings.light_dimmer = DEFAULT_LIGHT_DIMMER; - - Settings.light_speed = 1; - - Settings.light_width = 1; - - Settings.light_pixels = WS2812_LEDS; - - Settings.ws_width[WS_SECOND] = 1; - Settings.ws_color[WS_SECOND][WS_RED] = 255; - - Settings.ws_color[WS_SECOND][WS_BLUE] = 255; - Settings.ws_width[WS_MINUTE] = 3; - - Settings.ws_color[WS_MINUTE][WS_GREEN] = 255; - - Settings.ws_width[WS_HOUR] = 5; - Settings.ws_color[WS_HOUR][WS_RED] = 255; - - - - Settings.dimmer_hw_max = DEFAULT_DIMMER_MAX; - Settings.dimmer_hw_min = DEFAULT_DIMMER_MIN; - - - - Settings.display_mode = 1; - Settings.display_refresh = 2; - Settings.display_rows = 2; - Settings.display_cols[0] = 16; - Settings.display_cols[1] = 8; - Settings.display_dimmer = 1; - Settings.display_size = 1; - Settings.display_font = 1; - - Settings.display_address[0] = MTX_ADDRESS1; - Settings.display_address[1] = MTX_ADDRESS2; - Settings.display_address[2] = MTX_ADDRESS3; - Settings.display_address[3] = MTX_ADDRESS4; - Settings.display_address[4] = MTX_ADDRESS5; - Settings.display_address[5] = MTX_ADDRESS6; - Settings.display_address[6] = MTX_ADDRESS7; - Settings.display_address[7] = MTX_ADDRESS8; - - - if (((APP_TIMEZONE > -14) && (APP_TIMEZONE < 15)) || (99 == APP_TIMEZONE)) { - Settings.timezone = APP_TIMEZONE; - Settings.timezone_minutes = 0; - } else { - Settings.timezone = APP_TIMEZONE / 60; - Settings.timezone_minutes = abs(APP_TIMEZONE % 60); - } - SettingsUpdateText(SET_NTPSERVER1, NTP_SERVER1); - SettingsUpdateText(SET_NTPSERVER2, NTP_SERVER2); - SettingsUpdateText(SET_NTPSERVER3, NTP_SERVER3); - for (uint32_t i = 0; i < MAX_NTP_SERVERS; i++) { - SettingsUpdateText(SET_NTPSERVER1 +i, ReplaceCommaWithDot(SettingsText(SET_NTPSERVER1 +i))); - } - Settings.latitude = (int)((double)LATITUDE * 1000000); - Settings.longitude = (int)((double)LONGITUDE * 1000000); - SettingsResetStd(); - SettingsResetDst(); - - Settings.button_debounce = KEY_DEBOUNCE_TIME; - Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; - - for (uint32_t j = 0; j < 5; j++) { - Settings.rgbwwTable[j] = 255; - } - - Settings.novasds_startingoffset = STARTING_OFFSET; - - SettingsDefaultWebColor(); - - memset(&Settings.monitors, 0xFF, 20); - SettingsEnableAllI2cDrivers(); - - - Settings.flag3.tuya_apply_o20 = TUYA_SETOPTION_20; - Settings.flag3.tuya_serial_mqtt_publish = MQTT_TUYA_RECEIVED; - - Settings.flag3.buzzer_enable = BUZZER_ENABLE; - Settings.flag3.shutter_mode = SHUTTER_SUPPORT; - Settings.flag3.pcf8574_ports_inverted = PCF8574_INVERT_PORTS; - Settings.flag4.zigbee_use_names = ZIGBEE_FRIENDLY_NAMES; -} - - - -void SettingsResetStd(void) -{ - Settings.tflag[0].hemis = TIME_STD_HEMISPHERE; - Settings.tflag[0].week = TIME_STD_WEEK; - Settings.tflag[0].dow = TIME_STD_DAY; - Settings.tflag[0].month = TIME_STD_MONTH; - Settings.tflag[0].hour = TIME_STD_HOUR; - Settings.toffset[0] = TIME_STD_OFFSET; -} - -void SettingsResetDst(void) -{ - Settings.tflag[1].hemis = TIME_DST_HEMISPHERE; - Settings.tflag[1].week = TIME_DST_WEEK; - Settings.tflag[1].dow = TIME_DST_DAY; - Settings.tflag[1].month = TIME_DST_MONTH; - Settings.tflag[1].hour = TIME_DST_HOUR; - Settings.toffset[1] = TIME_DST_OFFSET; -} - -void SettingsDefaultWebColor(void) -{ - char scolor[10]; - for (uint32_t i = 0; i < COL_LAST; i++) { - WebHexCode(i, GetTextIndexed(scolor, sizeof(scolor), i, kWebColors)); - } -} - -void SettingsEnableAllI2cDrivers(void) -{ - Settings.i2c_drivers[0] = 0xFFFFFFFF; - Settings.i2c_drivers[1] = 0xFFFFFFFF; - Settings.i2c_drivers[2] = 0xFFFFFFFF; -} - - - -void SettingsDelta(void) -{ - if (Settings.version != VERSION) { - -#ifdef ESP8266 - if (Settings.version < 0x06000000) { - Settings.cfg_size = sizeof(SYSCFG); - Settings.cfg_crc = GetSettingsCrc(); - } - if (Settings.version < 0x06000002) { - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if (i < 4) { - Settings.switchmode[i] = Settings.interlock[i]; - } else { - Settings.switchmode[i] = SWITCH_MODE; - } - } - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - if (Settings.my_gp.io[i] >= GPIO_SWT5) { - Settings.my_gp.io[i] += 4; - } - } - } - if (Settings.version < 0x06000003) { - Settings.flag.mqtt_serial_raw = 0; - Settings.flag.pressure_conversion = 0; - Settings.flag3.data = 0; - } - if (Settings.version < 0x06010103) { - Settings.flag3.timers_enable = 1; - } - if (Settings.version < 0x0601010C) { - Settings.button_debounce = KEY_DEBOUNCE_TIME; - Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; - } - if (Settings.version < 0x0602010A) { - for (uint32_t j = 0; j < 5; j++) { - Settings.rgbwwTable[j] = 255; - } - } - if (Settings.version < 0x06030002) { - Settings.timezone_minutes = 0; - } - if (Settings.version < 0x06030004) { - memset(&Settings.monitors, 0xFF, 20); - } - if (Settings.version < 0x0603000E) { - Settings.flag2.calc_resolution = CALC_RESOLUTION; - } - if (Settings.version < 0x0603000F) { - if (Settings.sleep < 50) { - Settings.sleep = 50; - } - } - if (Settings.version < 0x06040105) { - Settings.flag3.mdns_enabled = MDNS_ENABLED; - Settings.param[P_MDNS_DELAYED_START] = 0; - } - if (Settings.version < 0x0604010B) { - Settings.interlock[0] = 0xFF; - for (uint32_t i = 1; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } - } - if (Settings.version < 0x0604010D) { - Settings.param[P_BOOT_LOOP_OFFSET] = BOOT_LOOP_OFFSET; - } - if (Settings.version < 0x06040110) { - ModuleDefault(WEMOS); - } - if (Settings.version < 0x06040113) { - Settings.param[P_RGB_REMAP] = RGB_REMAP_RGBW; - } - if (Settings.version < 0x06050003) { - Settings.novasds_startingoffset = STARTING_OFFSET; - } - if (Settings.version < 0x06050006) { - SettingsDefaultWebColor(); - } - if (Settings.version < 0x06050007) { - Settings.ledmask = APP_LEDMASK; - } - if (Settings.version < 0x0605000A) { - Settings.my_adc0 = ADC0_NONE; - } - if (Settings.version < 0x0605000D) { - Settings.param[P_IR_UNKNOW_THRESHOLD] = IR_RCV_MIN_UNKNOWN_SIZE; - } - if (Settings.version < 0x06060001) { - Settings.param[P_OVER_TEMP] = ENERGY_OVERTEMP; - } - if (Settings.version < 0x06060007) { - memset((char*)&Settings +0xE00, 0x00, sizeof(SYSCFG) -0xE00); - } - if (Settings.version < 0x06060008) { - - if (Settings.flag3.tuya_serial_mqtt_publish) { - Settings.param[P_ex_DIMMER_MAX] = 100; - } else { - Settings.param[P_ex_DIMMER_MAX] = 255; - } - } - if (Settings.version < 0x06060009) { - Settings.baudrate = APP_BAUDRATE / 300; - Settings.sbaudrate = SOFT_BAUDRATE / 300; - } - if (Settings.version < 0x0606000A) { - uint8_t tuyaindex = 0; - if (Settings.param[P_BACKLOG_DELAY] > 0) { - Settings.tuya_fnid_map[tuyaindex].fnid = 21; - Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_BACKLOG_DELAY]; - tuyaindex++; - } else if (Settings.flag3.fast_power_cycle_disable == 1) { - Settings.tuya_fnid_map[tuyaindex].fnid = 11; - Settings.tuya_fnid_map[tuyaindex].dpid = 1; - tuyaindex++; - } - if (Settings.param[P_ARP_GRATUITOUS] > 0) { - for (uint8_t i = 0 ; i < Settings.param[P_ARP_GRATUITOUS]; i++) { - Settings.tuya_fnid_map[tuyaindex].fnid = 12 + i; - Settings.tuya_fnid_map[tuyaindex].dpid = i + 2; - tuyaindex++; - } - } - if (Settings.param[P_ex_TUYA_POWER_ID] > 0) { - Settings.tuya_fnid_map[tuyaindex].fnid = 31; - Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_POWER_ID]; - tuyaindex++; - } - if (Settings.param[P_ex_TUYA_VOLTAGE_ID] > 0) { - Settings.tuya_fnid_map[tuyaindex].fnid = 33; - Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_VOLTAGE_ID]; - tuyaindex++; - } - if (Settings.param[P_ex_TUYA_CURRENT_ID] > 0) { - Settings.tuya_fnid_map[tuyaindex].fnid = 32; - Settings.tuya_fnid_map[tuyaindex].dpid = Settings.param[P_ex_TUYA_CURRENT_ID]; - } - } - if (Settings.version < 0x0606000C) { - memset((char*)&Settings +0x1D6, 0x00, 16); - } - if (Settings.version < 0x0606000F) { - Settings.ex_shutter_accuracy = 0; - Settings.ex_mqttlog_level = MQTT_LOG_LEVEL; - } - if (Settings.version < 0x06060011) { - Settings.param[P_BACKLOG_DELAY] = MIN_BACKLOG_DELAY; - } - if (Settings.version < 0x06060012) { - Settings.dimmer_hw_min = DEFAULT_DIMMER_MIN; - Settings.dimmer_hw_max = DEFAULT_DIMMER_MAX; - if (TUYA_DIMMER == Settings.module) { - if (Settings.flag3.ex_tuya_dimmer_min_limit) { - Settings.dimmer_hw_min = 25; - } else { - Settings.dimmer_hw_min = 1; - } - Settings.dimmer_hw_max = Settings.param[P_ex_DIMMER_MAX]; - } - else if (PS_16_DZ == Settings.module) { - Settings.dimmer_hw_min = 10; - Settings.dimmer_hw_max = Settings.param[P_ex_DIMMER_MAX]; - } - } - if (Settings.version < 0x06060014) { -# 1221 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/settings.ino" - Settings.flag3.fast_power_cycle_disable = 0; - Settings.energy_power_delta = Settings.ex_energy_power_delta; - Settings.ex_energy_power_delta = 0; - } - if (Settings.version < 0x06060015) { - if ((EX_WIFI_SMARTCONFIG == Settings.ex_sta_config) || (EX_WIFI_WPSCONFIG == Settings.ex_sta_config)) { - Settings.ex_sta_config = WIFI_MANAGER; - } - } - - if (Settings.version < 0x07000002) { - Settings.web_color2[0][0] = Settings.web_color[0][0]; - Settings.web_color2[0][1] = Settings.web_color[0][1]; - Settings.web_color2[0][2] = Settings.web_color[0][2]; - } - if (Settings.version < 0x07000003) { - SettingsEnableAllI2cDrivers(); - } - if (Settings.version < 0x07000004) { - Settings.ex_wifi_output_power = 170; - } - if (Settings.version < 0x07010202) { - Settings.ex_serial_config = TS_SERIAL_8N1; - } - if (Settings.version < 0x07010204) { - if (Settings.flag3.mqtt_buttons == 1) { - strlcpy(Settings.ex_cors_domain, CORS_ENABLED_ALL, sizeof(Settings.ex_cors_domain)); - } else { - Settings.ex_cors_domain[0] = 0; - } - } - if (Settings.version < 0x07010205) { - Settings.seriallog_level = Settings.ex_seriallog_level; - Settings.sta_config = Settings.ex_sta_config; - Settings.sta_active = Settings.ex_sta_active; - memcpy((char*)&Settings.rule_stop, (char*)&Settings.ex_rule_stop, 47); - } - if (Settings.version < 0x07010206) { - Settings.flag4 = Settings.ex_flag4; - Settings.mqtt_port = Settings.ex_mqtt_port; - memcpy((char*)&Settings.serial_config, (char*)&Settings.ex_serial_config, 5); - } - if (Settings.version < 0x08000000) { - char temp[strlen(Settings.text_pool) +1]; strncpy(temp, Settings.text_pool, sizeof(temp)); - char temp21[strlen(Settings.ex_mqtt_prefix[0]) +1]; strncpy(temp21, Settings.ex_mqtt_prefix[0], sizeof(temp21)); - char temp22[strlen(Settings.ex_mqtt_prefix[1]) +1]; strncpy(temp22, Settings.ex_mqtt_prefix[1], sizeof(temp22)); - char temp23[strlen(Settings.ex_mqtt_prefix[2]) +1]; strncpy(temp23, Settings.ex_mqtt_prefix[2], sizeof(temp23)); - char temp31[strlen(Settings.ex_sta_ssid[0]) +1]; strncpy(temp31, Settings.ex_sta_ssid[0], sizeof(temp31)); - char temp32[strlen(Settings.ex_sta_ssid[1]) +1]; strncpy(temp32, Settings.ex_sta_ssid[1], sizeof(temp32)); - char temp41[strlen(Settings.ex_sta_pwd[0]) +1]; strncpy(temp41, Settings.ex_sta_pwd[0], sizeof(temp41)); - char temp42[strlen(Settings.ex_sta_pwd[1]) +1]; strncpy(temp42, Settings.ex_sta_pwd[1], sizeof(temp42)); - char temp5[strlen(Settings.ex_hostname) +1]; strncpy(temp5, Settings.ex_hostname, sizeof(temp5)); - char temp6[strlen(Settings.ex_syslog_host) +1]; strncpy(temp6, Settings.ex_syslog_host, sizeof(temp6)); - char temp7[strlen(Settings.ex_mqtt_host) +1]; strncpy(temp7, Settings.ex_mqtt_host, sizeof(temp7)); - char temp8[strlen(Settings.ex_mqtt_client) +1]; strncpy(temp8, Settings.ex_mqtt_client, sizeof(temp8)); - char temp9[strlen(Settings.ex_mqtt_user) +1]; strncpy(temp9, Settings.ex_mqtt_user, sizeof(temp9)); - char temp10[strlen(Settings.ex_mqtt_pwd) +1]; strncpy(temp10, Settings.ex_mqtt_pwd, sizeof(temp10)); - char temp11[strlen(Settings.ex_mqtt_topic) +1]; strncpy(temp11, Settings.ex_mqtt_topic, sizeof(temp11)); - char temp12[strlen(Settings.ex_button_topic) +1]; strncpy(temp12, Settings.ex_button_topic, sizeof(temp12)); - char temp13[strlen(Settings.ex_mqtt_grptopic) +1]; strncpy(temp13, Settings.ex_mqtt_grptopic, sizeof(temp13)); - - memset(Settings.text_pool, 0x00, settings_text_size); - SettingsUpdateText(SET_OTAURL, temp); - SettingsUpdateText(SET_MQTTPREFIX1, temp21); - SettingsUpdateText(SET_MQTTPREFIX2, temp22); - SettingsUpdateText(SET_MQTTPREFIX3, temp23); - SettingsUpdateText(SET_STASSID1, temp31); - SettingsUpdateText(SET_STASSID2, temp32); - SettingsUpdateText(SET_STAPWD1, temp41); - SettingsUpdateText(SET_STAPWD2, temp42); - SettingsUpdateText(SET_HOSTNAME, temp5); - SettingsUpdateText(SET_SYSLOG_HOST, temp6); -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - if (!strlen(Settings.ex_mqtt_user)) { - SettingsUpdateText(SET_MQTT_HOST, temp7); - SettingsUpdateText(SET_MQTT_USER, temp9); - } else { - char aws_mqtt_host[66]; - snprintf_P(aws_mqtt_host, sizeof(aws_mqtt_host), PSTR("%s%s"), temp9, temp7); - SettingsUpdateText(SET_MQTT_HOST, aws_mqtt_host); - SettingsUpdateText(SET_MQTT_USER, ""); - } -#else - SettingsUpdateText(SET_MQTT_HOST, temp7); - SettingsUpdateText(SET_MQTT_USER, temp9); -#endif - SettingsUpdateText(SET_MQTT_CLIENT, temp8); - SettingsUpdateText(SET_MQTT_PWD, temp10); - SettingsUpdateText(SET_MQTT_TOPIC, temp11); - SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, temp12); - SettingsUpdateText(SET_MQTT_GRP_TOPIC, temp13); - - SettingsUpdateText(SET_WEBPWD, Settings.ex_web_password); - SettingsUpdateText(SET_CORS, Settings.ex_cors_domain); - SettingsUpdateText(SET_MQTT_FULLTOPIC, Settings.ex_mqtt_fulltopic); - SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, Settings.ex_switch_topic); - SettingsUpdateText(SET_STATE_TXT1, Settings.ex_state_text[0]); - SettingsUpdateText(SET_STATE_TXT2, Settings.ex_state_text[1]); - SettingsUpdateText(SET_STATE_TXT3, Settings.ex_state_text[2]); - SettingsUpdateText(SET_STATE_TXT4, Settings.ex_state_text[3]); - SettingsUpdateText(SET_NTPSERVER1, Settings.ex_ntp_server[0]); - SettingsUpdateText(SET_NTPSERVER2, Settings.ex_ntp_server[1]); - SettingsUpdateText(SET_NTPSERVER3, Settings.ex_ntp_server[2]); - SettingsUpdateText(SET_MEM1, Settings.script_pram[0]); - SettingsUpdateText(SET_MEM2, Settings.script_pram[1]); - SettingsUpdateText(SET_MEM3, Settings.script_pram[2]); - SettingsUpdateText(SET_MEM4, Settings.script_pram[3]); - SettingsUpdateText(SET_MEM5, Settings.script_pram[4]); - SettingsUpdateText(SET_FRIENDLYNAME1, Settings.ex_friendlyname[0]); - SettingsUpdateText(SET_FRIENDLYNAME2, Settings.ex_friendlyname[1]); - SettingsUpdateText(SET_FRIENDLYNAME3, Settings.ex_friendlyname[2]); - SettingsUpdateText(SET_FRIENDLYNAME4, Settings.ex_friendlyname[3]); - } - if (Settings.version < 0x08020003) { - SettingsUpdateText(SET_TEMPLATE_NAME, Settings.user_template_name); - Settings.zb_channel = 0; - } -#endif - - if (Settings.version < 0x08020004) { -#ifdef ESP8266 - Settings.config_version = 0; -#endif -#ifdef ESP32 - Settings.config_version = 1; -#endif - } - - Settings.version = VERSION; - SettingsSave(1); - } -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support.ino" -IPAddress syslog_host_addr; -uint32_t syslog_host_hash = 0; - -extern "C" { -extern struct rst_info resetInfo; -} - - - - - -#include - -Ticker tickerOSWatch; - -const uint32_t OSWATCH_RESET_TIME = 120; - -static unsigned long oswatch_last_loop_time; -uint8_t oswatch_blocked_loop = 0; - -#ifndef USE_WS2812_DMA - -#endif - -#ifdef USE_KNX -bool knx_started = false; -#endif - -void OsWatchTicker(void) -{ - uint32_t t = millis(); - uint32_t last_run = abs(t - oswatch_last_loop_time); - -#ifdef DEBUG_THEO - int32_t rssi = WiFi.RSSI(); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_OSWATCH " FreeRam %d, rssi %d %% (%d dBm), last_run %d"), ESP.getFreeHeap(), WifiGetRssiAsQuality(rssi), rssi, last_run); -#endif - if (last_run >= (OSWATCH_RESET_TIME * 1000)) { - - RtcSettings.oswatch_blocked_loop = 1; - RtcSettingsSave(); - - - - - - volatile uint32_t dummy; - dummy = *((uint32_t*) 0x00000000); - } -} - -void OsWatchInit(void) -{ - oswatch_blocked_loop = RtcSettings.oswatch_blocked_loop; - RtcSettings.oswatch_blocked_loop = 0; - oswatch_last_loop_time = millis(); - tickerOSWatch.attach_ms(((OSWATCH_RESET_TIME / 3) * 1000), OsWatchTicker); -} - -void OsWatchLoop(void) -{ - oswatch_last_loop_time = millis(); - -} - -bool OsWatchBlockedLoop(void) -{ - return oswatch_blocked_loop; -} - -uint32_t ResetReason(void) -{ -# 102 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support.ino" -#ifdef ESP8266 - return resetInfo.reason; -#else - return ESP_ResetInfoReason(); -#endif -} - -String GetResetReason(void) -{ - if (oswatch_blocked_loop) { - char buff[32]; - strncpy_P(buff, PSTR(D_JSON_BLOCKED_LOOP), sizeof(buff)); - return String(buff); - } else { - return ESP_getResetReason(); - } -} - - - - - - -size_t strchrspn(const char *str1, int character) -{ - size_t ret = 0; - char *start = (char*)str1; - char *end = strchr(str1, character); - if (end) ret = end - start; - return ret; -} - - -char* subStr(char* dest, char* str, const char *delim, int index) -{ - char *act; - char *sub = nullptr; - char *ptr; - int i; - - - strncpy(dest, str, strlen(str)+1); - for (i = 1, act = dest; i <= index; i++, act = nullptr) { - sub = strtok_r(act, delim, &ptr); - if (sub == nullptr) break; - } - sub = Trim(sub); - return sub; -} - -float CharToFloat(const char *str) -{ - - char strbuf[24]; - - strlcpy(strbuf, str, sizeof(strbuf)); - char *pt = strbuf; - while ((*pt != '\0') && isblank(*pt)) { pt++; } - - signed char sign = 1; - if (*pt == '-') { sign = -1; } - if (*pt == '-' || *pt=='+') { pt++; } - - float left = 0; - if (*pt != '.') { - left = atoi(pt); - while (isdigit(*pt)) { pt++; } - } - - float right = 0; - if (*pt == '.') { - pt++; - right = atoi(pt); - while (isdigit(*pt)) { - pt++; - right /= 10.0f; - } - } - - float result = left + right; - if (sign < 0) { - return -result; - } - return result; -} - -int TextToInt(char *str) -{ - char *p; - uint8_t radix = 10; - if ('#' == str[0]) { - radix = 16; - str++; - } - return strtol(str, &p, radix); -} - -char* ulltoa(unsigned long long value, char *str, int radix) -{ - char digits[64]; - char *dst = str; - int i = 0; - - - - do { - int n = value % radix; - digits[i++] = (n < 10) ? (char)n+'0' : (char)n-10+'A'; - value /= radix; - } while (value != 0); - - while (i > 0) { *dst++ = digits[--i]; } - - *dst = 0; - return str; -} - - - -char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, char inbetween) -{ - - - - static const char * hex = "0123456789ABCDEF"; - int between = (inbetween) ? 3 : 2; - const unsigned char * pin = in; - char * pout = out; - for (; pin < in+insz; pout += between, pin++) { - pout[0] = hex[(pgm_read_byte(pin)>>4) & 0xF]; - pout[1] = hex[ pgm_read_byte(pin) & 0xF]; - if (inbetween) { pout[2] = inbetween; } - if (pout + 3 - out > outsz) { break; } - } - pout[(inbetween && insz) ? -1 : 0] = 0; - return out; -} - -char* Uint64toHex(uint64_t value, char *str, uint16_t bits) -{ - ulltoa(value, str, 16); - - int fill = 8; - if ((bits > 3) && (bits < 65)) { - fill = bits / 4; - if (bits % 4) { fill++; } - } - int len = strlen(str); - fill -= len; - if (fill > 0) { - memmove(str + fill, str, len +1); - memset(str, '0', fill); - } - return str; -} - -char* dtostrfd(double number, unsigned char prec, char *s) -{ - if ((isnan(number)) || (isinf(number))) { - strcpy(s, "null"); - return s; - } else { - return dtostrf(number, 1, prec, s); - } -} - -char* Unescape(char* buffer, uint32_t* size) -{ - uint8_t* read = (uint8_t*)buffer; - uint8_t* write = (uint8_t*)buffer; - int32_t start_size = *size; - int32_t end_size = *size; - uint8_t che = 0; - - - - while (start_size > 0) { - uint8_t ch = *read++; - start_size--; - if (ch != '\\') { - *write++ = ch; - } else { - if (start_size > 0) { - uint8_t chi = *read++; - start_size--; - end_size--; - switch (chi) { - case '\\': che = '\\'; break; - case 'a': che = '\a'; break; - case 'b': che = '\b'; break; - case 'e': che = '\e'; break; - case 'f': che = '\f'; break; - case 'n': che = '\n'; break; - case 'r': che = '\r'; break; - case 's': che = ' '; break; - case 't': che = '\t'; break; - case 'v': che = '\v'; break; - case 'x': { - uint8_t* start = read; - che = (uint8_t)strtol((const char*)read, (char**)&read, 16); - start_size -= (uint16_t)(read - start); - end_size -= (uint16_t)(read - start); - break; - } - case '"': che = '\"'; break; - - default : { - che = chi; - *write++ = ch; - end_size++; - } - } - *write++ = che; - } - } - } - *size = end_size; - *write++ = 0; - - - return buffer; -} - -char* RemoveSpace(char* p) -{ - char* write = p; - char* read = p; - char ch = '.'; - - while (ch != '\0') { - ch = *read++; - if (!isspace(ch)) { - *write++ = ch; - } - } - - return p; -} - -char* ReplaceCommaWithDot(char* p) -{ - char* write = (char*)p; - char* read = (char*)p; - char ch = '.'; - - while (ch != '\0') { - ch = *read++; - if (ch == ',') { - ch = '.'; - } - *write++ = ch; - } - return p; -} - -char* LowerCase(char* dest, const char* source) -{ - char* write = dest; - const char* read = source; - char ch = '.'; - - while (ch != '\0') { - ch = *read++; - *write++ = tolower(ch); - } - return dest; -} - -char* UpperCase(char* dest, const char* source) -{ - char* write = dest; - const char* read = source; - char ch = '.'; - - while (ch != '\0') { - ch = *read++; - *write++ = toupper(ch); - } - return dest; -} - -char* UpperCase_P(char* dest, const char* source) -{ - char* write = dest; - const char* read = source; - char ch = '.'; - - while (ch != '\0') { - ch = pgm_read_byte(read++); - *write++ = toupper(ch); - } - return dest; -} - -char* Trim(char* p) -{ - while ((*p != '\0') && isblank(*p)) { p++; } - char* q = p + strlen(p) -1; - while ((q >= p) && isblank(*q)) { q--; } - q++; - *q = '\0'; - return p; -} - -char* RemoveAllSpaces(char* p) -{ - - char *cursor = p; - uint32_t offset = 0; - while (1) { - *cursor = *(cursor + offset); - if ((' ' == *cursor) || ('\t' == *cursor) || ('\n' == *cursor)) { - offset++; - } else { - if (0 == *cursor) { break; } - cursor++; - } - } - return p; -} - -char* NoAlNumToUnderscore(char* dest, const char* source) -{ - char* write = dest; - const char* read = source; - char ch = '.'; - - while (ch != '\0') { - ch = *read++; - *write++ = (isalnum(ch) || ('\0' == ch)) ? ch : '_'; - } - return dest; -} - -char IndexSeparator(void) -{ - - - - - - - if (Settings.flag3.use_underscore) { - return '_'; - } else { - return '-'; - } -} - -void SetShortcutDefault(void) -{ - if ('\0' != XdrvMailbox.data[0]) { - XdrvMailbox.data[0] = '0' + SC_DEFAULT; - XdrvMailbox.data[1] = '\0'; - } -} - -uint8_t Shortcut(void) -{ - uint8_t result = 10; - - if ('\0' == XdrvMailbox.data[1]) { - if (('"' == XdrvMailbox.data[0]) || ('0' == XdrvMailbox.data[0])) { - result = SC_CLEAR; - } else { - result = atoi(XdrvMailbox.data); - if (0 == result) { - result = 10; - } - } - } - return result; -} - -bool ValidIpAddress(const char* str) -{ - const char* p = str; - - while (*p && ((*p == '.') || ((*p >= '0') && (*p <= '9')))) { p++; } - return (*p == '\0'); -} - -bool ParseIp(uint32_t* addr, const char* str) -{ - uint8_t *part = (uint8_t*)addr; - uint8_t i; - - *addr = 0; - for (i = 0; i < 4; i++) { - part[i] = strtoul(str, nullptr, 10); - str = strchr(str, '.'); - if (str == nullptr || *str == '\0') { - break; - } - str++; - } - return (3 == i); -} - -uint32_t ParseParameters(uint32_t count, uint32_t *params) -{ - char *p; - uint32_t i = 0; - for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < count; str = strtok_r(nullptr, ", ", &p), i++) { - params[i] = strtoul(str, nullptr, 0); - } - return i; -} - - -bool NewerVersion(char* version_str) -{ - uint32_t version = 0; - uint32_t i = 0; - char *str_ptr; - - char version_dup[strlen(version_str) +1]; - strncpy(version_dup, version_str, sizeof(version_dup)); - - for (char *str = strtok_r(version_dup, ".", &str_ptr); str && i < sizeof(VERSION); str = strtok_r(nullptr, ".", &str_ptr), i++) { - int field = atoi(str); - - if ((field < 0) || (field > 255)) { - return false; - } - - version = (version << 8) + field; - - if ((2 == i) && isalpha(str[strlen(str)-1])) { - field = str[strlen(str)-1] & 0x1f; - version = (version << 8) + field; - i++; - } - } - - - if ((i < 2) || (i > sizeof(VERSION))) { - return false; - } - - - while (i < sizeof(VERSION)) { - version <<= 8; - i++; - } - - return (version > VERSION); -} - -char* GetPowerDevice(char* dest, uint32_t idx, size_t size, uint32_t option) -{ - strncpy_P(dest, S_RSLT_POWER, size); - if ((devices_present + option) > 1) { - char sidx[8]; - snprintf_P(sidx, sizeof(sidx), PSTR("%d"), idx); - strncat(dest, sidx, size - strlen(dest) -1); - } - return dest; -} - -char* GetPowerDevice(char* dest, uint32_t idx, size_t size) -{ - return GetPowerDevice(dest, idx, size, 0); -} - -void GetEspHardwareType(void) -{ -#ifdef ESP8266 - - uint32_t efuse1 = *(uint32_t*)(0x3FF00050); - uint32_t efuse2 = *(uint32_t*)(0x3FF00054); - - - - is_8285 = ( (efuse1 & (1 << 4)) || (efuse2 & (1 << 16)) ); - if (is_8285 && (ESP.getFlashChipRealSize() > 1048576)) { - is_8285 = false; - } -#else - is_8285 = false; -#endif -} - -String GetDeviceHardware(void) -{ - char buff[10]; -#ifdef ESP8266 - if (is_8285) { - strcpy_P(buff, PSTR("ESP8285")); - } else { - strcpy_P(buff, PSTR("ESP8266EX")); - } -#else - strcpy_P(buff, PSTR("ESP32")); -#endif - return String(buff); -} - -float ConvertTemp(float c) -{ - float result = c; - - global_update = uptime; - global_temperature = c; - - if (!isnan(c) && Settings.flag.temperature_conversion) { - result = c * 1.8 + 32; - } - result = result + (0.1 * Settings.temp_comp); - return result; -} - -float ConvertTempToCelsius(float c) -{ - float result = c; - - if (!isnan(c) && Settings.flag.temperature_conversion) { - result = (c - 32) / 1.8; - } - result = result + (0.1 * Settings.temp_comp); - return result; -} - -char TempUnit(void) -{ - return (Settings.flag.temperature_conversion) ? 'F' : 'C'; -} - -float ConvertHumidity(float h) -{ - float result = h; - - global_update = uptime; - global_humidity = h; - - result = result + (0.1 * Settings.hum_comp); - - return result; -} - -float CalcTempHumToDew(float t, float h) -{ - if (isnan(h) || isnan(t)) { return 0.0; } - - if (Settings.flag.temperature_conversion) { - t = (t - 32) / 1.8; - } - - float gamma = TaylorLog(h / 100) + 17.62 * t / (243.5 + t); - float result = (243.5 * gamma / (17.62 - gamma)); - - if (Settings.flag.temperature_conversion) { - result = result * 1.8 + 32; - } - return result; -} - -float ConvertPressure(float p) -{ - float result = p; - - global_update = uptime; - global_pressure = p; - - if (!isnan(p) && Settings.flag.pressure_conversion) { - result = p * 0.75006375541921; - } - return result; -} - -String PressureUnit(void) -{ - return (Settings.flag.pressure_conversion) ? String(D_UNIT_MILLIMETER_MERCURY) : String(D_UNIT_PRESSURE); -} - -float ConvertSpeed(float s) -{ - - return s * kSpeedConversionFactor[Settings.flag2.speed_conversion]; -} - -String SpeedUnit(void) -{ - char speed[8]; - return String(GetTextIndexed(speed, sizeof(speed), Settings.flag2.speed_conversion, kSpeedUnit)); -} - -void ResetGlobalValues(void) -{ - if ((uptime - global_update) > GLOBAL_VALUES_VALID) { - global_update = 0; - global_temperature = 9999; - global_humidity = 0; - global_pressure = 0; - } -} - -uint32_t SqrtInt(uint32_t num) -{ - if (num <= 1) { - return num; - } - - uint32_t x = num / 2; - uint32_t y; - do { - y = (x + num / x) / 2; - if (y >= x) { - return x; - } - x = y; - } while (true); -} - -uint32_t RoundSqrtInt(uint32_t num) -{ - uint32_t s = SqrtInt(4 * num); - if (s & 1) { - s++; - } - return s / 2; -} - -char* GetTextIndexed(char* destination, size_t destination_size, uint32_t index, const char* haystack) -{ - - - char* write = destination; - const char* read = haystack; - - index++; - while (index--) { - size_t size = destination_size -1; - write = destination; - char ch = '.'; - while ((ch != '\0') && (ch != '|')) { - ch = pgm_read_byte(read++); - if (size && (ch != '|')) { - *write++ = ch; - size--; - } - } - if (0 == ch) { - if (index) { - write = destination; - } - break; - } - } - *write = '\0'; - return destination; -} - -int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack) -{ - - - int result = -1; - const char* read = haystack; - char* write = destination; - - while (true) { - result++; - size_t size = destination_size -1; - write = destination; - char ch = '.'; - while ((ch != '\0') && (ch != '|')) { - ch = pgm_read_byte(read++); - if (size && (ch != '|')) { - *write++ = ch; - size--; - } - } - *write = '\0'; - if (!strcasecmp(needle, destination)) { - break; - } - if (0 == ch) { - result = -1; - break; - } - } - return result; -} - -bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void)) -{ - GetTextIndexed(XdrvMailbox.command, CMDSZ, 0, haystack); - int prefix_length = strlen(XdrvMailbox.command); - if (prefix_length) { - char prefix[prefix_length +1]; - snprintf_P(prefix, sizeof(prefix), XdrvMailbox.topic); - if (strcasecmp(prefix, XdrvMailbox.command)) { - return false; - } - } - int command_code = GetCommandCode(XdrvMailbox.command + prefix_length, CMDSZ, XdrvMailbox.topic + prefix_length, haystack); - if (command_code > 0) { - XdrvMailbox.command_code = command_code -1; - MyCommand[XdrvMailbox.command_code](); - return true; - } - return false; -} - -const char kOptions[] PROGMEM = "OFF|" D_OFF "|FALSE|" D_FALSE "|STOP|" D_STOP "|" D_CELSIUS "|" - "ON|" D_ON "|TRUE|" D_TRUE "|START|" D_START "|" D_FAHRENHEIT "|" D_USER "|" - "TOGGLE|" D_TOGGLE "|" D_ADMIN "|" - "BLINK|" D_BLINK "|" - "BLINKOFF|" D_BLINKOFF "|" - "ALL" ; - -const uint8_t sNumbers[] PROGMEM = { 0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1, - 2,2,2, - 3,3, - 4,4, - 255 }; - -int GetStateNumber(char *state_text) -{ - char command[CMDSZ]; - int state_number = GetCommandCode(command, sizeof(command), state_text, kOptions); - if (state_number >= 0) { - state_number = pgm_read_byte(sNumbers + state_number); - } - return state_number; -} - -String GetSerialConfig(void) -{ - - - - - - const char kParity[] = "NEOI"; - - char config[4]; - config[0] = '5' + (Settings.serial_config & 0x3); - config[1] = kParity[(Settings.serial_config >> 3) & 0x3]; - config[2] = '1' + ((Settings.serial_config >> 2) & 0x1); - config[3] = '\0'; - return String(config); -} - -void SetSerialBegin() -{ - uint32_t baudrate = Settings.baudrate * 300; - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_SERIAL "Set to %s %d bit/s"), GetSerialConfig().c_str(), baudrate); - Serial.flush(); - Serial.begin(baudrate, (SerialConfig)pgm_read_byte(kTasmotaSerialConfig + Settings.serial_config)); -} - -void SetSerialConfig(uint32_t serial_config) -{ - if (serial_config > TS_SERIAL_8O2) { - serial_config = TS_SERIAL_8N1; - } - if (serial_config != Settings.serial_config) { - Settings.serial_config = serial_config; - SetSerialBegin(); - } -} - -void SetSerialBaudrate(uint32_t baudrate) -{ - Settings.baudrate = baudrate / 300; - if (Serial.baudRate() != baudrate) { - SetSerialBegin(); - } -} - -void SetSerial(uint32_t baudrate, uint32_t serial_config) -{ - Settings.flag.mqtt_serial = 0; - Settings.serial_config = serial_config; - Settings.baudrate = baudrate / 300; - SetSeriallog(LOG_LEVEL_NONE); - SetSerialBegin(); -} - -void ClaimSerial(void) -{ - serial_local = true; - AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial")); - SetSeriallog(LOG_LEVEL_NONE); - Settings.baudrate = Serial.baudRate() / 300; -} - -void SerialSendRaw(char *codes) -{ - char *p; - char stemp[3]; - uint8_t code; - - int size = strlen(codes); - - while (size > 1) { - strlcpy(stemp, codes, sizeof(stemp)); - code = strtol(stemp, &p, 16); - Serial.write(code); - size -= 2; - codes += 2; - } -} - -uint32_t GetHash(const char *buffer, size_t size) -{ - uint32_t hash = 0; - for (uint32_t i = 0; i <= size; i++) { - hash += (uint8_t)*buffer++ * (i +1); - } - return hash; -} - -void ShowSource(uint32_t source) -{ - if ((source > 0) && (source < SRC_MAX)) { - char stemp1[20]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource)); - } -} - -void WebHexCode(uint32_t i, const char* code) -{ - char scolor[10]; - - strlcpy(scolor, code, sizeof(scolor)); - char* p = scolor; - if ('#' == p[0]) { p++; } - - if (3 == strlen(p)) { - p[6] = p[3]; - p[5] = p[2]; - p[4] = p[2]; - p[3] = p[1]; - p[2] = p[1]; - p[1] = p[0]; - } - - uint32_t color = strtol(p, nullptr, 16); - - - - - - - uint32_t j = sizeof(Settings.web_color) / 3; -# 962 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support.ino" - if (i >= j) { - - i += ((((uint8_t*)&Settings.web_color2 - (uint8_t*)&Settings.web_color) / 3) - j); - } - Settings.web_color[i][0] = (color >> 16) & 0xFF; - Settings.web_color[i][1] = (color >> 8) & 0xFF; - Settings.web_color[i][2] = color & 0xFF; -} - -uint32_t WebColor(uint32_t i) -{ - uint32_t j = sizeof(Settings.web_color) / 3; - - - - - if (i >= j) { - - i += ((((uint8_t*)&Settings.web_color2 - (uint8_t*)&Settings.web_color) / 3) - j); - } - uint32_t tcolor = (Settings.web_color[i][0] << 16) | (Settings.web_color[i][1] << 8) | Settings.web_color[i][2]; - - return tcolor; -} - - - - - -const uint16_t TIMESZ = 100; - -char* ResponseGetTime(uint32_t format, char* time_str) -{ - switch (format) { - case 1: - snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\",\"Epoch\":%u"), GetDateAndTime(DT_LOCAL).c_str(), UtcTime()); - break; - case 2: - snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime()); - break; - default: - snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); - } - return time_str; -} - -int Response_P(const char* format, ...) -{ - - va_list args; - va_start(args, format); - int len = vsnprintf_P(mqtt_data, sizeof(mqtt_data), format, args); - va_end(args); - return len; -} - -int ResponseTime_P(const char* format, ...) -{ - - va_list args; - va_start(args, format); - - ResponseGetTime(Settings.flag2.time_format, mqtt_data); - - int mlen = strlen(mqtt_data); - int len = vsnprintf_P(mqtt_data + mlen, sizeof(mqtt_data) - mlen, format, args); - va_end(args); - return len + mlen; -} - -int ResponseAppend_P(const char* format, ...) -{ - - va_list args; - va_start(args, format); - int mlen = strlen(mqtt_data); - int len = vsnprintf_P(mqtt_data + mlen, sizeof(mqtt_data) - mlen, format, args); - va_end(args); - return len + mlen; -} - -int ResponseAppendTimeFormat(uint32_t format) -{ - char time_str[TIMESZ]; - return ResponseAppend_P(ResponseGetTime(format, time_str)); -} - -int ResponseAppendTime(void) -{ - return ResponseAppendTimeFormat(Settings.flag2.time_format); -} - -int ResponseAppendTHD(float f_temperature, float f_humidity) -{ - char temperature[FLOATSZ]; - dtostrfd(f_temperature, Settings.flag2.temperature_resolution, temperature); - char humidity[FLOATSZ]; - dtostrfd(f_humidity, Settings.flag2.humidity_resolution, humidity); - char dewpoint[FLOATSZ]; - dtostrfd(CalcTempHumToDew(f_temperature, f_humidity), Settings.flag2.temperature_resolution, dewpoint); - - return ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s,\"" D_JSON_DEWPOINT "\":%s"), temperature, humidity, dewpoint); -} - -int ResponseJsonEnd(void) -{ - return ResponseAppend_P(PSTR("}")); -} - -int ResponseJsonEndEnd(void) -{ - return ResponseAppend_P(PSTR("}}")); -} - - - - - -void DigitalWrite(uint32_t gpio_pin, uint32_t state) -{ - if (pin[gpio_pin] < 99) { - digitalWrite(pin[gpio_pin], state &1); - } -} - -uint8_t ModuleNr(void) -{ - - - return (USER_MODULE == Settings.module) ? 0 : Settings.module +1; -} - -bool ValidTemplateModule(uint32_t index) -{ - for (uint32_t i = 0; i < sizeof(kModuleNiceList); i++) { - if (index == pgm_read_byte(kModuleNiceList + i)) { - return true; - } - } - return false; -} - -bool ValidModule(uint32_t index) -{ - if (index == USER_MODULE) { return true; } - return ValidTemplateModule(index); -} - -String AnyModuleName(uint32_t index) -{ - if (USER_MODULE == index) { - return String(SettingsText(SET_TEMPLATE_NAME)); - } else { - char name[TOPSZ]; - return String(GetTextIndexed(name, sizeof(name), index, kModuleNames)); - } -} - -String ModuleName(void) -{ - return AnyModuleName(Settings.module); -} - -void ModuleGpios(myio *gp) -{ - uint8_t *dest = (uint8_t *)gp; - memset(dest, GPIO_NONE, sizeof(myio)); - - uint8_t src[sizeof(mycfgio)]; - if (USER_MODULE == Settings.module) { - memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio)); - } else { -#ifdef ESP8266 - memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio)); -#else - memcpy_P(&src, &kModules.gp, sizeof(mycfgio)); -#endif - } - - - - - uint32_t j = 0; - for (uint32_t i = 0; i < sizeof(mycfgio); i++) { -#ifdef ESP8266 - if (6 == i) { j = 9; } - if (8 == i) { j = 12; } -#else - if (6 == i) { j = 12; } -#endif - dest[j] = src[i]; - j++; - } - - - -} - -gpio_flag ModuleFlag(void) -{ - gpio_flag flag; - -#ifdef ESP8266 - if (USER_MODULE == Settings.module) { - flag = Settings.user_template.flag; - } else { - memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag)); - } -#else - if (USER_MODULE == Settings.module) { - - - - - - memcpy_P(&flag, &Settings.user_template.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag)); - } else { - memcpy_P(&flag, &kModules.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag)); - } -#endif - - return flag; -} - -void ModuleDefault(uint32_t module) -{ - if (USER_MODULE == module) { module = WEMOS; } - Settings.user_template_base = module; - char name[TOPSZ]; - SettingsUpdateText(SET_TEMPLATE_NAME, GetTextIndexed(name, sizeof(name), module, kModuleNames)); -#ifdef ESP8266 - memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt)); -#else - memcpy_P(&Settings.user_template, &kModules, sizeof(mytmplt)); -#endif -} - -void SetModuleType(void) -{ - my_module_type = (USER_MODULE == Settings.module) ? Settings.user_template_base : Settings.module; -} - -bool FlashPin(uint32_t pin) -{ -#ifdef ESP8266 - return (((pin > 5) && (pin < 9)) || (11 == pin)); -#endif -#ifdef ESP32 - return ((pin > 5) && (pin < 12)); -#endif -} - -uint8_t ValidPin(uint32_t pin, uint32_t gpio) -{ - if (FlashPin(pin)) { - return GPIO_NONE; - } - -#ifdef ESP8266 - - if ((WEMOS == Settings.module) && !Settings.flag3.user_esp8285_enable) { - if ((pin == 9) || (pin == 10)) { - return GPIO_NONE; - } - } -#endif - - return gpio; -} - -bool ValidGPIO(uint32_t pin, uint32_t gpio) -{ - return (GPIO_USER == ValidPin(pin, gpio)); -} - -bool ValidAdc(void) -{ - gpio_flag flag = ModuleFlag(); - uint32_t template_adc0 = flag.data &15; - return (ADC0_USER == template_adc0); -} - -bool GetUsedInModule(uint32_t val, uint8_t *arr) -{ - int offset = 0; - - if (!val) { return false; } - - if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) { - offset = (GPIO_KEY1_NP - GPIO_KEY1); - } - if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) { - offset = -(GPIO_KEY1_NP - GPIO_KEY1); - } - if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) { - offset = -(GPIO_KEY1_INV - GPIO_KEY1); - } - if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) { - offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1); - } - - if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) { - offset = (GPIO_SWT1_NP - GPIO_SWT1); - } - if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) { - offset = -(GPIO_SWT1_NP - GPIO_SWT1); - } - - if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) { - offset = (GPIO_REL1_INV - GPIO_REL1); - } - if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) { - offset = -(GPIO_REL1_INV - GPIO_REL1); - } - - if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) { - offset = (GPIO_LED1_INV - GPIO_LED1); - } - if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) { - offset = -(GPIO_LED1_INV - GPIO_LED1); - } - - if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) { - offset = (GPIO_PWM1_INV - GPIO_PWM1); - } - if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) { - offset = -(GPIO_PWM1_INV - GPIO_PWM1); - } - - if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) { - offset = (GPIO_CNTR1_NP - GPIO_CNTR1); - } - if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) { - offset = -(GPIO_CNTR1_NP - GPIO_CNTR1); - } - - for (uint32_t i = 0; i < MAX_GPIO_PIN; i++) { - if (arr[i] == val) { return true; } - if (arr[i] == val + offset) { return true; } - } - return false; -} - -bool JsonTemplate(const char* dataBuf) -{ - - - if (strlen(dataBuf) < 9) { return false; } - -#ifdef ESP8266 - StaticJsonBuffer<400> jb; -#else - StaticJsonBuffer<800> jb; -#endif - JsonObject& obj = jb.parseObject(dataBuf); - if (!obj.success()) { return false; } - - - const char* name = obj[D_JSON_NAME]; - if (name != nullptr) { - SettingsUpdateText(SET_TEMPLATE_NAME, name); - } - if (obj[D_JSON_GPIO].success()) { - for (uint32_t i = 0; i < sizeof(mycfgio); i++) { - Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0; - } - } - if (obj[D_JSON_FLAG].success()) { - uint8_t flag = obj[D_JSON_FLAG] | 0; - memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag)); - } - if (obj[D_JSON_BASE].success()) { - uint8_t base = obj[D_JSON_BASE]; - if ((0 == base) || !ValidTemplateModule(base -1)) { base = 18; } - Settings.user_template_base = base -1; - } - return true; -} - -void TemplateJson(void) -{ - Response_P(PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), SettingsText(SET_TEMPLATE_NAME)); - for (uint32_t i = 0; i < sizeof(Settings.user_template.gp); i++) { - ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Settings.user_template.gp.io[i]); - } - ResponseAppend_P(PSTR("],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), Settings.user_template.flag, Settings.user_template_base +1); -} - - - - - -inline int32_t TimeDifference(uint32_t prev, uint32_t next) -{ - return ((int32_t) (next - prev)); -} - -int32_t TimePassedSince(uint32_t timestamp) -{ - - - return TimeDifference(timestamp, millis()); -} - -bool TimeReached(uint32_t timer) -{ - - const long passed = TimePassedSince(timer); - return (passed >= 0); -} - -void SetNextTimeInterval(unsigned long& timer, const unsigned long step) -{ - timer += step; - const long passed = TimePassedSince(timer); - if (passed < 0) { return; } - if (static_cast(passed) > step) { - - timer = millis() + step; - return; - } - - timer = millis() + (step - passed); -} - -int32_t TimePassedSinceUsec(uint32_t timestamp) -{ - return TimeDifference(timestamp, micros()); -} - -bool TimeReachedUsec(uint32_t timer) -{ - - const long passed = TimePassedSinceUsec(timer); - return (passed >= 0); -} - - - - - -#ifdef USE_I2C -const uint8_t I2C_RETRY_COUNTER = 3; - -uint32_t i2c_active[4] = { 0 }; -uint32_t i2c_buffer = 0; - -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) -{ - uint8_t retry = I2C_RETRY_COUNTER; - bool status = false; - - i2c_buffer = 0; - while (!status && retry) { - Wire.beginTransmission(addr); - Wire.write(reg); - if (0 == Wire.endTransmission(false)) { - Wire.requestFrom((int)addr, (int)size); - if (Wire.available() == size) { - for (uint32_t i = 0; i < size; i++) { - i2c_buffer = i2c_buffer << 8 | Wire.read(); - } - status = true; - } - } - retry--; - } - return status; -} - -bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg) -{ - bool status = I2cValidRead(addr, reg, 1); - *data = (uint8_t)i2c_buffer; - return status; -} - -bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg) -{ - bool status = I2cValidRead(addr, reg, 2); - *data = (uint16_t)i2c_buffer; - return status; -} - -bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg) -{ - bool status = I2cValidRead(addr, reg, 2); - *data = (int16_t)i2c_buffer; - return status; -} - -bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg) -{ - uint16_t ldata; - bool status = I2cValidRead16(&ldata, addr, reg); - *data = (ldata >> 8) | (ldata << 8); - return status; -} - -bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg) -{ - uint16_t ldata; - bool status = I2cValidRead16LE(&ldata, addr, reg); - *data = (int16_t)ldata; - return status; -} - -bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg) -{ - bool status = I2cValidRead(addr, reg, 3); - *data = i2c_buffer; - return status; -} - -uint8_t I2cRead8(uint8_t addr, uint8_t reg) -{ - I2cValidRead(addr, reg, 1); - return (uint8_t)i2c_buffer; -} - -uint16_t I2cRead16(uint8_t addr, uint8_t reg) -{ - I2cValidRead(addr, reg, 2); - return (uint16_t)i2c_buffer; -} - -int16_t I2cReadS16(uint8_t addr, uint8_t reg) -{ - I2cValidRead(addr, reg, 2); - return (int16_t)i2c_buffer; -} - -uint16_t I2cRead16LE(uint8_t addr, uint8_t reg) -{ - I2cValidRead(addr, reg, 2); - uint16_t temp = (uint16_t)i2c_buffer; - return (temp >> 8) | (temp << 8); -} - -int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg) -{ - return (int16_t)I2cRead16LE(addr, reg); -} - -int32_t I2cRead24(uint8_t addr, uint8_t reg) -{ - I2cValidRead(addr, reg, 3); - return i2c_buffer; -} - -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) -{ - uint8_t x = I2C_RETRY_COUNTER; - - do { - Wire.beginTransmission((uint8_t)addr); - Wire.write(reg); - uint8_t bytes = size; - while (bytes--) { - Wire.write((val >> (8 * bytes)) & 0xFF); - } - x--; - } while (Wire.endTransmission(true) != 0 && x != 0); - return (x); -} - -bool I2cWrite8(uint8_t addr, uint8_t reg, uint16_t val) -{ - return I2cWrite(addr, reg, val, 1); -} - -bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val) -{ - return I2cWrite(addr, reg, val, 2); -} - -int8_t I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len) -{ - Wire.beginTransmission((uint8_t)addr); - Wire.write((uint8_t)reg); - Wire.endTransmission(); - if (len != Wire.requestFrom((uint8_t)addr, (uint8_t)len)) { - return 1; - } - while (len--) { - *reg_data = (uint8_t)Wire.read(); - reg_data++; - } - return 0; -} - -int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len) -{ - Wire.beginTransmission((uint8_t)addr); - Wire.write((uint8_t)reg); - while (len--) { - Wire.write(*reg_data); - reg_data++; - } - Wire.endTransmission(); - return 0; -} - -void I2cScan(char *devs, unsigned int devs_len) -{ - - - - - - - - uint8_t error = 0; - uint8_t address = 0; - uint8_t any = 0; - - snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT)); - for (address = 1; address <= 127; address++) { - Wire.beginTransmission(address); - error = Wire.endTransmission(); - if (0 == error) { - any = 1; - snprintf_P(devs, devs_len, PSTR("%s 0x%02x"), devs, address); - } - else if (error != 2) { - any = 2; - snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address); - break; - } - } - if (any) { - strncat(devs, "\"}", devs_len - strlen(devs) -1); - } - else { - snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}")); - } -} - -void I2cResetActive(uint32_t addr, uint32_t count = 1) -{ - addr &= 0x7F; - count &= 0x7F; - while (count-- && (addr < 128)) { - i2c_active[addr / 32] &= ~(1 << (addr % 32)); - addr++; - } - -} - -void I2cSetActive(uint32_t addr, uint32_t count = 1) -{ - addr &= 0x7F; - count &= 0x7F; - while (count-- && (addr < 128)) { - i2c_active[addr / 32] |= (1 << (addr % 32)); - addr++; - } - -} - -void I2cSetActiveFound(uint32_t addr, const char *types) -{ - I2cSetActive(addr); - AddLog_P2(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); -} - -bool I2cActive(uint32_t addr) -{ - addr &= 0x7F; - if (i2c_active[addr / 32] & (1 << (addr % 32))) { - return true; - } - return false; -} - -bool I2cSetDevice(uint32_t addr) -{ - addr &= 0x7F; - if (I2cActive(addr)) { - return false; - } - Wire.beginTransmission((uint8_t)addr); - return (0 == Wire.endTransmission()); -} -#endif -# 1656 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support.ino" -void SetSeriallog(uint32_t loglevel) -{ - Settings.seriallog_level = loglevel; - seriallog_level = loglevel; - seriallog_timer = 0; -} - -void SetSyslog(uint32_t loglevel) -{ - Settings.syslog_level = loglevel; - syslog_level = loglevel; - syslog_timer = 0; -} - -#ifdef USE_WEBSERVER -void GetLog(uint32_t idx, char** entry_pp, size_t* len_p) -{ - char* entry_p = nullptr; - size_t len = 0; - - if (idx) { - char* it = web_log; - do { - uint32_t cur_idx = *it; - it++; - size_t tmp = strchrspn(it, '\1'); - tmp++; - if (cur_idx == idx) { - len = tmp; - entry_p = it; - break; - } - it += tmp; - } while (it < web_log + WEB_LOG_SIZE && *it != '\0'); - } - *entry_pp = entry_p; - *len_p = len; -} -#endif - -void Syslog(void) -{ - - - uint32_t current_hash = GetHash(SettingsText(SET_SYSLOG_HOST), strlen(SettingsText(SET_SYSLOG_HOST))); - if (syslog_host_hash != current_hash) { - syslog_host_hash = current_hash; - WiFi.hostByName(SettingsText(SET_SYSLOG_HOST), syslog_host_addr); - } - if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) { - char syslog_preamble[64]; - snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), my_hostname); - memmove(log_data + strlen(syslog_preamble), log_data, sizeof(log_data) - strlen(syslog_preamble)); - log_data[sizeof(log_data) -1] = '\0'; - memcpy(log_data, syslog_preamble, strlen(syslog_preamble)); - PortUdp_write(log_data, strlen(log_data)); - PortUdp.endPacket(); - delay(1); - } else { - syslog_level = 0; - syslog_timer = SYSLOG_TIMER; - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SYSLOG_HOST_NOT_FOUND ". " D_RETRY_IN " %d " D_UNIT_SECOND), SYSLOG_TIMER); - } -} - -void AddLog(uint32_t loglevel) -{ - char mxtime[10]; - - snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second); - - if (loglevel <= seriallog_level) { - Serial.printf("%s%s\r\n", mxtime, log_data); - } -#ifdef USE_WEBSERVER - if (Settings.webserver && (loglevel <= Settings.weblog_level)) { - - - web_log_index &= 0xFF; - if (!web_log_index) web_log_index++; - while (web_log_index == web_log[0] || - strlen(web_log) + strlen(log_data) + 13 > WEB_LOG_SIZE) - { - char* it = web_log; - it++; - it += strchrspn(it, '\1'); - it++; - memmove(web_log, it, WEB_LOG_SIZE -(it-web_log)); - } - snprintf_P(web_log, sizeof(web_log), PSTR("%s%c%s%s\1"), web_log, web_log_index++, mxtime, log_data); - web_log_index &= 0xFF; - if (!web_log_index) web_log_index++; - } -#endif - if (Settings.flag.mqtt_enabled && - !global_state.mqtt_down && - (loglevel <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); } - - if (!global_state.wifi_down && - (loglevel <= syslog_level)) { Syslog(); } - - prepped_loglevel = 0; -} - -void AddLog_P(uint32_t loglevel, const char *formatP) -{ - snprintf_P(log_data, sizeof(log_data), formatP); - AddLog(loglevel); -} - -void AddLog_P(uint32_t loglevel, const char *formatP, const char *formatP2) -{ - char message[sizeof(log_data)]; - - snprintf_P(log_data, sizeof(log_data), formatP); - snprintf_P(message, sizeof(message), formatP2); - strncat(log_data, message, sizeof(log_data) - strlen(log_data) -1); - AddLog(loglevel); -} - -void PrepLog_P2(uint32_t loglevel, PGM_P formatP, ...) -{ - va_list arg; - va_start(arg, formatP); - vsnprintf_P(log_data, sizeof(log_data), formatP, arg); - va_end(arg); - - prepped_loglevel = loglevel; -} - -void AddLog_P2(uint32_t loglevel, PGM_P formatP, ...) -{ - va_list arg; - va_start(arg, formatP); - vsnprintf_P(log_data, sizeof(log_data), formatP, arg); - va_end(arg); - - AddLog(loglevel); -} - -void AddLog_Debug(PGM_P formatP, ...) -{ - va_list arg; - va_start(arg, formatP); - vsnprintf_P(log_data, sizeof(log_data), formatP, arg); - va_end(arg); - - AddLog(LOG_LEVEL_DEBUG); -} - -void AddLogBuffer(uint32_t loglevel, uint8_t *buffer, uint32_t count) -{ -# 1820 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support.ino" - char hex_char[(count * 3) + 2]; - AddLog_P2(loglevel, PSTR("DMP: %s"), ToHex_P(buffer, count, hex_char, sizeof(hex_char), ' ')); -} - -void AddLogSerial(uint32_t loglevel) -{ - AddLogBuffer(loglevel, (uint8_t*)serial_in_buffer, serial_in_byte_counter); -} - -void AddLogMissed(const char *sensor, uint32_t misses) -{ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses); -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_button.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_button.ino" -#define BUTTON_V1 -#ifdef BUTTON_V1 - - - - -#define MAX_BUTTON_COMMANDS 5 - -const char kCommands[] PROGMEM = - D_CMND_WIFICONFIG " 2|" D_CMND_WIFICONFIG " 2|" D_CMND_WIFICONFIG " 2|" D_CMND_RESTART " 1|" D_CMND_UPGRADE " 1"; - -struct BUTTON { - unsigned long debounce = 0; - uint16_t hold_timer[MAX_KEYS] = { 0 }; - uint16_t dual_code = 0; - - uint8_t last_state[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; - uint8_t window_timer[MAX_KEYS] = { 0 }; - uint8_t press_counter[MAX_KEYS] = { 0 }; - - uint8_t dual_receive_count = 0; - uint8_t no_pullup_mask = 0; - uint8_t inverted_mask = 0; - uint8_t present = 0; - uint8_t adc = 99; -} Button; - - - -void ButtonPullupFlag(uint8 button_bit) -{ - bitSet(Button.no_pullup_mask, button_bit); -} - -void ButtonInvertFlag(uint8 button_bit) -{ - bitSet(Button.inverted_mask, button_bit); -} - -void ButtonInit(void) -{ - Button.present = 0; - for (uint32_t i = 0; i < MAX_KEYS; i++) { - if (pin[GPIO_KEY1 +i] < 99) { - Button.present++; - pinMode(pin[GPIO_KEY1 +i], bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == pin[GPIO_KEY1 +i]) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); - } -#ifndef USE_ADC_VCC - else if ((99 == Button.adc) && ((ADC0_BUTTON == my_adc0) || (ADC0_BUTTON_INV == my_adc0))) { - Button.present++; - Button.adc = i; - } -#endif - } -} - -uint8_t ButtonSerial(uint8_t serial_in_byte) -{ - if (Button.dual_receive_count) { - Button.dual_receive_count--; - if (Button.dual_receive_count) { - Button.dual_code = (Button.dual_code << 8) | serial_in_byte; - serial_in_byte = 0; - } else { - if (serial_in_byte != 0xA1) { - Button.dual_code = 0; - } - } - } - if (0xA0 == serial_in_byte) { - serial_in_byte = 0; - Button.dual_code = 0; - Button.dual_receive_count = 3; - } - - return serial_in_byte; -} -# 109 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_button.ino" -void ButtonHandler(void) -{ - if (uptime < 4) { return; } - - uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; - uint16_t loops_per_second = 1000 / Settings.button_debounce; - char scmnd[20]; - - - - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { - uint8_t button = NOT_PRESSED; - uint8_t button_present = 0; - -#ifdef ESP8266 - if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) { - button_present = 1; - if (Button.dual_code) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), Button.dual_code); - button = PRESSED; - if (0xF500 == Button.dual_code) { - Button.hold_timer[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1; - hold_time_extent = 1; - } - Button.dual_code = 0; - } - } - else -#endif - if (pin[GPIO_KEY1 +button_index] < 99) { - button_present = 1; - button = (digitalRead(pin[GPIO_KEY1 +button_index]) != bitRead(Button.inverted_mask, button_index)); - } -#ifndef USE_ADC_VCC - if (Button.adc == button_index) { - button_present = 1; - if (ADC0_BUTTON_INV == my_adc0) { - button = (AdcRead(1) < 128); - } - else if (ADC0_BUTTON == my_adc0) { - button = (AdcRead(1) > 128); - } - } -#endif - - if (button_present) { - XdrvMailbox.index = button_index; - XdrvMailbox.payload = button; - if (XdrvCall(FUNC_BUTTON_PRESSED)) { - - } -#ifdef ESP8266 - else if (SONOFF_4CHPRO == my_module_type) { - if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } - - bool button_pressed = false; - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1); - Button.hold_timer[button_index] = loops_per_second; - button_pressed = true; - } - if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1); - if (!Button.hold_timer[button_index]) { button_pressed = true; } - } - if (button_pressed) { - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); - } - } - } -#endif - else { - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - if (Settings.flag.button_single) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1); - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); - } - } else { - Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, Button.press_counter[button_index]); - Button.window_timer[button_index] = loops_per_second / 2; - } - blinks = 201; - } - - if (NOT_PRESSED == button) { - Button.hold_timer[button_index] = 0; - } else { - Button.hold_timer[button_index]++; - if (Settings.flag.button_single) { - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { - - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } else { - if (Settings.flag.button_restrict) { - if (Settings.param[P_HOLD_IGNORE] > 0) { - if (Button.hold_timer[button_index] > loops_per_second * Settings.param[P_HOLD_IGNORE] / 10) { - Button.hold_timer[button_index] = 0; - Button.press_counter[button_index] = 0; - DEBUG_CORE_LOG(PSTR("BTN: " D_BUTTON "%d cancel by " D_CMND_SETOPTION "40 %d"), button_index +1, Settings.param[P_HOLD_IGNORE]); - } - } - if (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { - Button.press_counter[button_index] = 0; - SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); - } - } else { - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { - Button.press_counter[button_index] = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - } - - if (!Settings.flag.button_single) { - if (Button.window_timer[button_index]) { - Button.window_timer[button_index]--; - } else { - if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < MAX_BUTTON_COMMANDS +3)) { - bool single_press = false; - if (Button.press_counter[button_index] < 3) { -#ifdef ESP8266 - if ((SONOFF_DUAL_R2 == my_module_type) || (SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { - single_press = true; - } else -#endif - { - single_press = (Settings.flag.button_swap +1 == Button.press_counter[button_index]); - if ((1 == Button.present) && (2 == devices_present)) { - if (Settings.flag.button_swap) { - Button.press_counter[button_index] = (single_press) ? 1 : 2; - } - } else { - Button.press_counter[button_index] = 1; - } - } - } -#if defined(USE_LIGHT) && defined(ROTARY_V1) - if (!((0 == button_index) && RotaryButtonPressed())) { -#endif - if (single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { - - } else { - if (Button.press_counter[button_index] < 3) { - if (WifiState() > WIFI_RESTART) { - restart_flag = 1; - } else { - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); - } - } else { - if (!Settings.flag.button_restrict) { - GetTextIndexed(scmnd, sizeof(scmnd), Button.press_counter[button_index] -3, kCommands); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } -#if defined(USE_LIGHT) && defined(ROTARY_V1) - } -#endif - Button.press_counter[button_index] = 0; - } - } - } - } - } - Button.last_state[button_index] = button; - } -} - -void ButtonLoop(void) -{ - if (Button.present) { - if (TimeReached(Button.debounce)) { - SetNextTimeInterval(Button.debounce, Settings.button_debounce); - ButtonHandler(); - } - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_button_v2.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_button_v2.ino" -#ifdef BUTTON_V2 - - - - -#define MAX_BUTTON_COMMANDS_V2 3 -#define MAX_RELAY_BUTTON1 4 - -const char kCommands[] PROGMEM = - D_CMND_WIFICONFIG " 2|" D_CMND_RESTART " 1|" D_CMND_UPGRADE " 1"; - -const char kMultiPress[] PROGMEM = - "|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|"; - -struct BUTTON { - unsigned long debounce = 0; - uint16_t hold_timer[MAX_KEYS] = { 0 }; - uint16_t dual_code = 0; - - uint8_t last_state[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; - uint8_t window_timer[MAX_KEYS] = { 0 }; - uint8_t press_counter[MAX_KEYS] = { 0 }; - - uint8_t dual_receive_count = 0; - uint8_t no_pullup_mask = 0; - uint8_t inverted_mask = 0; - uint8_t present = 0; - uint8_t adc = 99; -} Button; - - - -void ButtonPullupFlag(uint8 button_bit) -{ - bitSet(Button.no_pullup_mask, button_bit); -} - -void ButtonInvertFlag(uint8 button_bit) -{ - bitSet(Button.inverted_mask, button_bit); -} - -void ButtonInit(void) -{ - Button.present = 0; - for (uint32_t i = 0; i < MAX_KEYS; i++) { - if (pin[GPIO_KEY1 +i] < 99) { - Button.present++; - pinMode(pin[GPIO_KEY1 +i], bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == pin[GPIO_KEY1 +i]) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); - } -#ifndef USE_ADC_VCC - else if ((99 == Button.adc) && ((ADC0_BUTTON == my_adc0) || (ADC0_BUTTON_INV == my_adc0))) { - Button.present++; - Button.adc = i; - } -#endif - } -} - -uint8_t ButtonSerial(uint8_t serial_in_byte) -{ - if (Button.dual_receive_count) { - Button.dual_receive_count--; - if (Button.dual_receive_count) { - Button.dual_code = (Button.dual_code << 8) | serial_in_byte; - serial_in_byte = 0; - } else { - if (serial_in_byte != 0xA1) { - Button.dual_code = 0; - } - } - } - if (0xA0 == serial_in_byte) { - serial_in_byte = 0; - Button.dual_code = 0; - Button.dual_receive_count = 3; - } - - return serial_in_byte; -} -# 114 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_button_v2.ino" -void ButtonHandler(void) -{ - if (uptime < 4) { return; } - - uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; - uint16_t loops_per_second = 1000 / Settings.button_debounce; - char scmnd[20]; - - - - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { - uint8_t button = NOT_PRESSED; - uint8_t button_present = 0; - -#ifdef ESP8266 - if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) { - button_present = 1; - if (Button.dual_code) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), Button.dual_code); - button = PRESSED; - if (0xF500 == Button.dual_code) { - Button.hold_timer[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1; - hold_time_extent = 1; - } - Button.dual_code = 0; - } - } - else -#endif - if (pin[GPIO_KEY1 +button_index] < 99) { - button_present = 1; - button = (digitalRead(pin[GPIO_KEY1 +button_index]) != bitRead(Button.inverted_mask, button_index)); - } -#ifndef USE_ADC_VCC - if (Button.adc == button_index) { - button_present = 1; - if (ADC0_BUTTON_INV == my_adc0) { - button = (AdcRead(1) < 128); - } - else if (ADC0_BUTTON == my_adc0) { - button = (AdcRead(1) > 128); - } - } -#endif - - if (button_present) { - XdrvMailbox.index = button_index; - XdrvMailbox.payload = button; - if (XdrvCall(FUNC_BUTTON_PRESSED)) { - - } -#ifdef ESP8266 - else if (SONOFF_4CHPRO == my_module_type) { - if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } - - bool button_pressed = false; - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1); - Button.hold_timer[button_index] = loops_per_second; - button_pressed = true; - } - if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1); - if (!Button.hold_timer[button_index]) { button_pressed = true; } - } - if (button_pressed) { - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); - - } - } - } -#endif - else { - - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - - if (Settings.flag.button_single) { - if (!Settings.flag3.mqtt_buttons) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1); - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); - } - } else { - MqttButtonTopic(button_index +1, 1, 0); - } - } else { - Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, Button.press_counter[button_index]); - Button.window_timer[button_index] = loops_per_second / 2; - } - blinks = 201; - } - - if (NOT_PRESSED == button) { - Button.hold_timer[button_index] = 0; - } else { - Button.hold_timer[button_index]++; - if (Settings.flag.button_single) { - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } else { - if (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { - Button.press_counter[button_index] = 0; - if (Settings.flag3.mqtt_buttons) { - MqttButtonTopic(button_index +1, 3, 1); - } else { - SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); - } - } else { - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { - Button.press_counter[button_index] = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - } - - if (!Settings.flag.button_single) { - if (Button.window_timer[button_index]) { - Button.window_timer[button_index]--; - } else { - if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < MAX_BUTTON_COMMANDS_V2 +6)) { - bool single_press = false; - if (Button.press_counter[button_index] < 3) { -#ifdef ESP8266 - if ((SONOFF_DUAL_R2 == my_module_type) || (SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { - single_press = true; - } else -#endif - { - single_press = (Settings.flag.button_swap +1 == Button.press_counter[button_index]); - if ((1 == Button.present) && (2 == devices_present)) { - if (Settings.flag.button_swap) { - Button.press_counter[button_index] = (single_press) ? 1 : 2; - } - - - - - } - } - } -#if defined(USE_LIGHT) && defined(ROTARY_V1) - if (!((0 == button_index) && RotaryButtonPressed())) { -#endif - if (!Settings.flag3.mqtt_buttons && single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { - - } else { - if (Button.press_counter[button_index] < 6) { - if (WifiState() > WIFI_RESTART) { - restart_flag = 1; - } - if (!Settings.flag3.mqtt_buttons) { - if (Button.press_counter[button_index] == 1) { - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); - } else { - SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); - if (0 == button_index) { - if ((Button.press_counter[button_index] > 1 && pin[GPIO_REL1 + Button.press_counter[button_index]-1] < 99) && Button.press_counter[button_index] <= MAX_RELAY_BUTTON1) { - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: Relay%d found on GPIO%d"), Button.press_counter[button_index], pin[GPIO_REL1 + Button.press_counter[button_index]-1]); - } - } - } - } - } else { - GetTextIndexed(scmnd, sizeof(scmnd), Button.press_counter[button_index] -6, kCommands); - ExecuteCommand(scmnd, SRC_BUTTON); - } - if (Settings.flag3.mqtt_buttons) { - if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) { - MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0); - } - } - } -#if defined(USE_LIGHT) && defined(ROTARY_V1) - } -#endif - Button.press_counter[button_index] = 0; - } - } - } - - } - } - Button.last_state[button_index] = button; - } -} - -void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold) -{ - char scommand[CMDSZ]; - char stopic[TOPSZ]; - char mqttstate[7]; - - GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress); - - SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9); - snprintf_P(scommand, sizeof(scommand), PSTR("BUTTON%d"), button_id); - GetTopic_P(stopic, STAT, mqtt_topic, scommand); - Response_P(S_JSON_COMMAND_SVALUE, "ACTION", (hold) ? SettingsText(SET_STATE_TXT4) : mqttstate); - MqttPublish(stopic); -} - -void ButtonLoop(void) -{ - if (Button.present) { - if (TimeReached(Button.debounce)) { - SetNextTimeInterval(Button.debounce, Settings.button_debounce); - ButtonHandler(); - } - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_command.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_command.ino" -const char kTasmotaCommands[] PROGMEM = "|" - D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" - D_CMND_SERIALLOG "|" D_CMND_RESTART "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SAVEDATA "|" - D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|" D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" - D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_WEIGHT_RESOLUTION "|" - D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_TEMPLATE "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" - D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALCONFIG "|" - D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" - D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" - D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" - D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" -#ifdef USE_I2C - D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|" -#endif -#ifdef USE_DEVICE_GROUPS - D_CMND_DEVGROUP_NAME "|" -#ifdef USE_DEVICE_GROUPS_SEND - D_CMND_DEVGROUP_SEND "|" -#endif - D_CMND_DEVGROUP_SHARE "|" D_CMND_DEVGROUPSTATUS "|" -#endif - D_CMND_SENSOR "|" D_CMND_DRIVER; - -void (* const TasmotaCommand[])(void) PROGMEM = { - &CmndBacklog, &CmndDelay, &CmndPower, &CmndStatus, &CmndState, &CmndSleep, &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl, - &CmndSeriallog, &CmndRestart, &CmndPowerOnState, &CmndPulsetime, &CmndBlinktime, &CmndBlinkcount, &CmndSavedata, - &CmndSetoption, &CmndTemperatureResolution, &CmndHumidityResolution, &CmndPressureResolution, &CmndPowerResolution, - &CmndVoltageResolution, &CmndFrequencyResolution, &CmndCurrentResolution, &CmndEnergyResolution, &CmndWeightResolution, - &CmndModule, &CmndModules, &CmndGpio, &CmndGpios, &CmndTemplate, &CmndPwm, &CmndPwmfrequency, &CmndPwmrange, - &CmndButtonDebounce, &CmndSwitchDebounce, &CmndSyslog, &CmndLoghost, &CmndLogport, &CmndSerialSend, &CmndBaudrate, &CmndSerialConfig, - &CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig, - &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd, - &CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, - &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, -#ifdef USE_I2C - &CmndI2cScan, CmndI2cDriver, -#endif -#ifdef USE_DEVICE_GROUPS - &CmndDevGroupName, -#ifdef USE_DEVICE_GROUPS_SEND - &CmndDevGroupSend, -#endif - &CmndDevGroupShare, &CmndDevGroupStatus, -#endif - &CmndSensor, &CmndDriver }; - -const char kWifiConfig[] PROGMEM = - D_WCFG_0_RESTART "||" D_WCFG_2_WIFIMANAGER "||" D_WCFG_4_RETRY "|" D_WCFG_5_WAIT "|" D_WCFG_6_SERIAL "|" D_WCFG_7_WIFIMANAGER_RESET_ONLY; - - - -void ResponseCmndNumber(int value) -{ - Response_P(S_JSON_COMMAND_NVALUE, XdrvMailbox.command, value); -} - -void ResponseCmndFloat(float value, uint32_t decimals) -{ - char stemp1[TOPSZ]; - dtostrfd(value, decimals, stemp1); - Response_P(S_JSON_COMMAND_XVALUE, XdrvMailbox.command, stemp1); -} - -void ResponseCmndIdxNumber(int value) -{ - Response_P(S_JSON_COMMAND_INDEX_NVALUE, XdrvMailbox.command, XdrvMailbox.index, value); -} - -void ResponseCmndChar_P(const char* value) -{ - size_t buf_size = strlen_P(value); - char buf[buf_size + 1]; - strcpy_P(buf, value); - Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, buf); -} - -void ResponseCmndChar(const char* value) -{ - Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, value); -} - -void ResponseCmndStateText(uint32_t value) -{ - ResponseCmndChar(GetStateText(value)); -} - -void ResponseCmndDone(void) -{ - ResponseCmndChar(D_JSON_DONE); -} - -void ResponseCmndIdxChar(const char* value) -{ - Response_P(S_JSON_COMMAND_INDEX_SVALUE, XdrvMailbox.command, XdrvMailbox.index, value); -} - -void ResponseCmndAll(uint32_t text_index, uint32_t count) -{ - uint32_t real_index = text_index; - mqtt_data[0] = '\0'; - for (uint32_t i = 0; i < count; i++) { - if ((SET_MQTT_GRP_TOPIC == text_index) && (1 == i)) { real_index = SET_MQTT_GRP_TOPIC2 -1; } - ResponseAppend_P(PSTR("%c\"%s%d\":\"%s\""), (i) ? ',' : '{', XdrvMailbox.command, i +1, SettingsText(real_index +i)); - } - ResponseJsonEnd(); -} - - - -void ExecuteCommand(const char *cmnd, uint32_t source) -{ - - - -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("ExecuteCommand")); -#endif - ShowSource(source); - - const char *pos = cmnd; - while (*pos && isspace(*pos)) { - pos++; - } - - const char *start = pos; - - while (*pos && (isalpha(*pos) || isdigit(*pos) || '_' == *pos || '/' == *pos)) { - if ('/' == *pos) { - start = pos + 1; - } - pos++; - } - if ('\0' == *start || pos <= start) { - return; - } - - uint32_t size = pos - start; - char stopic[size + 2]; - stopic[0] = '/'; - memcpy(stopic+1, start, size); - stopic[size+1] = '\0'; - - char svalue[strlen(pos) +1]; - strlcpy(svalue, pos, sizeof(svalue)); - CommandHandler(stopic, svalue, strlen(svalue)); -} -# 174 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_command.ino" -void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) -{ -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("CommandHandler")); -#endif - - while (*dataBuf && isspace(*dataBuf)) { - dataBuf++; - data_len--; - } - - bool grpflg = false; - uint32_t real_index = SET_MQTT_GRP_TOPIC; - for (uint32_t i = 0; i < MAX_GROUP_TOPICS; i++) { - if (1 == i) { real_index = SET_MQTT_GRP_TOPIC2 -1; } - char *group_topic = SettingsText(real_index +i); - if (*group_topic && strstr(topicBuf, group_topic) != nullptr) { - grpflg = true; - break; - } - } - - char stemp1[TOPSZ]; - GetFallbackTopic_P(stemp1, ""); - fallback_topic_flag = (!strncmp(topicBuf, stemp1, strlen(stemp1))); - - char *type = strrchr(topicBuf, '/'); - - uint32_t index = 1; - bool user_index = false; - if (type != nullptr) { - type++; - uint32_t i; - for (i = 0; i < strlen(type); i++) { - type[i] = toupper(type[i]); - } - while (isdigit(type[i-1])) { - i--; - } - if (i < strlen(type)) { - index = atoi(type +i); - user_index = true; - } - type[i] = '\0'; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); - - if (type != nullptr) { - Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}")); - - if (Settings.ledstate &0x02) { blinks++; } - - if (!strcmp(dataBuf,"?")) { data_len = 0; } - - char *p; - int32_t payload = strtol(dataBuf, &p, 0); - if (p == dataBuf) { payload = -99; } - int temp_payload = GetStateNumber(dataBuf); - if (temp_payload > -1) { payload = temp_payload; } - - DEBUG_CORE_LOG(PSTR("CMD: Payload %d"), payload); - - - backlog_delay = millis() + Settings.param[P_BACKLOG_DELAY]; - - char command[CMDSZ] = { 0 }; - XdrvMailbox.command = command; - XdrvMailbox.index = index; - XdrvMailbox.data_len = data_len; - XdrvMailbox.payload = payload; - XdrvMailbox.grpflg = grpflg; - XdrvMailbox.usridx = user_index; - XdrvMailbox.topic = type; - XdrvMailbox.data = dataBuf; - -#ifdef USE_SCRIPT_SUB_COMMAND - - if (!Script_SubCmd()) { - if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) { - if (!XdrvCall(FUNC_COMMAND)) { - if (!XsnsCall(FUNC_COMMAND)) { - type = nullptr; - } - } - } - } -#else - if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) { - if (!XdrvCall(FUNC_COMMAND)) { - if (!XsnsCall(FUNC_COMMAND)) { - type = nullptr; - } - } - } -#endif - - } - - if (type == nullptr) { - blinks = 201; - snprintf_P(stemp1, sizeof(stemp1), PSTR(D_JSON_COMMAND)); - Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_UNKNOWN "\"}")); - type = (char*)stemp1; - } - - if (mqtt_data[0] != '\0') { - MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); - XdrvRulesProcess(); - } - fallback_topic_flag = false; -} - - - -void CmndBacklog(void) -{ - if (XdrvMailbox.data_len) { - -#ifdef SUPPORT_IF_STATEMENT - char *blcommand = strtok(XdrvMailbox.data, ";"); - while ((blcommand != nullptr) && (backlog.size() < MAX_BACKLOG)) -#else - uint32_t bl_pointer = (!backlog_pointer) ? MAX_BACKLOG -1 : backlog_pointer; - bl_pointer--; - char *blcommand = strtok(XdrvMailbox.data, ";"); - while ((blcommand != nullptr) && (backlog_index != bl_pointer)) -#endif - { - while(true) { - blcommand = Trim(blcommand); - if (!strncasecmp_P(blcommand, PSTR(D_CMND_BACKLOG), strlen(D_CMND_BACKLOG))) { - blcommand += strlen(D_CMND_BACKLOG); - } else { - break; - } - } - if (*blcommand != '\0') { -#ifdef SUPPORT_IF_STATEMENT - if (backlog.size() < MAX_BACKLOG) { - backlog.add(blcommand); - } -#else - backlog[backlog_index] = String(blcommand); - backlog_index++; - if (backlog_index >= MAX_BACKLOG) backlog_index = 0; -#endif - } - blcommand = strtok(nullptr, ";"); - } - - mqtt_data[0] = '\0'; - } else { - bool blflag = BACKLOG_EMPTY; -#ifdef SUPPORT_IF_STATEMENT - backlog.clear(); -#else - backlog_pointer = backlog_index; -#endif - ResponseCmndChar(blflag ? D_JSON_EMPTY : D_JSON_ABORTED); - } -} - -void CmndDelay(void) -{ - if ((XdrvMailbox.payload >= (MIN_BACKLOG_DELAY / 100)) && (XdrvMailbox.payload <= 3600)) { - backlog_delay = millis() + (100 * XdrvMailbox.payload); - } - uint32_t bl_delay = 0; - long bl_delta = TimePassedSince(backlog_delay); - if (bl_delta < 0) { bl_delay = (bl_delta *-1) / 100; } - ResponseCmndNumber(bl_delay); -} - -void CmndPower(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= devices_present)) { - if ((XdrvMailbox.payload < POWER_OFF) || (XdrvMailbox.payload > POWER_BLINK_STOP)) { - XdrvMailbox.payload = POWER_SHOW_STATE; - } - - ExecuteCommandPower(XdrvMailbox.index, XdrvMailbox.payload, SRC_IGNORE); - mqtt_data[0] = '\0'; - } - else if (0 == XdrvMailbox.index) { - if ((XdrvMailbox.payload < POWER_OFF) || (XdrvMailbox.payload > POWER_TOGGLE)) { - XdrvMailbox.payload = POWER_SHOW_STATE; - } - SetAllPower(XdrvMailbox.payload, SRC_IGNORE); - mqtt_data[0] = '\0'; - } -} - -void CmndStatus(void) -{ - uint32_t payload = ((XdrvMailbox.payload < 0) || (XdrvMailbox.payload > MAX_STATUS)) ? 99 : XdrvMailbox.payload; - - uint32_t option = STAT; - char stemp[200]; - char stemp2[TOPSZ]; - - - - - - if ((!Settings.flag.mqtt_enabled) && (6 == payload)) { payload = 99; } - if (!energy_flg && (9 == payload)) { payload = 99; } - if (!CrashFlag() && (12 == payload)) { payload = 99; } - - if ((0 == payload) || (99 == payload)) { - uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { maxfn = 1; } -#endif - stemp[0] = '\0'; - for (uint32_t i = 0; i < maxfn; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), SettingsText(SET_FRIENDLYNAME1 +i)); - } - stemp2[0] = '\0'; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]); - } - Response_P(PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" - D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" - D_CMND_LEDMASK "\":\"%04X\",\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" - D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), - ModuleNr(), stemp, mqtt_topic, - SettingsText(SET_MQTT_BUTTON_TOPIC), power, Settings.poweronstate, Settings.ledstate, - Settings.ledmask, Settings.save_data, - Settings.flag.save_state, - SettingsText(SET_MQTT_SWITCH_TOPIC), - stemp2, - Settings.flag.mqtt_button_retain, - Settings.flag.mqtt_switch_retain, - Settings.flag.mqtt_sensor_retain, - Settings.flag.mqtt_power_retain); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS)); - } - - if ((0 == payload) || (1 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS1_PARAMETER "\":{\"" D_JSON_BAUDRATE "\":%d,\"" D_CMND_SERIALCONFIG "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\",\"" D_CMND_OTAURL "\":\"%s\",\"" - D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\",\"" D_JSON_STARTUPUTC "\":\"%s\",\"" D_CMND_SLEEP "\":%d,\"" - D_JSON_CONFIG_HOLDER "\":%d,\"" D_JSON_BOOTCOUNT "\":%d,\"BCResetTime\":\"%s\",\"" D_JSON_SAVECOUNT "\":%d,\"" D_JSON_SAVEADDRESS "\":\"%X\"}}"), - Settings.baudrate * 300, GetSerialConfig().c_str(), SettingsText(SET_MQTT_GRP_TOPIC), SettingsText(SET_OTAURL), - GetResetReason().c_str(), GetUptime().c_str(), GetDateAndTime(DT_RESTART).c_str(), Settings.sleep, - Settings.cfg_holder, Settings.bootcount, GetDateAndTime(DT_BOOTCOUNT).c_str(), Settings.save_flag, GetSettingsAddress()); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "1")); - } - - if ((0 == payload) || (2 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS2_FIRMWARE "\":{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\",\"" - D_JSON_BOOTVERSION "\":%d,\"" D_JSON_COREVERSION "\":\"" ARDUINO_CORE_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\"," - "\"Hardware\":\"%s\"" - "%s}}"), - my_version, my_image, GetBuildDateAndTime().c_str(), - ESP_getBootVersion(), ESP.getSdkVersion(), - GetDeviceHardware().c_str(), - GetStatistics().c_str()); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "2")); - } - - if ((0 == payload) || (3 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_MQTTLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" - D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\"" - D_JSON_RESOLUTION "\":\"%08X\",\"" D_CMND_SETOPTION "\":[\"%08X\",\"%s\",\"%08X\",\"%08X\"]}}"), - Settings.seriallog_level, Settings.weblog_level, Settings.mqttlog_level, Settings.syslog_level, - SettingsText(SET_SYSLOG_HOST), Settings.syslog_port, SettingsText(SET_STASSID1), SettingsText(SET_STASSID2), Settings.tele_period, - Settings.flag2.data, Settings.flag.data, ToHex_P((unsigned char*)Settings.param, PARAM8_SIZE, stemp2, sizeof(stemp2)), - Settings.flag3.data, Settings.flag4.data); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3")); - } - - if ((0 == payload) || (4 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\"" - D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\"" - D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]"), - ESP_getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, - ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP_getFlashChipId(), ESP.getFlashChipMode(), - LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, feature6); - XsnsDriverState(); - ResponseAppend_P(PSTR(",\"Sensors\":")); - XsnsSensorState(); - ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "4")); - } - - if ((0 == payload) || (5 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\"" - D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\"" - D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"), - my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(), - IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(), - Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str()); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5")); - } - - if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" - D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"), - SettingsText(SET_MQTT_HOST), Settings.mqtt_port, SettingsText(SET_MQTT_CLIENT), - mqtt_client, SettingsText(SET_MQTT_USER), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6")); - } - - if ((0 == payload) || (7 == payload)) { - if (99 == Settings.timezone) { - snprintf_P(stemp, sizeof(stemp), PSTR("%d" ), Settings.timezone); - } else { - snprintf_P(stemp, sizeof(stemp), PSTR("\"%s\"" ), GetTimeZone().c_str()); - } -#if defined(USE_TIMERS) && defined(USE_SUNRISE) - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\"" - D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%s,\"" D_JSON_SUNRISE "\":\"%s\",\"" D_JSON_SUNSET "\":\"%s\"}}"), - GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_LOCALNOTZ).c_str(), GetDateAndTime(DT_DST).c_str(), - GetDateAndTime(DT_STD).c_str(), stemp, GetSun(0).c_str(), GetSun(1).c_str()); -#else - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\"" - D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%s}}"), - GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_LOCALNOTZ).c_str(), GetDateAndTime(DT_DST).c_str(), - GetDateAndTime(DT_STD).c_str(), stemp); -#endif - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "7")); - } - -#if defined(USE_ENERGY_SENSOR) && defined(USE_ENERGY_MARGIN_DETECTION) - if (energy_flg) { - if ((0 == payload) || (9 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":%d,\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\"" - D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"), - Settings.energy_power_delta, Settings.energy_min_power, Settings.energy_max_power, - Settings.energy_min_voltage, Settings.energy_max_voltage, Settings.energy_min_current, Settings.energy_max_current); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "9")); - } - } -#endif - - if ((0 == payload) || (8 == payload) || (10 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS10_SENSOR "\":")); - MqttShowSensor(); - ResponseJsonEnd(); - if (8 == payload) { - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "8")); - } else { - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "10")); - } - } - - if ((0 == payload) || (11 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS11_STATUS "\":")); - MqttShowState(); - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "11")); - } - - if (CrashFlag()) { - if ((0 == payload) || (12 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS12_STATUS "\":")); - CrashDump(); - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "12")); - } - } - -#ifdef USE_SCRIPT_STATUS - if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">U",2,mqtt_data); -#endif - mqtt_data[0] = '\0'; -} - -void CmndState(void) -{ - mqtt_data[0] = '\0'; - MqttShowState(); - if (Settings.flag3.hass_tele_on_power) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN); - } -#ifdef USE_HOME_ASSISTANT - if (Settings.flag.hass_discovery) { - HAssPublishStatus(); - } -#endif -} - -void CmndTempOffset(void) -{ - if (XdrvMailbox.data_len > 0) { - int value = (int)(CharToFloat(XdrvMailbox.data) * 10); - if ((value > -127) && (value < 127)) { - Settings.temp_comp = value; - } - } - ResponseCmndFloat((float)(Settings.temp_comp) / 10, 1); -} - -void CmndHumOffset(void) -{ - if (XdrvMailbox.data_len > 0) { - int value = (int)(CharToFloat(XdrvMailbox.data) * 10); - if ((value > -101) && (value < 101)) { - Settings.hum_comp = value; - } - } - ResponseCmndFloat((float)(Settings.hum_comp) / 10, 1); -} - -void CmndGlobalTemp(void) -{ - if (XdrvMailbox.data_len > 0) { - float temperature = CharToFloat(XdrvMailbox.data); - if (!isnan(temperature) && Settings.flag.temperature_conversion) { - temperature = (temperature - 32) / 1.8; - } - if ((temperature >= -50.0) && (temperature <= 100.0)) { - ConvertTemp(temperature); - global_update = 1; - } - } - ResponseCmndFloat(global_temperature, 1); -} - -void CmndGlobalHum(void) -{ - if (XdrvMailbox.data_len > 0) { - float humidity = CharToFloat(XdrvMailbox.data); - if ((humidity >= 0.0) && (humidity <= 100.0)) { - ConvertHumidity(humidity); - global_update = 1; - } - } - ResponseCmndFloat(global_humidity, 1); -} - -void CmndSleep(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 251)) { - Settings.sleep = XdrvMailbox.payload; - ssleep = XdrvMailbox.payload; - WiFiSetSleepMode(); - } - Response_P(S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, Settings.sleep, ssleep); - -} - -void CmndUpgrade(void) -{ - - - - - if (((1 == XdrvMailbox.data_len) && (1 == XdrvMailbox.payload)) || ((XdrvMailbox.data_len >= 3) && NewerVersion(XdrvMailbox.data))) { - ota_state_flag = 3; - char stemp1[TOPSZ]; - Response_P(PSTR("{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}"), XdrvMailbox.command, my_version, GetOtaUrl(stemp1, sizeof(stemp1))); - } else { - Response_P(PSTR("{\"%s\":\"" D_JSON_ONE_OR_GT "\"}"), XdrvMailbox.command, my_version); - } -} - -void CmndOtaUrl(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_OTAURL, (SC_DEFAULT == Shortcut()) ? OTA_URL : XdrvMailbox.data); - } - ResponseCmndChar(SettingsText(SET_OTAURL)); -} - -void CmndSeriallog(void) -{ - if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { - Settings.flag.mqtt_serial = 0; - SetSeriallog(XdrvMailbox.payload); - } - Response_P(S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, Settings.seriallog_level, seriallog_level); -} - -void CmndRestart(void) -{ - switch (XdrvMailbox.payload) { - case 1: - restart_flag = 2; - ResponseCmndChar(D_JSON_RESTARTING); - break; - case -1: - CmndCrash(); - break; - case -2: - CmndWDT(); - break; - case -3: - CmndBlockedLoop(); - break; - case 99: - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING)); - EspRestart(); - break; - default: - ResponseCmndChar_P(PSTR(D_JSON_ONE_TO_RESTART)); - } -} - -void CmndPowerOnState(void) -{ -#ifdef ESP8266 - if (my_module_type != MOTOR) -#endif - { - - - - - - - - if ((XdrvMailbox.payload >= POWER_ALL_OFF) && (XdrvMailbox.payload <= POWER_ALL_OFF_PULSETIME_ON)) { - Settings.poweronstate = XdrvMailbox.payload; - if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { - for (uint32_t i = 1; i <= devices_present; i++) { - ExecuteCommandPower(i, POWER_ON, SRC_IGNORE); - } - } - } - ResponseCmndNumber(Settings.poweronstate); - } -} - -void CmndPulsetime(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PULSETIMERS)) { - uint32_t items = 1; - if (!XdrvMailbox.usridx && !XdrvMailbox.data_len) { - items = MAX_PULSETIMERS; - } else { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 65536)) { - Settings.pulse_timer[XdrvMailbox.index -1] = XdrvMailbox.payload; - SetPulseTimer(XdrvMailbox.index -1, XdrvMailbox.payload); - } - } - mqtt_data[0] = '\0'; - for (uint32_t i = 0; i < items; i++) { - uint32_t index = (1 == items) ? XdrvMailbox.index : i +1; - ResponseAppend_P(PSTR("%c\"%s%d\":{\"" D_JSON_SET "\":%d,\"" D_JSON_REMAINING "\":%d}"), - (i) ? ',' : '{', - XdrvMailbox.command, index, - Settings.pulse_timer[index -1], GetPulseTimer(index -1)); - } - ResponseJsonEnd(); - } -} - -void CmndBlinktime(void) -{ - if ((XdrvMailbox.payload > 1) && (XdrvMailbox.payload <= 3600)) { - Settings.blinktime = XdrvMailbox.payload; - if (blink_timer > 0) { blink_timer = millis() + (100 * XdrvMailbox.payload); } - } - ResponseCmndNumber(Settings.blinktime); -} - -void CmndBlinkcount(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 65536)) { - Settings.blinkcount = XdrvMailbox.payload; - if (blink_counter) { blink_counter = Settings.blinkcount *2; } - } - ResponseCmndNumber(Settings.blinkcount); -} - -void CmndSavedata(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3600)) { - Settings.save_data = XdrvMailbox.payload; - save_data_counter = Settings.save_data; - } - SettingsSaveAll(); - char stemp1[TOPSZ]; - if (Settings.save_data > 1) { - snprintf_P(stemp1, sizeof(stemp1), PSTR(D_JSON_EVERY " %d " D_UNIT_SECOND), Settings.save_data); - } - ResponseCmndChar((Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data)); -} - -void CmndSetoption(void) -{ - if (XdrvMailbox.index < 114) { - uint32_t ptype; - uint32_t pindex; - if (XdrvMailbox.index <= 31) { - ptype = 2; - pindex = XdrvMailbox.index; - } - else if (XdrvMailbox.index <= 49) { - ptype = 1; - pindex = XdrvMailbox.index -32; - } - else if (XdrvMailbox.index <= 81) { - ptype = 3; - pindex = XdrvMailbox.index -50; - } - else { - ptype = 4; - pindex = XdrvMailbox.index -82; - } - - if (XdrvMailbox.payload >= 0) { - if (1 == ptype) { - uint32_t param_low = 0; - uint32_t param_high = 255; - switch (pindex) { - case P_HOLD_TIME: - case P_MAX_POWER_RETRY: - param_low = 1; - param_high = 250; - break; - } - if ((XdrvMailbox.payload >= param_low) && (XdrvMailbox.payload <= param_high)) { - Settings.param[pindex] = XdrvMailbox.payload; -#ifdef USE_LIGHT - if (P_RGB_REMAP == pindex) { - LightUpdateColorMapping(); - restart_flag = 2; - } -#endif -#if (defined(USE_IR_REMOTE) && defined(USE_IR_RECEIVE)) || defined(USE_IR_REMOTE_FULL) - if (P_IR_UNKNOW_THRESHOLD == pindex) { - IrReceiveUpdateThreshold(); - } -#endif - } else { - ptype = 99; - } - } else { - if (XdrvMailbox.payload <= 1) { - if (2 == ptype) { - switch (pindex) { - case 5: - case 6: - case 7: - case 9: - case 14: - case 22: - case 23: - case 25: - case 27: - ptype = 99; - break; - case 3: - case 15: - restart_flag = 2; - default: - bitWrite(Settings.flag.data, pindex, XdrvMailbox.payload); - } - if (12 == pindex) { - stop_flash_rotate = XdrvMailbox.payload; - SettingsSave(2); - } - #ifdef USE_HOME_ASSISTANT - if ((19 == pindex) || (30 == pindex)) { - HAssDiscover(); - } - #endif - } - else if (3 == ptype) { - bitWrite(Settings.flag3.data, pindex, XdrvMailbox.payload); - switch (pindex) { - case 5: - if (0 == XdrvMailbox.payload) { - restart_flag = 2; - } - break; - case 10: - WiFiSetSleepMode(); - break; - case 18: - case 25: - restart_flag = 2; - break; - } - } - else if (4 == ptype) { - bitWrite(Settings.flag4.data, pindex, XdrvMailbox.payload); - switch (pindex) { - case 6: - restart_flag = 2; - break; - } - } - } else { - ptype = 99; - } - } - } - - if (ptype < 99) { - if (1 == ptype) { - ResponseCmndIdxNumber(Settings.param[pindex]); - } else { - uint32_t flag = Settings.flag.data; - if (3 == ptype) { - flag = Settings.flag3.data; - } - else if (4 == ptype) { - flag = Settings.flag4.data; - } - ResponseCmndIdxChar(GetStateText(bitRead(flag, pindex))); - } - } - } -} - -void CmndTemperatureResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.temperature_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.temperature_resolution); -} - -void CmndHumidityResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.humidity_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.humidity_resolution); -} - -void CmndPressureResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.pressure_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.pressure_resolution); -} - -void CmndPowerResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.wattage_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.wattage_resolution); -} - -void CmndVoltageResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.voltage_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.voltage_resolution); -} - -void CmndFrequencyResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.frequency_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.frequency_resolution); -} - -void CmndCurrentResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.current_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.current_resolution); -} - -void CmndEnergyResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) { - Settings.flag2.energy_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.energy_resolution); -} - -void CmndWeightResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - Settings.flag2.weight_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.weight_resolution); -} - -void CmndSpeedUnit(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) { - Settings.flag2.speed_conversion = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.speed_conversion); -} - -void CmndModule(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= MAXMODULE)) { - bool present = false; - if (0 == XdrvMailbox.payload) { - XdrvMailbox.payload = USER_MODULE; - present = true; - } else { - XdrvMailbox.payload--; - present = ValidTemplateModule(XdrvMailbox.payload); - } - if (present) { - Settings.last_module = Settings.module; - Settings.module = XdrvMailbox.payload; - SetModuleType(); - if (Settings.last_module != XdrvMailbox.payload) { - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - Settings.my_gp.io[i] = GPIO_NONE; - } - } - restart_flag = 2; - } - } - Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, ModuleNr(), ModuleName().c_str()); -} - -void CmndModules(void) -{ - uint32_t midx = USER_MODULE; - uint32_t lines = 1; - bool jsflg = false; - for (uint32_t i = 0; i <= sizeof(kModuleNiceList); i++) { - if (i > 0) { midx = pgm_read_byte(kModuleNiceList + i -1); } - if (!jsflg) { - Response_P(PSTR("{\"" D_CMND_MODULES "%d\":{"), lines); - } else { - ResponseAppend_P(PSTR(",")); - } - jsflg = true; - uint32_t j = i ? midx +1 : 0; - if ((ResponseAppend_P(PSTR("\"%d\":\"%s\""), j, AnyModuleName(midx).c_str()) > (LOGSZ - TOPSZ)) || (i == sizeof(kModuleNiceList))) { - ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, UpperCase(XdrvMailbox.command, XdrvMailbox.command)); - jsflg = false; - lines++; - } - } - mqtt_data[0] = '\0'; -} - -void CmndGpio(void) -{ - if (XdrvMailbox.index < sizeof(Settings.my_gp)) { - myio cmodule; - ModuleGpios(&cmodule); - if (ValidGPIO(XdrvMailbox.index, cmodule.io[XdrvMailbox.index]) && (XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < GPIO_SENSOR_END)) { - bool present = false; - for (uint32_t i = 0; i < sizeof(kGpioNiceList); i++) { - uint32_t midx = pgm_read_byte(kGpioNiceList + i); - if (midx == XdrvMailbox.payload) { present = true; } - } - if (present) { - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - if (ValidGPIO(i, cmodule.io[i]) && (Settings.my_gp.io[i] == XdrvMailbox.payload)) { - Settings.my_gp.io[i] = GPIO_NONE; - } - } - Settings.my_gp.io[XdrvMailbox.index] = XdrvMailbox.payload; - restart_flag = 2; - } - } - Response_P(PSTR("{")); - bool jsflg = false; - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - if (ValidGPIO(i, cmodule.io[i]) || ((GPIO_USER == XdrvMailbox.payload) && !FlashPin(i))) { - if (jsflg) { ResponseAppend_P(PSTR(",")); } - jsflg = true; - uint8_t sensor_type = Settings.my_gp.io[i]; - if (!ValidGPIO(i, cmodule.io[i])) { - sensor_type = cmodule.io[i]; - if (GPIO_USER == sensor_type) { - sensor_type = GPIO_NONE; - } - } - uint8_t sensor_name_idx = sensor_type; - const char *sensor_names = kSensorNames; - if (sensor_type > GPIO_FIX_START) { - sensor_name_idx = sensor_type - GPIO_FIX_START -1; - sensor_names = kSensorNamesFixed; - } - char stemp1[TOPSZ]; - ResponseAppend_P(PSTR("\"" D_CMND_GPIO "%d\":{\"%d\":\"%s\"}"), - i, sensor_type, GetTextIndexed(stemp1, sizeof(stemp1), sensor_name_idx, sensor_names)); - } - } - if (jsflg) { - ResponseJsonEnd(); - } else { - ResponseCmndChar(D_JSON_NOT_SUPPORTED); - } - } -} - -void CmndGpios(void) -{ - myio cmodule; - ModuleGpios(&cmodule); - uint32_t lines = 1; - bool jsflg = false; - for (uint32_t i = 0; i < sizeof(kGpioNiceList); i++) { - uint32_t midx = pgm_read_byte(kGpioNiceList + i); - if ((XdrvMailbox.payload != 255) && GetUsedInModule(midx, cmodule.io)) { continue; } - if (!jsflg) { - Response_P(PSTR("{\"" D_CMND_GPIOS "%d\":{"), lines); - } else { - ResponseAppend_P(PSTR(",")); - } - jsflg = true; - char stemp1[TOPSZ]; - if ((ResponseAppend_P(PSTR("\"%d\":\"%s\""), midx, GetTextIndexed(stemp1, sizeof(stemp1), midx, kSensorNames)) > (LOGSZ - TOPSZ)) || (i == sizeof(kGpioNiceList) -1)) { - ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, UpperCase(XdrvMailbox.command, XdrvMailbox.command)); - jsflg = false; - lines++; - } - } - mqtt_data[0] = '\0'; -} - -void CmndTemplate(void) -{ - - bool error = false; - - if (strstr(XdrvMailbox.data, "{") == nullptr) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= MAXMODULE)) { - XdrvMailbox.payload--; - if (ValidTemplateModule(XdrvMailbox.payload)) { - ModuleDefault(XdrvMailbox.payload); - if (USER_MODULE == Settings.module) { restart_flag = 2; } - } - } - else if (0 == XdrvMailbox.payload) { - if (Settings.module != USER_MODULE) { - ModuleDefault(Settings.module); - } - } - else if (255 == XdrvMailbox.payload) { - if (Settings.module != USER_MODULE) { - ModuleDefault(Settings.module); - } - SettingsUpdateText(SET_TEMPLATE_NAME, "Merged"); - uint32_t j = 0; - for (uint32_t i = 0; i < sizeof(mycfgio); i++) { -#ifdef ESP8266 - if (6 == i) { j = 9; } - if (8 == i) { j = 12; } -#else - if (6 == i) { j = 12; } -#endif - if (my_module.io[j] > GPIO_NONE) { - Settings.user_template.gp.io[i] = my_module.io[j]; - } - j++; - } - } - } - else { - if (JsonTemplate(XdrvMailbox.data)) { - if (USER_MODULE == Settings.module) { restart_flag = 2; } - } else { - ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); - error = true; - } - } - if (!error) { TemplateJson(); } -} - -void CmndPwm(void) -{ - if (pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings.pwm_range) && (pin[GPIO_PWM1 + XdrvMailbox.index -1] < 99)) { - Settings.pwm_value[XdrvMailbox.index -1] = XdrvMailbox.payload; - analogWrite(pin[GPIO_PWM1 + XdrvMailbox.index -1], bitRead(pwm_inverted, XdrvMailbox.index -1) ? Settings.pwm_range - XdrvMailbox.payload : XdrvMailbox.payload); - } - Response_P(PSTR("{")); - MqttShowPWMState(); - ResponseJsonEnd(); - } -} - -void CmndPwmfrequency(void) -{ - if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) { - Settings.pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload; - analogWriteFreq(Settings.pwm_frequency); - } - ResponseCmndNumber(Settings.pwm_frequency); -} - -void CmndPwmrange(void) -{ - if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) { - Settings.pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : XdrvMailbox.payload; - for (uint32_t i = 0; i < MAX_PWMS; i++) { - if (Settings.pwm_value[i] > Settings.pwm_range) { - Settings.pwm_value[i] = Settings.pwm_range; - } - } - analogWriteRange(Settings.pwm_range); - } - ResponseCmndNumber(Settings.pwm_range); -} - -void CmndButtonDebounce(void) -{ - if ((XdrvMailbox.payload > 39) && (XdrvMailbox.payload < 1001)) { - Settings.button_debounce = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.button_debounce); -} - -void CmndSwitchDebounce(void) -{ - if ((XdrvMailbox.payload > 39) && (XdrvMailbox.payload < 1001)) { - Settings.switch_debounce = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.switch_debounce); -} - -void CmndBaudrate(void) -{ - if (XdrvMailbox.payload >= 300) { - XdrvMailbox.payload /= 300; - uint32_t baudrate = (XdrvMailbox.payload & 0xFFFF) * 300; - SetSerialBaudrate(baudrate); - } - ResponseCmndNumber(Settings.baudrate * 300); -} - -void CmndSerialConfig(void) -{ - - - - - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.data_len < 3) { - if ((XdrvMailbox.payload >= TS_SERIAL_5N1) && (XdrvMailbox.payload <= TS_SERIAL_8O2)) { - SetSerialConfig(XdrvMailbox.payload); - } - } - else if ((XdrvMailbox.payload >= 5) && (XdrvMailbox.payload <= 8)) { - uint8_t serial_config = XdrvMailbox.payload -5; - - bool valid = true; - char parity = (XdrvMailbox.data[1] & 0xdf); - if ('E' == parity) { - serial_config += 0x08; - } - else if ('O' == parity) { - serial_config += 0x10; - } - else if ('N' != parity) { - valid = false; - } - - if ('2' == XdrvMailbox.data[2]) { - serial_config += 0x04; - } - else if ('1' != XdrvMailbox.data[2]) { - valid = false; - } - - if (valid) { - SetSerialConfig(serial_config); - } - } - } - ResponseCmndChar(GetSerialConfig().c_str()); -} - -void CmndSerialSend(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { - SetSeriallog(LOG_LEVEL_NONE); - Settings.flag.mqtt_serial = 1; - Settings.flag.mqtt_serial_raw = (XdrvMailbox.index > 3) ? 1 : 0; - if (XdrvMailbox.data_len > 0) { - if (1 == XdrvMailbox.index) { - Serial.printf("%s\n", XdrvMailbox.data); - } - else if (2 == XdrvMailbox.index || 4 == XdrvMailbox.index) { - for (uint32_t i = 0; i < XdrvMailbox.data_len; i++) { - Serial.write(XdrvMailbox.data[i]); - } - } - else if (3 == XdrvMailbox.index) { - uint32_t dat_len = XdrvMailbox.data_len; - Serial.printf("%s", Unescape(XdrvMailbox.data, &dat_len)); - } - else if (5 == XdrvMailbox.index) { - SerialSendRaw(RemoveSpace(XdrvMailbox.data)); - } - ResponseCmndDone(); - } - } -} - -void CmndSerialDelimiter(void) -{ - if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.payload < 256)) { - if (XdrvMailbox.payload > 0) { - Settings.serial_delimiter = XdrvMailbox.payload; - } else { - uint32_t dat_len = XdrvMailbox.data_len; - Unescape(XdrvMailbox.data, &dat_len); - Settings.serial_delimiter = XdrvMailbox.data[0]; - } - } - ResponseCmndNumber(Settings.serial_delimiter); -} - -void CmndSyslog(void) -{ - if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { - SetSyslog(XdrvMailbox.payload); - } - Response_P(S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, Settings.syslog_level, syslog_level); -} - -void CmndLoghost(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_SYSLOG_HOST, (SC_DEFAULT == Shortcut()) ? SYS_LOG_HOST : XdrvMailbox.data); - } - ResponseCmndChar(SettingsText(SET_SYSLOG_HOST)); -} - -void CmndLogport(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 65536)) { - Settings.syslog_port = (1 == XdrvMailbox.payload) ? SYS_LOG_PORT : XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.syslog_port); -} - -void CmndIpAddress(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) { - uint32_t address; - if (ParseIp(&address, XdrvMailbox.data)) { - Settings.ip_address[XdrvMailbox.index -1] = address; - - } - char stemp1[TOPSZ]; - snprintf_P(stemp1, sizeof(stemp1), PSTR(" (%s)"), WiFi.localIP().toString().c_str()); - Response_P(S_JSON_COMMAND_INDEX_SVALUE_SVALUE, XdrvMailbox.command, XdrvMailbox.index, IPAddress(Settings.ip_address[XdrvMailbox.index -1]).toString().c_str(), (1 == XdrvMailbox.index) ? stemp1:""); - } -} - -void CmndNtpServer(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_NTP_SERVERS)) { - if (!XdrvMailbox.usridx) { - ResponseCmndAll(SET_NTPSERVER1, MAX_NTP_SERVERS); - } else { - uint32_t ntp_server = SET_NTPSERVER1 + XdrvMailbox.index -1; - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(ntp_server, - (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? NTP_SERVER1 : (2 == XdrvMailbox.index) ? NTP_SERVER2 : NTP_SERVER3 : XdrvMailbox.data); - SettingsUpdateText(ntp_server, ReplaceCommaWithDot(SettingsText(ntp_server))); - - ntp_force_sync = true; - } - ResponseCmndIdxChar(SettingsText(ntp_server)); - } - } -} - -void CmndAp(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { - switch (XdrvMailbox.payload) { - case 0: - Settings.sta_active ^= 1; - break; - case 1: - case 2: - Settings.sta_active = XdrvMailbox.payload -1; - } - restart_flag = 2; - } - Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active)); -} - -void CmndSsid(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SSIDS)) { - if (!XdrvMailbox.usridx) { - ResponseCmndAll(SET_STASSID1, MAX_SSIDS); - } else { - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_STASSID1 + XdrvMailbox.index -1, - (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? STA_SSID1 : STA_SSID2 : XdrvMailbox.data); - Settings.sta_active = XdrvMailbox.index -1; - restart_flag = 2; - } - ResponseCmndIdxChar(SettingsText(SET_STASSID1 + XdrvMailbox.index -1)); - } - } -} - -void CmndPassword(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) { - if ((XdrvMailbox.data_len > 4) || (SC_CLEAR == Shortcut()) || (SC_DEFAULT == Shortcut())) { - SettingsUpdateText(SET_STAPWD1 + XdrvMailbox.index -1, - (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? STA_PASS1 : STA_PASS2 : XdrvMailbox.data); - Settings.sta_active = XdrvMailbox.index -1; - restart_flag = 2; - ResponseCmndIdxChar(SettingsText(SET_STAPWD1 + XdrvMailbox.index -1)); - } else { - Response_P(S_JSON_COMMAND_INDEX_ASTERISK, XdrvMailbox.command, XdrvMailbox.index); - } - } -} - -void CmndHostname(void) -{ - if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { - SettingsUpdateText(SET_HOSTNAME, (SC_DEFAULT == Shortcut()) ? WIFI_HOSTNAME : XdrvMailbox.data); - if (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) { - SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); - } - restart_flag = 2; - } - ResponseCmndChar(SettingsText(SET_HOSTNAME)); -} - -void CmndWifiConfig(void) -{ - if ((XdrvMailbox.payload >= WIFI_RESTART) && (XdrvMailbox.payload < MAX_WIFI_OPTION)) { - if ((EX_WIFI_SMARTCONFIG == XdrvMailbox.payload) || (EX_WIFI_WPSCONFIG == XdrvMailbox.payload)) { - XdrvMailbox.payload = WIFI_MANAGER; - } - Settings.sta_config = XdrvMailbox.payload; - wifi_state_flag = Settings.sta_config; - if (WifiState() > WIFI_RESTART) { - restart_flag = 2; - } - } - char stemp1[TOPSZ]; - Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_config, GetTextIndexed(stemp1, sizeof(stemp1), Settings.sta_config, kWifiConfig)); -} - -void CmndFriendlyname(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_FRIENDLYNAMES)) { - if (!XdrvMailbox.usridx && !XdrvMailbox.data_len) { - ResponseCmndAll(SET_FRIENDLYNAME1, MAX_FRIENDLYNAMES); - } else { - if (XdrvMailbox.data_len > 0) { - char stemp1[TOPSZ]; - if (1 == XdrvMailbox.index) { - snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME)); - } else { - snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME "%d"), XdrvMailbox.index); - } - SettingsUpdateText(SET_FRIENDLYNAME1 + XdrvMailbox.index -1, ('"' == XdrvMailbox.data[0]) ? "" : (SC_DEFAULT == Shortcut()) ? stemp1 : XdrvMailbox.data); - } - ResponseCmndIdxChar(SettingsText(SET_FRIENDLYNAME1 + XdrvMailbox.index -1)); - } - } -} - -void CmndSwitchMode(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SWITCHES)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_SWITCH_OPTION)) { - Settings.switchmode[XdrvMailbox.index -1] = XdrvMailbox.payload; - } - ResponseCmndIdxNumber(Settings.switchmode[XdrvMailbox.index-1]); - } -} - -void CmndInterlock(void) -{ - - uint32_t max_relays = devices_present; - if (light_type) { max_relays--; } - if (max_relays > sizeof(Settings.interlock[0]) * 8) { max_relays = sizeof(Settings.interlock[0]) * 8; } - if (max_relays > 1) { - if (XdrvMailbox.data_len > 0) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { - for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } - char *group; - char *q; - uint32_t group_index = 0; - power_t relay_mask = 0; - for (group = strtok_r(XdrvMailbox.data, " ", &q); group && group_index < MAX_INTERLOCKS; group = strtok_r(nullptr, " ", &q)) { - char *str; - char *p; - for (str = strtok_r(group, ",", &p); str; str = strtok_r(nullptr, ",", &p)) { - int pbit = atoi(str); - if ((pbit > 0) && (pbit <= max_relays)) { - pbit--; - if (!bitRead(relay_mask, pbit)) { - bitSet(relay_mask, pbit); - bitSet(Settings.interlock[group_index], pbit); - } - } - } - group_index++; - } - for (uint32_t i = 0; i < group_index; i++) { - uint32_t minimal_bits = 0; - for (uint32_t j = 0; j < max_relays; j++) { - if (bitRead(Settings.interlock[i], j)) { minimal_bits++; } - } - if (minimal_bits < 2) { Settings.interlock[i] = 0; } - } - } else { - Settings.flag.interlock = XdrvMailbox.payload &1; - if (Settings.flag.interlock) { - SetDevicePower(power, SRC_IGNORE); - } - } -#ifdef USE_SHUTTER - if (Settings.flag3.shutter_mode) { - ShutterInit(); - } -#endif - } - Response_P(PSTR("{\"" D_CMND_INTERLOCK "\":\"%s\",\"" D_JSON_GROUPS "\":\""), GetStateText(Settings.flag.interlock)); - uint32_t anygroup = 0; - for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { - if (Settings.interlock[i]) { - anygroup++; - ResponseAppend_P(PSTR("%s"), (anygroup > 1) ? " " : ""); - uint32_t anybit = 0; - power_t mask = 1; - for (uint32_t j = 0; j < max_relays; j++) { - if (Settings.interlock[i] & mask) { - anybit++; - ResponseAppend_P(PSTR("%s%d"), (anybit > 1) ? "," : "", j +1); - } - mask <<= 1; - } - } - } - if (!anygroup) { - for (uint32_t j = 1; j <= max_relays; j++) { - ResponseAppend_P(PSTR("%s%d"), (j > 1) ? "," : "", j); - } - } - ResponseAppend_P(PSTR("\"}")); - } else { - Settings.flag.interlock = 0; - ResponseCmndStateText(Settings.flag.interlock); - } -} - -void CmndTeleperiod(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.tele_period = (1 == XdrvMailbox.payload) ? TELE_PERIOD : XdrvMailbox.payload; - if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) Settings.tele_period = 10; - tele_period = Settings.tele_period; - } - ResponseCmndNumber(Settings.tele_period); -} - -void CmndReset(void) -{ - switch (XdrvMailbox.payload) { - case 1: - restart_flag = 211; - ResponseCmndChar(D_JSON_RESET_AND_RESTARTING); - break; - case 2 ... 6: - restart_flag = 210 + XdrvMailbox.payload; - Response_P(PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}")); - break; - case 99: - Settings.bootcount = 0; - Settings.bootcount_reset_time = 0; - ResponseCmndDone(); - break; - default: - ResponseCmndChar(D_JSON_ONE_TO_RESET); - } -} - -void CmndTime(void) -{ - - - - - - - - uint32_t format = Settings.flag2.time_format; - if (XdrvMailbox.data_len > 0) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4)) { - Settings.flag2.time_format = XdrvMailbox.payload -1; - format = Settings.flag2.time_format; - } else { - format = 1; - RtcSetTime(XdrvMailbox.payload); - } - } - mqtt_data[0] = '\0'; - ResponseAppendTimeFormat(format); - ResponseJsonEnd(); -} - -void CmndTimezone(void) -{ - if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.payload >= -13)) { - Settings.timezone = XdrvMailbox.payload; - Settings.timezone_minutes = 0; - if (XdrvMailbox.payload < 15) { - char *p = strtok (XdrvMailbox.data, ":"); - if (p) { - p = strtok (nullptr, ":"); - if (p) { - Settings.timezone_minutes = strtol(p, nullptr, 10); - if (Settings.timezone_minutes > 59) { Settings.timezone_minutes = 59; } - } - } - } else { - Settings.timezone = 99; - } - ntp_force_sync = true; - } - if (99 == Settings.timezone) { - ResponseCmndNumber(Settings.timezone); - } else { - char stemp1[TOPSZ]; - snprintf_P(stemp1, sizeof(stemp1), PSTR("%+03d:%02d"), Settings.timezone, Settings.timezone_minutes); - ResponseCmndChar(stemp1); - } -} - -void CmndTimeStdDst(uint32_t ts) -{ - - if (XdrvMailbox.data_len > 0) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { - uint32_t tpos = 0; - int value = 0; - char *p = XdrvMailbox.data; - char *q = p; - while (p && (tpos < 7)) { - if (p > q) { - if (1 == tpos) { Settings.tflag[ts].hemis = value &1; } - if (2 == tpos) { Settings.tflag[ts].week = (value < 0) ? 0 : (value > 4) ? 4 : value; } - if (3 == tpos) { Settings.tflag[ts].month = (value < 1) ? 1 : (value > 12) ? 12 : value; } - if (4 == tpos) { Settings.tflag[ts].dow = (value < 1) ? 1 : (value > 7) ? 7 : value; } - if (5 == tpos) { Settings.tflag[ts].hour = (value < 0) ? 0 : (value > 23) ? 23 : value; } - if (6 == tpos) { Settings.toffset[ts] = (value < -900) ? -900 : (value > 900) ? 900 : value; } - } - p = Trim(p); - if (tpos && (*p == ',')) { p++; } - p = Trim(p); - q = p; - value = strtol(p, &p, 10); - tpos++; - } - ntp_force_sync = true; - } else { - if (0 == XdrvMailbox.payload) { - if (0 == ts) { - SettingsResetStd(); - } else { - SettingsResetDst(); - } - } - ntp_force_sync = true; - } - } - Response_P(PSTR("{\"%s\":{\"Hemisphere\":%d,\"Week\":%d,\"Month\":%d,\"Day\":%d,\"Hour\":%d,\"Offset\":%d}}"), - XdrvMailbox.command, Settings.tflag[ts].hemis, Settings.tflag[ts].week, Settings.tflag[ts].month, Settings.tflag[ts].dow, Settings.tflag[ts].hour, Settings.toffset[ts]); -} - -void CmndTimeStd(void) -{ - CmndTimeStdDst(0); -} - -void CmndTimeDst(void) -{ - CmndTimeStdDst(1); -} - -void CmndAltitude(void) -{ - if ((XdrvMailbox.data_len > 0) && ((XdrvMailbox.payload >= -30000) && (XdrvMailbox.payload <= 30000))) { - Settings.altitude = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.altitude); -} - -void CmndLedPower(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_LEDS)) { - if (99 == pin[GPIO_LEDLNK]) { XdrvMailbox.index = 1; } - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { - Settings.ledstate &= 8; - uint32_t mask = 1 << (XdrvMailbox.index -1); - switch (XdrvMailbox.payload) { - case 0: - led_power &= (0xFF ^ mask); - Settings.ledstate = 0; - break; - case 1: - led_power |= mask; - Settings.ledstate = 8; - break; - case 2: - led_power ^= mask; - Settings.ledstate ^= 8; - break; - } - blinks = 0; - if (99 == pin[GPIO_LEDLNK]) { - SetLedPower(Settings.ledstate &8); - } else { - SetLedPowerIdx(XdrvMailbox.index -1, (led_power & mask)); - } - } - bool state = bitRead(led_power, XdrvMailbox.index -1); - if (99 == pin[GPIO_LEDLNK]) { - state = bitRead(Settings.ledstate, 3); - } - ResponseCmndIdxChar(GetStateText(state)); - } -} - -void CmndLedState(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_LED_OPTION)) { - Settings.ledstate = XdrvMailbox.payload; - if (!Settings.ledstate) { - SetLedPowerAll(0); - SetLedLink(0); - } - } - ResponseCmndNumber(Settings.ledstate); -} - -void CmndLedMask(void) -{ - if (XdrvMailbox.data_len > 0) { - Settings.ledmask = XdrvMailbox.payload; - } - char stemp1[TOPSZ]; - snprintf_P(stemp1, sizeof(stemp1), PSTR("%d (0x%04X)"), Settings.ledmask, Settings.ledmask); - ResponseCmndChar(stemp1); -} - -void CmndWifiPower(void) -{ - if (XdrvMailbox.data_len > 0) { - Settings.wifi_output_power = (uint8_t)(CharToFloat(XdrvMailbox.data) * 10); - if (Settings.wifi_output_power > 205) { - Settings.wifi_output_power = 205; - } - WifiSetOutputPower(); - } - ResponseCmndChar(WifiGetOutputPower().c_str()); -} - -#ifdef USE_I2C -void CmndI2cScan(void) -{ - if (i2c_flg) { - I2cScan(mqtt_data, sizeof(mqtt_data)); - } -} - -void CmndI2cDriver(void) -{ - if (XdrvMailbox.index < MAX_I2C_DRIVERS) { - if (XdrvMailbox.payload >= 0) { - bitWrite(Settings.i2c_drivers[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1); - restart_flag = 2; - } - } - Response_P(PSTR("{\"" D_CMND_I2CDRIVER "\":")); - I2cDriverState(); - ResponseJsonEnd(); -} -#endif - -#ifdef USE_DEVICE_GROUPS -void CmndDevGroupName(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DEV_GROUP_NAMES)) { - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.data_len > TOPSZ) - XdrvMailbox.data[TOPSZ - 1] = 0; - else if (1 == XdrvMailbox.data_len && ('"' == XdrvMailbox.data[0] || '0' == XdrvMailbox.data[0])) - XdrvMailbox.data[0] = 0; - SettingsUpdateText(SET_DEV_GROUP_NAME1 + XdrvMailbox.index - 1, XdrvMailbox.data); - restart_flag = 2; - } - ResponseCmndAll(SET_DEV_GROUP_NAME1, MAX_DEV_GROUP_NAMES); - } -} - -#ifdef USE_DEVICE_GROUPS_SEND -void CmndDevGroupSend(void) -{ - uint8_t device_group_index = (XdrvMailbox.usridx ? XdrvMailbox.index - 1 : 0); - if (device_group_index < device_group_count) { - _SendDeviceGroupMessage(device_group_index, DGR_MSGTYPE_UPDATE_COMMAND); - ResponseCmndChar(XdrvMailbox.data); - } -} -#endif - -void CmndDevGroupShare(void) -{ - uint32_t parm[2] = { Settings.device_group_share_in, Settings.device_group_share_out }; - ParseParameters(2, parm); - Settings.device_group_share_in = parm[0]; - Settings.device_group_share_out = parm[1]; - Response_P(PSTR("{\"" D_CMND_DEVGROUP_SHARE "\":{\"In\":\"%X\",\"Out\":\"%X\"}}"), Settings.device_group_share_in, Settings.device_group_share_out); -} - -void CmndDevGroupStatus(void) -{ - DeviceGroupStatus((XdrvMailbox.usridx ? XdrvMailbox.index - 1 : 0)); -} -#endif - -void CmndSensor(void) -{ - XsnsCall(FUNC_COMMAND_SENSOR); -} - -void CmndDriver(void) -{ - XdrvCall(FUNC_COMMAND_DRIVER); -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_crash_recorder.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_crash_recorder.ino" -#ifdef ESP8266 - -const uint32_t crash_magic = 0x53415400; -const uint32_t crash_rtc_offset = 32; -const uint32_t crash_dump_max_len = 31; - - - - - - -extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) -{ - uint32_t addr_written = 0; - uint32_t value; - - for (uint32_t i = stack; i < stack_end; i += 4) { - value = *((uint32_t*) i); - if ((value >= 0x40000000) && (value < 0x40300000)) { - ESP.rtcUserMemoryWrite(crash_rtc_offset + addr_written, (uint32_t*)&value, sizeof(value)); - addr_written++; - if (addr_written >= crash_dump_max_len) { break; } - } - } - value = crash_magic + addr_written; - ESP.rtcUserMemoryWrite(crash_rtc_offset + crash_dump_max_len, (uint32_t*)&value, sizeof(value)); -} - - -void CmndCrash(void) -{ - volatile uint32_t dummy; - dummy = *((uint32_t*) 0x00000000); -} - - -void CmndWDT(void) -{ - volatile uint32_t dummy = 0; - while (1) { - dummy++; - } -} - - -void CmndBlockedLoop(void) -{ - while (1) { - delay(1000); - } -} - - -void CrashDumpClear(void) -{ - uint32_t value = 0; - ESP.rtcUserMemoryWrite(crash_rtc_offset + crash_dump_max_len, (uint32_t*)&value, sizeof(value)); -} - - - - - -bool CrashFlag(void) -{ - return ((ResetReason() == REASON_EXCEPTION_RST) || (ResetReason() == REASON_SOFT_WDT_RST) || oswatch_blocked_loop); -} - -void CrashDump(void) -{ - ResponseAppend_P(PSTR("{\"Exception\":%d,\"Reason\":\"%s\",\"EPC\":[\"%08x\",\"%08x\",\"%08x\"],\"EXCVADDR\":\"%08x\",\"DEPC\":\"%08x\""), - resetInfo.exccause, - GetResetReason().c_str(), - resetInfo.epc1, - resetInfo.epc2, - resetInfo.epc3, - resetInfo.excvaddr, - resetInfo.depc); - - uint32_t value; - ESP.rtcUserMemoryRead(crash_rtc_offset + crash_dump_max_len, (uint32_t*)&value, sizeof(value)); - if (crash_magic == (value & 0xFFFFFF00)) { - ResponseAppend_P(PSTR(",\"CallChain\":[")); - uint32_t count = value & 0x3F; - for (uint32_t i = 0; i < count; i++) { - ESP.rtcUserMemoryRead(crash_rtc_offset +i, (uint32_t*)&value, sizeof(value)); - if (i > 0) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(PSTR("\"%08x\""), value); - } - ResponseAppend_P(PSTR("]")); - } - - ResponseJsonEnd(); -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_device_groups.ino" -# 24 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_device_groups.ino" -#ifdef USE_DEVICE_GROUPS - - -#define DGR_MEMBER_TIMEOUT 45000 -#define DGR_ANNOUNCEMENT_INTERVAL 60000 - -extern bool udp_connected; - -struct device_group_member { - struct device_group_member * flink; - IPAddress ip_address; - uint16_t received_sequence; - uint16_t acked_sequence; - uint32_t unicast_count; -}; - -struct device_group { - uint32_t next_announcement_time; - uint32_t next_ack_check_time; - uint32_t member_timeout_time; - uint16_t last_full_status_sequence; - uint16_t message_length; - uint16_t ack_check_interval; - uint8_t message_header_length; - uint8_t initial_status_requests_remaining; - bool local; - char group_name[TOPSZ]; - char message[128]; - struct device_group_member * device_group_members; -#ifdef USE_DEVICE_GROUPS_SEND - uint8_t values_8bit[DGR_ITEM_LAST_8BIT]; - uint16_t values_16bit[DGR_ITEM_LAST_16BIT - DGR_ITEM_MAX_8BIT - 1]; - uint32_t values_32bit[DGR_ITEM_LAST_32BIT - DGR_ITEM_MAX_16BIT - 1]; -#endif -}; - -struct device_group * device_groups; -uint32_t next_check_time = 0; -uint16_t outgoing_sequence = 0; -bool device_groups_initialized = false; -bool device_groups_initialization_failed = false; -bool building_status_message = false; -bool processing_remote_device_message = false; -bool udp_was_connected = false; - -void DeviceGroupsInit(void) -{ - - - for (; device_group_count < MAX_DEV_GROUP_NAMES; device_group_count++) { - if (!*SettingsText(SET_DEV_GROUP_NAME1 + device_group_count)) break; - } - - - device_groups = (struct device_group *)calloc(device_group_count, sizeof(struct device_group)); - if (device_groups == nullptr) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error allocating %u-element device group array"), device_group_count); - device_groups_initialization_failed = true; - return; - } - - for (uint32_t device_group_index = 0; device_group_index < device_group_count; device_group_index++) { - struct device_group * device_group = &device_groups[device_group_index]; - strcpy(device_group->group_name, SettingsText(SET_DEV_GROUP_NAME1 + device_group_index)); - - - - if (!device_group->group_name[0]) { - strcpy(device_group->group_name, SettingsText(SET_MQTT_GRP_TOPIC)); - if (device_group_index) { - char str[10]; - sprintf_P(str, PSTR("%u"), device_group_index + 1); - strcat(device_group->group_name, str); - } - } - device_group->message_header_length = sprintf_P(device_group->message, PSTR("%s%s HTTP/1.1\n\n"), kDeviceGroupMessage, device_group->group_name); - device_group->last_full_status_sequence = -1; - } - - device_groups[0].local = true; - - - if (!Settings.device_group_share_in && !Settings.device_group_share_out) { - Settings.device_group_share_in = Settings.device_group_share_out = 0xffffffff; - } - - device_groups_initialized = true; -} - -char * IPAddressToString(const IPAddress& ip_address) -{ - static char buffer[16]; - sprintf_P(buffer, PSTR("%u.%u.%u.%u"), ip_address[0], ip_address[1], ip_address[2], ip_address[3]); - return buffer; -} - -char * BeginDeviceGroupMessage(struct device_group * device_group, uint16_t flags, bool hold_sequence = false) -{ - char * message_ptr = &device_group->message[device_group->message_header_length]; - if (!hold_sequence && !++outgoing_sequence) outgoing_sequence = 1; - *message_ptr++ = outgoing_sequence & 0xff; - *message_ptr++ = outgoing_sequence >> 8; - *message_ptr++ = flags & 0xff; - *message_ptr++ = flags >> 8; - return message_ptr; -} - - -bool DeviceGroupItemShared(bool incoming, uint8_t item) -{ - uint8_t mask = 0; - switch (item) { - case DGR_ITEM_LIGHT_BRI: - case DGR_ITEM_BRI_POWER_ON: - mask = DGR_SHARE_LIGHT_BRI; - break; - case DGR_ITEM_POWER: - mask = DGR_SHARE_POWER; - break; - case DGR_ITEM_LIGHT_SCHEME: - mask = DGR_SHARE_LIGHT_SCHEME; - break; - case DGR_ITEM_LIGHT_FIXED_COLOR: - case DGR_ITEM_LIGHT_CHANNELS: - mask = DGR_SHARE_LIGHT_COLOR; - break; - case DGR_ITEM_LIGHT_FADE: - case DGR_ITEM_LIGHT_SPEED: - mask = DGR_SHARE_LIGHT_FADE; - break; - case DGR_ITEM_BRI_PRESET_LOW: - case DGR_ITEM_BRI_PRESET_HIGH: - mask = DGR_SHARE_DIMMER_SETTINGS; - break; - } - return (!mask || ((incoming ? Settings.device_group_share_in : Settings.device_group_share_out) & mask)); -} - -void SendDeviceGroupPacket(IPAddress ip, char * packet, int len, const char * label) -{ - if (!ip) ip = IPAddress(239,255,255,250); - for (int attempt = 1; attempt <= 5; attempt++) { - if (PortUdp.beginPacket(ip, 1900)) { - PortUdp_write(packet, len); - if (PortUdp.endPacket()) return; - } - delay(10); - } - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error sending %s packet"), label); -} - -void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType message_type, ...) -{ - - if (!Settings.flag4.device_groups_enabled) return; - - - if (!udp_connected) return; - - - if (processing_remote_device_message && message_type != DGR_MSGTYPE_UPDATE_COMMAND) return; - - - struct device_group * device_group = &device_groups[device_group_index]; - - - if (device_group->initial_status_requests_remaining) return; - - - - - char * message_ptr = &device_group->message[device_group->message_header_length]; - if (message_type == DGR_MSGTYP_FULL_STATUS) { - - - - building_status_message = true; - - - if (!++outgoing_sequence) outgoing_sequence = 1; -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Building device group %s full status packet"), device_group->group_name); -#endif - device_group->message_length = 0; - SendDeviceGroupMessage(device_group_index, DGR_MSGTYP_PARTIAL_UPDATE, DGR_ITEM_POWER, power); - XdrvMailbox.index = device_group_index << 16; - XdrvMailbox.command_code = DGR_ITEM_STATUS; - XdrvMailbox.topic = (char *)&device_group_index; - XdrvCall(FUNC_DEVICE_GROUP_ITEM); - building_status_message = false; - - - if (!device_group->message_length) { - if (!--outgoing_sequence) outgoing_sequence = -1; - return; - } - device_group->last_full_status_sequence = outgoing_sequence; - - - *(message_ptr + 2) |= DGR_FLAG_FULL_STATUS; - } - - else { -#ifdef USE_DEVICE_GROUPS_SEND - bool use_command; - char oper; - uint32_t old_value; - char * delim_ptr; -#endif - bool shared; - uint8_t item; - uint32_t value; - char * value_ptr; - va_list ap; - -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Building device group %s packet"), device_group->group_name); -#endif - -#ifdef USE_DEVICE_GROUPS_SEND - use_command = (message_type == DGR_MSGTYPE_UPDATE_COMMAND); -#endif - value = 0; - if (message_type == DGR_MSGTYP_UPDATE_MORE_TO_COME) - value |= DGR_FLAG_MORE_TO_COME; - else if (message_type == DGR_MSGTYP_UPDATE_DIRECT) - value |= DGR_FLAG_DIRECT; -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">sequence=%u, flags=%u"), outgoing_sequence, value); -#endif - message_ptr = BeginDeviceGroupMessage(device_group, value, building_status_message || message_type == DGR_MSGTYP_PARTIAL_UPDATE); - - - - - - if (device_group->message_length) { - uint8_t item_array[32]; - int item_index = 0; - int kept_item_count = 0; - - -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) - value_ptr = XdrvMailbox.data; - else -#endif - va_start(ap, message_type); -#ifdef USE_DEVICE_GROUPS_SEND - while (use_command ? (item = strtoul(value_ptr, &delim_ptr, 0)) : (item = va_arg(ap, int))) { -#else - while ((item = va_arg(ap, int))) { -#endif - item_array[item_index++] = item; -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) { - if (!*delim_ptr) break; - if (*delim_ptr == '=') { - delim_ptr = strchr(delim_ptr, ' '); - if (!delim_ptr) break; - } - value_ptr = delim_ptr + 1; - } - else { -#endif - if (item <= DGR_ITEM_MAX_32BIT) - va_arg(ap, int); - else if (item <= DGR_ITEM_MAX_STRING) - va_arg(ap, char *); - else { - switch (item) { - case DGR_ITEM_LIGHT_CHANNELS: - va_arg(ap, uint8_t *); - break; - } - } -#ifdef USE_DEVICE_GROUPS_SEND - } -#endif - } -#ifdef USE_DEVICE_GROUPS_SEND - if (!use_command) va_end(ap); -#else - va_end(ap); -#endif - item_array[item_index] = 0; - - - - char * previous_message_ptr = message_ptr; - while (item = *previous_message_ptr++) { - - - for (item_index = 0; item_array[item_index]; item_index++) { - if (item_array[item_index] == item) break; - } - - - if (item_array[item_index]) { - if (item <= DGR_ITEM_MAX_32BIT) { - previous_message_ptr++; - if (item > DGR_ITEM_MAX_8BIT) { - previous_message_ptr++; - if (item > DGR_ITEM_MAX_16BIT) { - previous_message_ptr++; - previous_message_ptr++; - } - } - } - else if (item <= DGR_ITEM_MAX_STRING) - previous_message_ptr += *previous_message_ptr++; - else { - switch (item) { - case DGR_ITEM_LIGHT_CHANNELS: - previous_message_ptr += 5; - break; - } - } - } - - - else { - *message_ptr++ = item; - if (item <= DGR_ITEM_MAX_32BIT) { - *message_ptr++ = *previous_message_ptr++; - if (item > DGR_ITEM_MAX_8BIT) { - *message_ptr++ = *previous_message_ptr++; - if (item > DGR_ITEM_MAX_16BIT) { - *message_ptr++ = *previous_message_ptr++; - *message_ptr++ = *previous_message_ptr++; - } - } - } - else if (item <= DGR_ITEM_MAX_STRING) { - *message_ptr++ = value = *previous_message_ptr++; - memmove(message_ptr, previous_message_ptr, value); - previous_message_ptr += value; - message_ptr += value; - } - else { - switch (item) { - case DGR_ITEM_LIGHT_CHANNELS: - memmove(message_ptr, previous_message_ptr, 5); - previous_message_ptr += 5; - message_ptr += 5; - break; - } - } - kept_item_count++; - } - } -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%u items carried over from previous update"), kept_item_count); -#endif - } - - -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) - value_ptr = XdrvMailbox.data; - else -#endif - va_start(ap, message_type); -#ifdef USE_DEVICE_GROUPS_SEND - while (use_command ? (item = strtoul(value_ptr, &delim_ptr, 0)) : (item = va_arg(ap, int))) { -#else - while ((item = va_arg(ap, int))) { -#endif - - - shared = true; - if (!device_group_index) shared = DeviceGroupItemShared(false, item); - if (shared) *message_ptr++ = item; - -#ifdef USE_DEVICE_GROUPS_SEND - - if (use_command) value_ptr = (*delim_ptr == '=' ? delim_ptr + 1 : nullptr); -#endif - - - if (item <= DGR_ITEM_MAX_32BIT) { - -#ifdef USE_DEVICE_GROUPS_SEND - - - if (use_command) { - value = 0; - if (value_ptr) { - oper = 0; - if (*value_ptr == '@') { - oper = value_ptr[1]; - value_ptr += 2; - } - value = strtoul(value_ptr, nullptr, 0); - if (oper) { - old_value = (item <= DGR_ITEM_MAX_8BIT ? device_group->values_8bit[item] : (item <= DGR_ITEM_MAX_16BIT ? device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] : device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1])); - value = (oper == '+' ? old_value + value : (oper == '-' ? old_value - value : (oper == '^' ? old_value ^ (value ? value : 0xffffffff) : old_value))); - } - } - } - else -#endif - value = va_arg(ap, int); - - - if (shared) { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%u"), item, value); -#endif - *message_ptr++ = value & 0xff; - if (item > DGR_ITEM_MAX_8BIT) { -#ifdef USE_DEVICE_GROUPS_SEND - old_value = value; -#endif - value >>= 8; - *message_ptr++ = value & 0xff; - if (item > DGR_ITEM_MAX_16BIT) { - value >>= 8; - *message_ptr++ = value & 0xff; - value >>= 8; - - - if (item == DGR_ITEM_POWER) { - if (!value) - value = (device_group_index == 0 ? devices_present : 1); -#ifdef USE_DEVICE_GROUPS_SEND - else - old_value = old_value & 0xffffff; -#endif - } - - *message_ptr++ = value; -#ifdef USE_DEVICE_GROUPS_SEND - device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1] = old_value; -#endif - } -#ifdef USE_DEVICE_GROUPS_SEND - else { - device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] = old_value; - } -#endif - } -#ifdef USE_DEVICE_GROUPS_SEND - else { - device_group->values_8bit[item] = value; - } -#endif - } - } - - - else if (item <= DGR_ITEM_MAX_STRING) { -#ifdef USE_DEVICE_GROUPS_SEND - if (!use_command) -#endif - value_ptr = va_arg(ap, char *); - if (shared) { - value = (value_ptr ? strlen((const char *)value_ptr) : 0); -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%s"), item, value_ptr); -#endif - *message_ptr++ = value; - memcpy(message_ptr, value_ptr, value); - message_ptr += value; - } - } - - - else { - switch (item) { - case DGR_ITEM_LIGHT_CHANNELS: -#ifdef USE_DEVICE_GROUPS_SEND - if (use_command) { - if (shared) { - for (int i = 0; i < 5; i++) { - value = 0; - if (value_ptr) { - value = strtoul(value_ptr, &value_ptr, 0); - value_ptr = (*value_ptr == ',' ? value_ptr + 1 : nullptr); - } - *message_ptr++ = value; - } - } - } - else { -#endif - value_ptr = va_arg(ap, char *); - if (shared) { - memmove(message_ptr, value_ptr, 5); - message_ptr += 5; - } -#ifdef USE_DEVICE_GROUPS_SEND - } -#endif -#ifdef DEVICE_GROUPS_DEBUG - if (shared) AddLog_P2(LOG_LEVEL_DEBUG, PSTR(">item=%u, value=%u,%u,%u,%u,%u"), item, *(message_ptr - 5), *(message_ptr - 4), *(message_ptr - 3), *(message_ptr - 2), *(message_ptr - 1)); -#endif - break; - } - } - -#ifdef USE_DEVICE_GROUPS_SEND - - - if (use_command) { - if (!*delim_ptr) break; - if (*delim_ptr == '=') { - delim_ptr = strchr(delim_ptr, ' '); - if (!delim_ptr) break; - } - value_ptr = delim_ptr + 1; - } -#endif - } -#ifdef USE_DEVICE_GROUPS_SEND - if (!use_command) va_end(ap); -#else - va_end(ap); -#endif - - - *message_ptr++ = 0; - device_group->message_length = message_ptr - device_group->message; - - - if (building_status_message || message_type == DGR_MSGTYP_PARTIAL_UPDATE) return; - } - - -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending %u-byte device group %s packet via multicast, sequence=%u"), device_group->message_length, device_group->group_name, device_group->message[device_group->message_header_length] | device_group->message[device_group->message_header_length + 1] << 8); -#endif - SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, device_group->message_length, PSTR("Multicast")); - - uint32_t now = millis(); - if (message_type == DGR_MSGTYP_UPDATE_MORE_TO_COME) { - device_group->message_length = 0; - device_group->next_ack_check_time = 0; - } - else { - device_group->ack_check_interval = 100; - device_group->next_ack_check_time = now + device_group->ack_check_interval; - if (device_group->next_ack_check_time < next_check_time) next_check_time = device_group->next_ack_check_time; - device_group->member_timeout_time = now + DGR_MEMBER_TIMEOUT; - } - - device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL; - if (device_group->next_announcement_time < next_check_time) next_check_time = device_group->next_announcement_time; -} - -void ProcessDeviceGroupMessage(char * packet, int packet_length) -{ - - char * message_group_name = packet + sizeof(DEVICE_GROUP_MESSAGE) - 1; - char * message_ptr = strchr(message_group_name, ' '); - if (message_ptr == nullptr) return; - *message_ptr = 0; - - - struct device_group * device_group; - uint8_t device_group_index = 0; - for (;;) { - device_group = &device_groups[device_group_index]; - if (!strcmp(message_group_name, device_group->group_name)) break; - if (++device_group_index >= device_group_count) return; - } - *message_ptr++ = ' '; - - - IPAddress remote_ip = PortUdp.remoteIP(); - struct device_group_member * * flink = &device_group->device_group_members; - struct device_group_member * device_group_member; - for (;;) { - device_group_member = *flink; - if (!device_group_member) { - device_group_member = (struct device_group_member *)calloc(1, sizeof(struct device_group_member)); - if (device_group_member == nullptr) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error allocating device group member block")); - return; - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Adding member %s"), IPAddressToString(remote_ip)); - device_group_member->ip_address = remote_ip; - *flink = device_group_member; - break; - } - else if (device_group_member->ip_address == remote_ip) { - break; - } - flink = &device_group_member->flink; - } - - - message_ptr = strstr_P(message_ptr, PSTR("\n\n")); - if (message_ptr == nullptr) return; - message_ptr += 2; - - bool light_fade; - uint16_t flags; - uint16_t item; - uint16_t message_sequence; - int32_t value; - - - if (packet_length - (message_ptr - packet) < 4) goto badmsg; - message_sequence = *message_ptr++; - message_sequence |= *message_ptr++ << 8; - flags = *message_ptr++; - flags |= *message_ptr++ << 8; -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Received device group %s packet from %s: sequence=%u, flags=%u"), device_group->group_name, IPAddressToString(remote_ip), message_sequence, flags); -#endif - - - if (flags == DGR_FLAG_ANNOUNCEMENT) return; - - - - if (flags == DGR_FLAG_ACK) { - if (message_sequence > device_group_member->acked_sequence || device_group_member->acked_sequence - message_sequence < 64536) { - device_group_member->acked_sequence = message_sequence; - } -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("acked_sequence != device_group->last_full_status_sequence) { - _SendDeviceGroupMessage(device_group_index, DGR_MSGTYP_FULL_STATUS); - } -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("received_sequence) { - if (message_sequence == device_group_member->received_sequence || device_group_member->received_sequence - message_sequence > 64536) { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("received_sequence = message_sequence; - - - - processing_remote_device_message = true; -# 697 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_device_groups.ino" - XdrvMailbox.command = nullptr; - XdrvMailbox.index = flags | message_sequence << 16; - XdrvMailbox.topic = (char *)&device_group_index; - if (flags & (DGR_FLAG_MORE_TO_COME | DGR_FLAG_DIRECT)) skip_light_fade = true; - - for (;;) { - if (packet_length - (message_ptr - packet) < 1) goto badmsg; - item = *message_ptr++; - if (!item) break; - -#ifdef DEVICE_GROUPS_DEBUG - switch (item) { - case DGR_ITEM_LIGHT_FADE: - case DGR_ITEM_LIGHT_SPEED: - case DGR_ITEM_LIGHT_BRI: - case DGR_ITEM_LIGHT_SCHEME: - case DGR_ITEM_LIGHT_FIXED_COLOR: - case DGR_ITEM_BRI_PRESET_LOW: - case DGR_ITEM_BRI_PRESET_HIGH: - case DGR_ITEM_BRI_POWER_ON: - case DGR_ITEM_POWER: - case DGR_ITEM_LIGHT_CHANNELS: - break; - default: - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: ********** Invalid item=%u received from device group %s member %s"), item, device_group->group_name, IPAddressToString(remote_ip)); - } -#endif - - XdrvMailbox.command_code = item; - if (item <= DGR_ITEM_LAST_32BIT) { - value = *message_ptr++; - if (item > DGR_ITEM_MAX_8BIT) { - value |= *message_ptr++ << 8; - if (item > DGR_ITEM_MAX_16BIT) { - value |= *message_ptr++ << 16; - value |= *message_ptr++ << 24; -#ifdef USE_DEVICE_GROUPS_SEND - device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1] = (item == DGR_ITEM_POWER ? value & 0xffffff : value); -#endif - } -#ifdef USE_DEVICE_GROUPS_SEND - else { - device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] = value; - } -#endif - } -#ifdef USE_DEVICE_GROUPS_SEND - else { - device_group->values_8bit[item] = value; - } -#endif - -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("= packet_length - (message_ptr - packet)) goto badmsg; -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("local) { - uint8_t mask_devices = value >> 24; - if (mask_devices > devices_present) mask_devices = devices_present; - for (uint32_t i = 0; i < devices_present; i++) { - uint32_t mask = 1 << i; - bool on = (value & mask); - if (on != (power & mask)) ExecuteCommandPower(i + 1, (on ? POWER_ON : POWER_OFF), SRC_REMOTE); - } - } - } - XdrvCall(FUNC_DEVICE_GROUP_ITEM); - } - } - - XdrvMailbox.command_code = DGR_ITEM_EOL; - XdrvCall(FUNC_DEVICE_GROUP_ITEM); - skip_light_fade = false; - - processing_remote_device_message = false; -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("device_group_members; device_group_member; device_group_member = device_group_member->flink) { - snprintf(buffer, sizeof(buffer), PSTR("%s,{\"IPAddress\":\"%s\",\"ResendCount\":%u,\"LastRcvdSeq\":%u,\"LastAckedSeq\":%u}"), buffer, IPAddressToString(device_group_member->ip_address), device_group_member->unicast_count, device_group_member->received_sequence, device_group_member->acked_sequence); - member_count++; - } - Response_P(PSTR("{\"" D_CMND_DEVGROUPSTATUS "\":{\"Index\":%u,\"GroupName\":\"%s\",\"MessageSeq\":%u,\"MemberCount\":%d,\"Members\":[%s]}"), device_group_index, device_group->group_name, outgoing_sequence, member_count, &buffer[1]); - } -} - -void DeviceGroupsLoop(void) -{ - if (!Settings.flag4.device_groups_enabled) return; - if (udp_connected) { - uint32_t now = millis(); - - - if (!udp_was_connected) { - udp_was_connected = true; - - if (!device_groups_initialized) DeviceGroupsInit(); - if (device_groups_initialization_failed) return; - - - - next_check_time = now + 3000; - for (uint32_t device_group_index = 0; device_group_index < device_group_count; device_group_index++) { - device_group * device_group = &device_groups[device_group_index]; - device_group->message_length = BeginDeviceGroupMessage(device_group, DGR_FLAG_RESET | DGR_FLAG_STATUS_REQUEST) - device_group->message; - device_group->initial_status_requests_remaining = 10; - device_group->next_ack_check_time = next_check_time; - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: (Re)discovering device groups")); - } - - if (device_groups_initialization_failed) return; - - - if (next_check_time <= now) { -#ifdef DEVICE_GROUPS_DEBUG -AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), next_check_time, now); -#endif - next_check_time = now + DGR_ANNOUNCEMENT_INTERVAL * 2; - - for (uint32_t device_group_index = 0; device_group_index < device_group_count; device_group_index++) { - device_group * device_group = &device_groups[device_group_index]; - - - if (device_group->next_ack_check_time) { - - - if (device_group->next_ack_check_time <= now) { - - - if (device_group->initial_status_requests_remaining) { - if (--device_group->initial_status_requests_remaining) { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending initial status request for group %s"), device_group->group_name); -#endif - SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, device_group->message_length, PSTR("Initial")); - device_group->message[device_group->message_header_length + 2] = DGR_FLAG_STATUS_REQUEST; - device_group->next_ack_check_time = now + 200; - } - - - - else { - device_group->next_ack_check_time = 0; - _SendDeviceGroupMessage(device_group_index, DGR_MSGTYP_FULL_STATUS); - } - } - - - else { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Checking for ack's")); -#endif - bool acked = true; - struct device_group_member ** flink = &device_group->device_group_members; - struct device_group_member * device_group_member; - while ((device_group_member = *flink)) { - - - if (device_group_member->acked_sequence != outgoing_sequence) { - - - - if (device_group->member_timeout_time < now) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Removing member %s"), IPAddressToString(device_group_member->ip_address)); - *flink = device_group_member->flink; - free(device_group_member); - } - - - else { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending %u-byte device group %s packet via unicast to %s, sequence %u, last message acked=%u"), device_group->message_length, device_group->group_name, IPAddressToString(device_group_member->ip_address), outgoing_sequence, device_group_member->acked_sequence); -#endif - SendDeviceGroupPacket(device_group_member->ip_address, device_group->message, device_group->message_length, PSTR("Unicast")); - device_group_member->unicast_count++; - acked = false; - flink = &device_group_member->flink; - } - } - else { - flink = &device_group_member->flink; - } - } - - - - if (acked) { - device_group->next_ack_check_time = 0; - device_group->message_length = 0; - } - - - - - else { - device_group->ack_check_interval *= 2; - if (device_group->ack_check_interval > 5000) device_group->ack_check_interval = 5000; - device_group->next_ack_check_time = now + device_group->ack_check_interval; - } - } - } - - if (device_group->next_ack_check_time < next_check_time) next_check_time = device_group->next_ack_check_time; - } - - - - - - -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: next_announcement_time=%u, now=%u"), device_group->next_announcement_time, now); -#endif - if (device_group->next_announcement_time <= now) { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending device group %s announcement"), device_group->group_name); -#endif - SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT, true) - device_group->message, PSTR("Announcement")); - device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL + random(10000); - } - if (device_group->next_announcement_time < next_check_time) next_check_time = device_group->next_announcement_time; - } - } - } - else { - udp_was_connected = false; - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_esp32.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_esp32.ino" -#ifdef ESP32 - -#include -#include - -void SettingsErase(uint8_t type) -{ - if (1 == type) - { - } - else if (2 == type) - { - } - else if (3 == type) - { - } - - noInterrupts(); - nvs_handle handle; - nvs_open("main", NVS_READWRITE, &handle); - nvs_erase_all(handle); - nvs_commit(handle); - nvs_close(handle); - interrupts(); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " t=%d"), type); -} - -void SettingsLoad(const char *sNvsName, const char *sName, void *pSettings, unsigned nSettingsLen) -{ - noInterrupts(); - nvs_handle handle; - size_t size; - nvs_open(sNvsName, NVS_READONLY, &handle); - size = nSettingsLen; - nvs_get_blob(handle, sName, pSettings, &size); - nvs_close(handle); - interrupts(); -} - -void SettingsSave(const char *sNvsName, const char *sName, const void *pSettings, unsigned nSettingsLen) -{ - nvs_handle handle; - noInterrupts(); - nvs_open(sNvsName, NVS_READWRITE, &handle); - nvs_set_blob(handle, sName, pSettings, nSettingsLen); - nvs_commit(handle); - nvs_close(handle); - interrupts(); -} - -void ESP32_flashRead(uint32_t offset, uint32_t *data, size_t size) -{ - SettingsLoad("main", "Settings", data, size); -} - -void ESP32_flashReadHeader(uint32_t offset, uint32_t *data, size_t size) -{ - SettingsLoad("main", "SettingsH", data, size); -} - -void SettingsSaveMain(const void *pSettings, unsigned nSettingsLen) -{ - SettingsSave("main", "Settings", pSettings, nSettingsLen); -} -# 98 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_esp32.ino" -void SettingsLoadUpg(void *pSettings, unsigned nSettingsLen) -{ - SettingsLoad("upg", "Settings", pSettings, nSettingsLen); -} - -void SettingsLoadUpgH(void *pSettings, unsigned nSettingsLen) -{ - SettingsLoad("upg", "SettingsH", pSettings, nSettingsLen); -} - - - - -static bool bNetIsTimeSync = false; - -void SntpInit() -{ - bNetIsTimeSync = true; -} - -uint32_t SntpGetCurrentTimestamp(void) -{ - time_t now = 0; - if (bNetIsTimeSync || ntp_force_sync) - { - - - configTime(0, 0, SettingsText(SET_NTPSERVER1), SettingsText(SET_NTPSERVER2), SettingsText(SET_NTPSERVER3)); - bNetIsTimeSync = false; - ntp_force_sync = false; - } - time(&now); - return now; -} - - - - - -void CrashDump(void) -{ -} - -bool CrashFlag(void) -{ - return false; -} - -void CrashDumpClear(void) -{ -} -void CmndCrash(void) -{ - - - - -} - - -void CmndWDT(void) -{ - - - - - - -} - -void CmndBlockedLoop(void) -{ - - - - - -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_esptool.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_esptool.ino" -#ifdef ESP8266 -#define USE_ESPTOOL -#endif - -#ifdef USE_ESPTOOL - - - - - - - -#define READ_REG(REG) (*((volatile uint32_t *)(REG))) -#define WRITE_REG(REG,VAL) *((volatile uint32_t *)(REG)) = (VAL) -#define REG_SET_MASK(reg,mask) WRITE_REG((reg), (READ_REG(reg)|(mask))) - -#define SPI_BASE_REG 0x60000200 - -#define SPI_CMD_REG (SPI_BASE_REG + 0x00) -#define SPI_FLASH_RDSR (1<<27) -#define SPI_FLASH_SE (1<<24) -#define SPI_FLASH_BE (1<<23) -#define SPI_FLASH_WREN (1<<30) - -#define SPI_ADDR_REG (SPI_BASE_REG + 0x04) -#define SPI_CTRL_REG (SPI_BASE_REG + 0x08) -#define SPI_RD_STATUS_REG (SPI_BASE_REG + 0x10) -#define SPI_W0_REG (SPI_BASE_REG + 0x40) -#define SPI_EXT2_REG (SPI_BASE_REG + 0xF8) - -#define SPI_ST 0x7 - - -#define SECTORS_PER_BLOCK (FLASH_BLOCK_SIZE / SPI_FLASH_SEC_SIZE) - - -static const uint32_t STATUS_WIP_BIT = (1 << 0); - - -inline static void spi_wait_ready(void) -{ - while((READ_REG(SPI_EXT2_REG) & SPI_ST)) { } -} - - - -static bool spiflash_is_ready(void) -{ - spi_wait_ready(); - WRITE_REG(SPI_RD_STATUS_REG, 0); - WRITE_REG(SPI_CMD_REG, SPI_FLASH_RDSR); - while(READ_REG(SPI_CMD_REG) != 0) { } - uint32_t status_value = READ_REG(SPI_RD_STATUS_REG); - return (status_value & STATUS_WIP_BIT) == 0; -} - -static void spi_write_enable(void) -{ - while(!spiflash_is_ready()) { } - WRITE_REG(SPI_CMD_REG, SPI_FLASH_WREN); - while(READ_REG(SPI_CMD_REG) != 0) { } -} - -bool EsptoolEraseSector(uint32_t sector) -{ - spi_write_enable(); - spi_wait_ready(); - - WRITE_REG(SPI_ADDR_REG, (sector * SPI_FLASH_SEC_SIZE) & 0xffffff); - WRITE_REG(SPI_CMD_REG, SPI_FLASH_SE); - while(READ_REG(SPI_CMD_REG) != 0) { } - while(!spiflash_is_ready()) { } - - return true; -} - -void EsptoolErase(uint32_t start_sector, uint32_t end_sector) -{ - int next_erase_sector = start_sector; - int remaining_erase_sector = end_sector - start_sector; - - while (remaining_erase_sector > 0) { - spi_write_enable(); - - uint32_t command = SPI_FLASH_SE; - uint32_t sectors_to_erase = 1; - if (remaining_erase_sector >= SECTORS_PER_BLOCK && - next_erase_sector % SECTORS_PER_BLOCK == 0) { - command = SPI_FLASH_BE; - sectors_to_erase = SECTORS_PER_BLOCK; - } - uint32_t addr = next_erase_sector * SPI_FLASH_SEC_SIZE; - - spi_wait_ready(); - WRITE_REG(SPI_ADDR_REG, addr & 0xffffff); - WRITE_REG(SPI_CMD_REG, command); - while(READ_REG(SPI_CMD_REG) != 0) { } - remaining_erase_sector -= sectors_to_erase; - next_erase_sector += sectors_to_erase; - - while (!spiflash_is_ready()) { } - yield(); - OsWatchLoop(); - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_features.ino" -# 24 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_features.ino" -void GetFeatures(void) -{ - feature_drv1 = 0x00000000; - -#ifdef USE_ENERGY_MARGIN_DETECTION - feature_drv1 |= 0x00000001; -#endif -#ifdef USE_LIGHT - feature_drv1 |= 0x00000002; -#endif -#ifdef USE_I2C - feature_drv1 |= 0x00000004; -#endif -#ifdef USE_SPI - feature_drv1 |= 0x00000008; -#endif -#ifdef USE_DISCOVERY - feature_drv1 |= 0x00000010; -#endif -#ifdef USE_ARDUINO_OTA - feature_drv1 |= 0x00000020; -#endif -#ifdef USE_MQTT_TLS - feature_drv1 |= 0x00000040; -#endif -#ifdef USE_WEBSERVER - feature_drv1 |= 0x00000080; -#endif -#ifdef WEBSERVER_ADVERTISE - feature_drv1 |= 0x00000100; -#endif -#ifdef USE_EMULATION_HUE - feature_drv1 |= 0x00000200; -#endif - - feature_drv1 |= 0x00000400; - - - - - - - -#ifdef MQTT_HOST_DISCOVERY - feature_drv1 |= 0x00002000; -#endif -#ifdef USE_ARILUX_RF - feature_drv1 |= 0x00004000; -#endif -#if defined(USE_LIGHT) && defined(USE_WS2812) - feature_drv1 |= 0x00008000; -#endif -#ifdef USE_WS2812_DMA - feature_drv1 |= 0x00010000; -#endif -#if defined(USE_IR_REMOTE) || defined(USE_IR_REMOTE_FULL) - feature_drv1 |= 0x00020000; -#endif -#ifdef USE_IR_HVAC - feature_drv1 |= 0x00040000; -#endif -#ifdef USE_IR_RECEIVE - feature_drv1 |= 0x00080000; -#endif -#ifdef USE_DOMOTICZ - feature_drv1 |= 0x00100000; -#endif -#ifdef USE_DISPLAY - feature_drv1 |= 0x00200000; -#endif -#ifdef USE_HOME_ASSISTANT - feature_drv1 |= 0x00400000; -#endif -#ifdef USE_SERIAL_BRIDGE - feature_drv1 |= 0x00800000; -#endif -#ifdef USE_TIMERS - feature_drv1 |= 0x01000000; -#endif -#ifdef USE_SUNRISE - feature_drv1 |= 0x02000000; -#endif -#ifdef USE_TIMERS_WEB - feature_drv1 |= 0x04000000; -#endif -#ifdef USE_RULES - feature_drv1 |= 0x08000000; -#endif -#ifdef USE_KNX - feature_drv1 |= 0x10000000; -#endif -#ifdef USE_WPS - feature_drv1 |= 0x20000000; -#endif -#ifdef USE_SMARTCONFIG - feature_drv1 |= 0x40000000; -#endif -#ifdef USE_ENERGY_POWER_LIMIT - feature_drv1 |= 0x80000000; -#endif - - - - feature_drv2 = 0x00000000; - -#ifdef USE_CONFIG_OVERRIDE - feature_drv2 |= 0x00000001; -#endif -#ifdef FIRMWARE_MINIMAL - feature_drv2 |= 0x00000002; -#endif -#ifdef FIRMWARE_SENSORS - feature_drv2 |= 0x00000004; -#endif -#ifdef FIRMWARE_CLASSIC - feature_drv2 |= 0x00000008; -#endif -#ifdef FIRMWARE_KNX_NO_EMULATION - feature_drv2 |= 0x00000010; -#endif -#ifdef USE_DISPLAY_MODES1TO5 - feature_drv2 |= 0x00000020; -#endif -#ifdef USE_DISPLAY_GRAPH - feature_drv2 |= 0x00000040; -#endif -#ifdef USE_DISPLAY_LCD - feature_drv2 |= 0x00000080; -#endif -#ifdef USE_DISPLAY_SSD1306 - feature_drv2 |= 0x00000100; -#endif -#ifdef USE_DISPLAY_MATRIX - feature_drv2 |= 0x00000200; -#endif -#ifdef USE_DISPLAY_ILI9341 - feature_drv2 |= 0x00000400; -#endif -#ifdef USE_DISPLAY_EPAPER_29 - feature_drv2 |= 0x00000800; -#endif -#ifdef USE_DISPLAY_SH1106 - feature_drv2 |= 0x00001000; -#endif -#ifdef USE_MP3_PLAYER - feature_drv2 |= 0x00002000; -#endif -#ifdef USE_PCA9685 - feature_drv2 |= 0x00004000; -#endif -#if defined(USE_LIGHT) && defined(USE_TUYA_MCU) - feature_drv2 |= 0x00008000; -#endif -#ifdef USE_RC_SWITCH - feature_drv2 |= 0x00010000; -#endif -#if defined(USE_LIGHT) && defined(USE_ARMTRONIX_DIMMERS) - feature_drv2 |= 0x00020000; -#endif -#if defined(USE_LIGHT) && defined(USE_SM16716) - feature_drv2 |= 0x00040000; -#endif -#ifdef USE_SCRIPT - feature_drv2 |= 0x00080000; -#endif -#ifdef USE_EMULATION_WEMO - feature_drv2 |= 0x00100000; -#endif -#ifdef USE_SONOFF_IFAN - feature_drv2 |= 0x00200000; -#endif -#ifdef USE_ZIGBEE - feature_drv2 |= 0x00400000; -#endif -#ifdef NO_EXTRA_4K_HEAP - feature_drv2 |= 0x00800000; -#endif -#ifdef VTABLES_IN_IRAM - feature_drv2 |= 0x01000000; -#endif -#ifdef VTABLES_IN_DRAM - feature_drv2 |= 0x02000000; -#endif -#ifdef VTABLES_IN_FLASH - feature_drv2 |= 0x04000000; -#endif -#ifdef PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH - feature_drv2 |= 0x08000000; -#endif -#ifdef PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY - feature_drv2 |= 0x10000000; -#endif -#ifdef PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH - feature_drv2 |= 0x20000000; -#endif -#ifdef DEBUG_THEO - feature_drv2 |= 0x40000000; -#endif -#ifdef USE_DEBUG_DRIVER - feature_drv2 |= 0x80000000; -#endif - - - - feature_sns1 = 0x00000000; - -#ifdef USE_COUNTER - feature_sns1 |= 0x00000001; -#endif -#ifdef USE_ADC_VCC - feature_sns1 |= 0x00000002; -#endif -#ifdef USE_ENERGY_SENSOR - feature_sns1 |= 0x00000004; -#endif -#ifdef USE_PZEM004T - feature_sns1 |= 0x00000008; -#endif -#ifdef USE_DS18B20 - feature_sns1 |= 0x00000010; -#endif -#ifdef USE_DS18x20_LEGACY - feature_sns1 |= 0x00000020; -#endif -#ifdef USE_DS18x20 - feature_sns1 |= 0x00000040; -#endif -#ifdef USE_DHT - feature_sns1 |= 0x00000080; -#endif -#ifdef USE_SHT - feature_sns1 |= 0x00000100; -#endif -#ifdef USE_HTU - feature_sns1 |= 0x00000200; -#endif -#ifdef USE_BMP - feature_sns1 |= 0x00000400; -#endif -#ifdef USE_BME680 - feature_sns1 |= 0x00000800; -#endif -#ifdef USE_BH1750 - feature_sns1 |= 0x00001000; -#endif -#ifdef USE_VEML6070 - feature_sns1 |= 0x00002000; -#endif -#ifdef USE_ADS1115_I2CDEV - feature_sns1 |= 0x00004000; -#endif -#ifdef USE_ADS1115 - feature_sns1 |= 0x00008000; -#endif -#ifdef USE_INA219 - feature_sns1 |= 0x00010000; -#endif -#ifdef USE_SHT3X - feature_sns1 |= 0x00020000; -#endif -#ifdef USE_MHZ19 - feature_sns1 |= 0x00040000; -#endif -#ifdef USE_TSL2561 - feature_sns1 |= 0x00080000; -#endif -#ifdef USE_SENSEAIR - feature_sns1 |= 0x00100000; -#endif -#ifdef USE_PMS5003 - feature_sns1 |= 0x00200000; -#endif -#ifdef USE_MGS - feature_sns1 |= 0x00400000; -#endif -#ifdef USE_NOVA_SDS - feature_sns1 |= 0x00800000; -#endif -#ifdef USE_SGP30 - feature_sns1 |= 0x01000000; -#endif -#ifdef USE_SR04 - feature_sns1 |= 0x02000000; -#endif -#ifdef USE_SDM120 - feature_sns1 |= 0x04000000; -#endif -#ifdef USE_SI1145 - feature_sns1 |= 0x08000000; -#endif -#ifdef USE_SDM630 - feature_sns1 |= 0x10000000; -#endif -#ifdef USE_LM75AD - feature_sns1 |= 0x20000000; -#endif -#ifdef USE_APDS9960 - feature_sns1 |= 0x40000000; -#endif -#ifdef USE_TM1638 - feature_sns1 |= 0x80000000; -#endif - - - - feature_sns2 = 0x00000000; - -#ifdef USE_MCP230xx - feature_sns2 |= 0x00000001; -#endif -#ifdef USE_MPR121 - feature_sns2 |= 0x00000002; -#endif -#ifdef USE_CCS811 - feature_sns2 |= 0x00000004; -#endif -#ifdef USE_MPU6050 - feature_sns2 |= 0x00000008; -#endif -#ifdef USE_MCP230xx_OUTPUT - feature_sns2 |= 0x00000010; -#endif -#ifdef USE_MCP230xx_DISPLAYOUTPUT - feature_sns2 |= 0x00000020; -#endif -#ifdef USE_HLW8012 - feature_sns2 |= 0x00000040; -#endif -#ifdef USE_CSE7766 - feature_sns2 |= 0x00000080; -#endif -#ifdef USE_MCP39F501 - feature_sns2 |= 0x00000100; -#endif -#ifdef USE_PZEM_AC - feature_sns2 |= 0x00000200; -#endif -#ifdef USE_DS3231 - feature_sns2 |= 0x00000400; -#endif -#ifdef USE_HX711 - feature_sns2 |= 0x00000800; -#endif -#ifdef USE_PZEM_DC - feature_sns2 |= 0x00001000; -#endif -#if defined(USE_TX20_WIND_SENSOR) || defined(USE_TX23_WIND_SENSOR) - feature_sns2 |= 0x00002000; -#endif -#ifdef USE_MGC3130 - feature_sns2 |= 0x00004000; -#endif -#ifdef USE_RF_SENSOR - feature_sns2 |= 0x00008000; -#endif -#ifdef USE_THEO_V2 - feature_sns2 |= 0x00010000; -#endif -#ifdef USE_ALECTO_V2 - feature_sns2 |= 0x00020000; -#endif -#ifdef USE_AZ7798 - feature_sns2 |= 0x00040000; -#endif -#ifdef USE_MAX31855 - feature_sns2 |= 0x00080000; -#endif -#ifdef USE_PN532_HSU - feature_sns2 |= 0x00100000; -#endif -#ifdef USE_MAX44009 - feature_sns2 |= 0x00200000; -#endif -#ifdef USE_SCD30 - feature_sns2 |= 0x00400000; -#endif -#ifdef USE_HRE - feature_sns2 |= 0x00800000; -#endif -#ifdef USE_ADE7953 - feature_sns2 |= 0x01000000; -#endif -#ifdef USE_SPS30 - feature_sns2 |= 0x02000000; -#endif -#ifdef USE_VL53L0X - feature_sns2 |= 0x04000000; -#endif -#ifdef USE_MLX90614 - feature_sns2 |= 0x08000000; -#endif -#ifdef USE_MAX31865 - feature_sns2 |= 0x10000000; -#endif -#ifdef USE_CHIRP - feature_sns2 |= 0x20000000; -#endif -#ifdef USE_SOLAX_X1 - feature_sns2 |= 0x40000000; -#endif -#ifdef USE_PAJ7620 - feature_sns2 |= 0x80000000; -#endif - - - - feature5 = 0x00000000; - -#ifdef USE_BUZZER - feature5 |= 0x00000001; -#endif -#ifdef USE_RDM6300 - feature5 |= 0x00000002; -#endif -#ifdef USE_IBEACON - feature5 |= 0x00000004; -#endif -#ifdef USE_SML_M - feature5 |= 0x00000008; -#endif -#ifdef USE_INA226 - feature5 |= 0x00000010; -#endif -#ifdef USE_A4988_STEPPER - feature5 |= 0x00000020; -#endif -#ifdef USE_DDS2382 - feature5 |= 0x00000040; -#endif -#ifdef USE_SM2135 - feature5 |= 0x00000080; -#endif -#ifdef USE_SHUTTER - feature5 |= 0x00000100; -#endif -#ifdef USE_PCF8574 - feature5 |= 0x00000200; -#endif -#ifdef USE_DDSU666 - feature5 |= 0x00000400; -#endif -#ifdef USE_DEEPSLEEP - feature5 |= 0x00000800; -#endif -#ifdef USE_SONOFF_SC - feature5 |= 0x00001000; -#endif -#ifdef USE_SONOFF_RF - feature5 |= 0x00002000; -#endif -#ifdef USE_SONOFF_L1 - feature5 |= 0x00004000; -#endif -#ifdef USE_EXS_DIMMER - feature5 |= 0x00008000; -#endif -#ifdef USE_ARDUINO_SLAVE - feature5 |= 0x00010000; -#endif -#ifdef USE_HIH6 - feature5 |= 0x00020000; -#endif -#ifdef USE_HPMA - feature5 |= 0x00040000; -#endif -#ifdef USE_TSL2591 - feature5 |= 0x00080000; -#endif -#ifdef USE_DHT12 - feature5 |= 0x00100000; -#endif -#ifdef USE_DS1624 - feature5 |= 0x00200000; -#endif -#ifdef USE_GPS - feature5 |= 0x00400000; -#endif -#ifdef USE_HOTPLUG - feature5 |= 0x00800000; -#endif -#ifdef USE_NRF24 - feature5 |= 0x01000000; -#endif -#ifdef USE_MIBLE - feature5 |= 0x02000000; -#endif -#ifdef USE_HM10 - feature5 |= 0x04000000; -#endif -#ifdef USE_LE01MR - feature5 |= 0x08000000; -#endif -#ifdef USE_AHT1x - feature5 |= 0x10000000; -#endif -#ifdef USE_WEMOS_MOTOR_V1 - feature5 |= 0x20000000; -#endif -#ifdef USE_DEVICE_GROUPS - feature5 |= 0x40000000; -#endif -#ifdef USE_PWM_DIMMER - feature5 |= 0x80000000; -#endif - - - - feature6 = 0x00000000; - -#ifdef USE_KEELOQ - feature6 |= 0x00000001; -#endif -#ifdef USE_HRXL - feature6 |= 0x00000002; -#endif -#ifdef USE_SONOFF_D1 - feature6 |= 0x00000004; -#endif -#ifdef USE_HDC1080 - feature6 |= 0x00000008; -#endif -#ifdef USE_IAQ - feature6 |= 0x00000010; -#endif -#ifdef USE_DISPLAY_SEVENSEG - feature6 |= 0x00000020; -#endif -#ifdef USE_AS3935 - feature6 |= 0x00000040; -#endif -#ifdef USE_PING - feature6 |= 0x00000080; -#endif -#ifdef USE_THERMOSTAT - feature6 |= 0x00000100; -#endif -# 589 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_features.ino" -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_flash_log.ino" -# 39 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_flash_log.ino" -#ifdef USE_FLOG -#ifdef ESP8266 - -class FLOG - -#define MAGIC_WORD_FL 0x464c - -{ - -struct header_t{ - uint16_t magic_word; - uint16_t padding; - uint32_t physical_start_sector:10; - uint32_t number:10; - uint32_t buf_pointer:12; - }; - -private: -void _readSector(uint8_t one_sector); -void _eraseSector(uint8_t one_sector); -void _writeSector(uint8_t one_sector); -void _clearBuffer(void); -void _searchSaves(void); -void _findFirstErasedSector(void); -void _showBuffer(void); -void _initBuffer(void); -void _saveBufferToSector(void); -header_t _saved_header; - -public: - uint32_t size; - uint32_t start; - uint32_t end; - uint16_t num_sectors; - - uint16_t first_erased_sector; - uint16_t current_sector; - - uint16_t bytes_left; - uint16_t sectors_left; - - uint8_t mode = 0; - bool found_saved_data = false; - bool ready = false; - bool running_download = false; - bool recording = false; - - union sector_t{ - uint32_t dword_buffer[FLASH_SECTOR_SIZE/4]; - uint8_t byte_buffer[FLASH_SECTOR_SIZE]; - header_t header; - } sector; - - void init(void); - void addToBuffer(uint8_t src[], uint32_t size); - void startRecording(bool append); - void stopRecording(void); - - typedef void (*CallbackNoArgs) (); - typedef void (*CallbackWithArgs) (uint8_t *_record); - - void startDownload(size_t size, CallbackNoArgs sendHeader, CallbackWithArgs sendRecord, CallbackNoArgs sendFooter); -}; - -extern "C" uint32_t _SPIFFS_start; -extern "C" uint32_t _FS_start; - - - - -void FLOG::init(void) -{ -DEBUG_SENSOR_LOG(PSTR("FLOG: init ...")); -size = ESP.getSketchSize(); - -start = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) || defined(ARDUINO_ESP8266_RELEASE_2_5_0) || defined(ARDUINO_ESP8266_RELEASE_2_5_1) || defined(ARDUINO_ESP8266_RELEASE_2_5_2) -end = (uint32_t)&_SPIFFS_start - 0x40200000; -#else -end = (uint32_t)&_FS_start - 0x40200000; -#endif -num_sectors = (end - start)/FLASH_SECTOR_SIZE; -DEBUG_SENSOR_LOG(PSTR("FLOG: size: 0x%lx, start: 0x%lx, end: 0x%lx, num_sectors(dec): %lu"), size, start, end, num_sectors ); -_findFirstErasedSector(); -if(first_erased_sector == 0xffff){ - _eraseSector(0); - first_erased_sector = 0; -} -_searchSaves(); -_initBuffer(); -ready = true; -} -# 143 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_flash_log.ino" -void FLOG::_readSector(uint8_t one_sector){ - DEBUG_SENSOR_LOG(PSTR("FLOG: read sector number: %u" ), one_sector); - ESP.flashRead(start+(one_sector * FLASH_SECTOR_SIZE),(uint32_t *)§or.dword_buffer, FLASH_SECTOR_SIZE); -} - - - - - -void FLOG::_eraseSector(uint8_t one_sector){ - DEBUG_SENSOR_LOG(PSTR("FLOG: erasing sector number: %u" ), one_sector); - ESP.flashEraseSector((start/FLASH_SECTOR_SIZE)+one_sector); -} - - - - - -void FLOG::_writeSector(uint8_t one_sector){ - DEBUG_SENSOR_LOG(PSTR("FLOG: write buffer to sector number: %u" ), one_sector); - ESP.flashWrite(start+(one_sector * FLASH_SECTOR_SIZE),(uint32_t *)§or.dword_buffer, FLASH_SECTOR_SIZE); -} - - - - -void FLOG::_clearBuffer(){ - for (uint32_t i = sizeof(sector.header)/4; i<(sizeof(sector.dword_buffer)/4); i++){ - sector.dword_buffer[i] = 0; - } - sector.header.buf_pointer = sizeof(sector.header); - -} - - - - -void FLOG::_saveBufferToSector(){ - DEBUG_SENSOR_LOG(PSTR("FLOG: write buffer to current sector: %u" ),current_sector); - _writeSector(current_sector); - if(current_sector == num_sectors){ - current_sector = 0; - } - else{ - current_sector++; - } - _eraseSector(current_sector); - _clearBuffer(); - sector.header.number++; - DEBUG_SENSOR_LOG(PSTR("FLOG: new sector header number: %u" ),sector.header.number); -} - - - - - -void FLOG::_findFirstErasedSector(){ - for (uint32_t i = 0; i3){ - break; - } - } -} - - - - - - - -void FLOG::addToBuffer(uint8_t src[], uint32_t size){ - if(mode == 0){ - if(sector.header.number == num_sectors && !ready){ - return; - } - } - if((FLASH_SECTOR_SIZE-sector.header.buf_pointer-sizeof(sector.header))>size){ - - - - memcpy(sector.byte_buffer + sector.header.buf_pointer, src, size); - sector.header.buf_pointer+=size; - - } - else{ - DEBUG_SENSOR_LOG(PSTR("FLOG: save buffer to flash sector: %u"), current_sector); - DEBUG_SENSOR_LOG(PSTR("FLOG: current buf_pointer: %u"), sector.header.buf_pointer); - _saveBufferToSector(); - sectors_left++; - - if((FLASH_SECTOR_SIZE-sector.header.buf_pointer-sizeof(sector.header))>size){ - memcpy(sector.byte_buffer + sector.header.buf_pointer, src, size); - sector.header.buf_pointer+=size; - } - } -} - - - - - - -void FLOG::startRecording(bool append){ - if(recording){ - DEBUG_SENSOR_LOG(PSTR("FLOG: already recording")); - return; - } - recording = true; - DEBUG_SENSOR_LOG(PSTR("FLOG: start recording")); - _initBuffer(); - if(!found_saved_data) { - append = false; - } - if(append){ - sector.header.number = _saved_header.number+1; - sector.header.physical_start_sector = _saved_header.physical_start_sector; - } - else{ - sector.header.physical_start_sector = (uint16_t)first_erased_sector; - found_saved_data = false; - sectors_left = 0; - } - } - - - - - -void FLOG::stopRecording(void){ - _saveBufferToSector(); - _findFirstErasedSector(); - _searchSaves(); - _initBuffer(); - recording = false; - found_saved_data = true; - } -# 382 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_flash_log.ino" - void FLOG::startDownload(size_t size, CallbackNoArgs sendHeader, CallbackWithArgs sendRecord, CallbackNoArgs sendFooter){ - - _readSector(sector.header.physical_start_sector); - uint32_t next_sector = sector.header.physical_start_sector; - bytes_left = sector.header.buf_pointer - sizeof(sector.header); - DEBUG_SENSOR_LOG(PSTR("FLOG: create file for download, will process %u bytes"), bytes_left); - running_download = true; - - sendHeader(); - - while(sectors_left){ - DEBUG_SENSOR_LOG(PSTR("FLOG: next sector: %u"), next_sector); - - uint32_t k = sizeof(sector.header); - while(bytes_left){ - - uint8_t *_record_start = (uint8_t*)§or.byte_buffer[k]; - - sendRecord(_record_start); - if(k%128 == 0){ - - OsWatchLoop(); - delay(ssleep); - } - k+=size; - if(bytes_left>7){ - bytes_left-=size; - } - else{ - bytes_left = 0; - DEBUG_SENSOR_LOG(PSTR("FLOG: Flog->bytes_left not dividable by 8 ??????")); - } - } - next_sector++; - if(next_sector>num_sectors){ - next_sector = 0; - } - sectors_left--; - _readSector(next_sector); - bytes_left = sector.header.buf_pointer - sizeof(sector.header); - OsWatchLoop(); - delay(ssleep); - } - running_download = false; - - sendFooter(); - - _searchSaves(); - _initBuffer(); - } - - #endif - #endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -# 23 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -float fmodf(float x, float y) -{ - - union {float f; uint32_t i;} ux = {x}, uy = {y}; - int ex = ux.i>>23 & 0xff; - int ey = uy.i>>23 & 0xff; - uint32_t sx = ux.i & 0x80000000; - uint32_t i; - uint32_t uxi = ux.i; - - if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) - return (x*y)/(x*y); - if (uxi<<1 <= uy.i<<1) { - if (uxi<<1 == uy.i<<1) - return 0*x; - return x; - } - - - if (!ex) { - for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); - uxi <<= -ex + 1; - } else { - uxi &= -1U >> 9; - uxi |= 1U << 23; - } - if (!ey) { - for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); - uy.i <<= -ey + 1; - } else { - uy.i &= -1U >> 9; - uy.i |= 1U << 23; - } - - - for (; ex > ey; ex--) { - i = uxi - uy.i; - if (i >> 31 == 0) { - if (i == 0) - return 0*x; - uxi = i; - } - uxi <<= 1; - } - i = uxi - uy.i; - if (i >> 31 == 0) { - if (i == 0) - return 0*x; - uxi = i; - } - for (; uxi>>23 == 0; uxi <<= 1, ex--); - - - if (ex > 0) { - uxi -= 1U << 23; - uxi |= (uint32_t)ex << 23; - } else { - uxi >>= -ex + 1; - } - uxi |= sx; - ux.i = uxi; - return ux.f; -} - - -double FastPrecisePow(double a, double b) -{ - - - int e = abs((int)b); - union { - double d; - int x[2]; - } u = { a }; - u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447); - u.x[0] = 0; - - - double r = 1.0; - while (e) { - if (e & 1) { - r *= a; - } - a *= a; - e >>= 1; - } - return r * u.d; -} - -float FastPrecisePowf(const float x, const float y) -{ - - return (float)FastPrecisePow(x, y); -} - -double TaylorLog(double x) -{ - - - if (x <= 0.0) { return NAN; } - double z = (x + 1) / (x - 1); - double step = ((x - 1) * (x - 1)) / ((x + 1) * (x + 1)); - double totalValue = 0; - double powe = 1; - for (uint32_t count = 0; count < 10; count++) { - z *= step; - double y = (1 / powe) * z; - totalValue = totalValue + y; - powe = powe + 2; - } - totalValue *= 2; -# 144 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" - return totalValue; -} -# 154 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -inline float sinf(float x) { return sin_52(x); } -inline float cosf(float x) { return cos_52(x); } -inline float tanf(float x) { return tan_56(x); } -inline float atanf(float x) { return atan_66(x); } -inline float asinf(float x) { return asinf1(x); } -inline float acosf(float x) { return acosf1(x); } -inline float sqrtf(float x) { return sqrt1(x); } -inline float powf(float x, float y) { return FastPrecisePow(x, y); } - - -double const f_pi = 3.1415926535897932384626433; -double const f_twopi = 2.0 * f_pi; -double const f_two_over_pi = 2.0 / f_pi; -double const f_halfpi = f_pi / 2.0; -double const f_threehalfpi = 3.0 * f_pi / 2.0; -double const f_four_over_pi = 4.0 / f_pi; -double const f_qtrpi = f_pi / 4.0; -double const f_sixthpi = f_pi / 6.0; -double const f_tansixthpi = tan(f_sixthpi); -double const f_twelfthpi = f_pi / 12.0; -double const f_tantwelfthpi = tan(f_twelfthpi); -float const f_180pi = 180 / f_pi; -# 194 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -float cos_52s(float x) -{ - const float c1 = 0.9999932946; - const float c2 = -0.4999124376; - const float c3 = 0.0414877472; - const float c4 = -0.0012712095; - - float x2 = x * x; - return (c1 + x2 * (c2 + x2 * (c3 + c4 * x2))); -} - - - - - - -float cos_52(float x) -{ - x = fmodf(x, f_twopi); - if (x < 0) { x = -x; } - int quad = int(x * (float)f_two_over_pi); - switch (quad) { - case 0: return cos_52s(x); - case 1: return -cos_52s((float)f_pi - x); - case 2: return -cos_52s(x-(float)f_pi); - case 3: return cos_52s((float)f_twopi - x); - } -} - - - - -float sin_52(float x) -{ - return cos_52((float)f_halfpi - x); -} -# 247 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -float tan_56s(float x) -{ - const float c1 = -3.16783027; - const float c2 = 0.134516124; - const float c3 = -4.033321984; - - float x2 = x * x; - return (x * (c1 + c2 * x2) / (c3 + x2)); -} -# 267 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -float tan_56(float x) -{ - x = fmodf(x, (float)f_twopi); - int octant = int(x * (float)f_four_over_pi); - switch (octant){ - case 0: return tan_56s(x * (float)f_four_over_pi); - case 1: return 1.0f / tan_56s(((float)f_halfpi - x) * (float)f_four_over_pi); - case 2: return -1.0f / tan_56s((x-(float)f_halfpi) * (float)f_four_over_pi); - case 3: return - tan_56s(((float)f_pi - x) * (float)f_four_over_pi); - case 4: return tan_56s((x-(float)f_pi) * (float)f_four_over_pi); - case 5: return 1.0f / tan_56s(((float)f_threehalfpi - x) * (float)f_four_over_pi); - case 6: return -1.0f / tan_56s((x-(float)f_threehalfpi) * (float)f_four_over_pi); - case 7: return - tan_56s(((float)f_twopi - x) * (float)f_four_over_pi); - } -} -# 296 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -float atan_66s(float x) -{ - const float c1 = 1.6867629106; - const float c2 = 0.4378497304; - const float c3 = 1.6867633134; - - float x2 = x * x; - return (x * (c1 + x2 * c2) / (c3 + x2)); -} - - - - - -float atan_66(float x) -{ - float y; - bool complement= false; - bool region= false; - bool sign= false; - - if (x < 0) { - x = -x; - sign = true; - } - if (x > 1.0) { - x = 1.0 / x; - complement = true; - } - if (x > (float)f_tantwelfthpi) { - x = (x - (float)f_tansixthpi) / (1 + (float)f_tansixthpi * x); - region = true; - } - - y = atan_66s(x); - if (region) { y += (float)f_sixthpi; } - if (complement) { y = (float)f_halfpi-y; } - if (sign) { y = -y; } - return (y); -} - -float asinf1(float x) -{ - float d = 1.0f - x * x; - if (d < 0.0f) { return NAN; } - return 2 * atan_66(x / (1 + sqrt1(d))); -} - -float acosf1(float x) -{ - float d = 1.0f - x * x; - if (d < 0.0f) { return NAN; } - float y = asinf1(sqrt1(d)); - if (x >= 0.0f) { - return y; - } else { - return (float)f_pi - y; - } -} - - -float sqrt1(const float x) -{ - union { - int i; - float x; - } u; - u.x = x; - u.i = (1 << 29) + (u.i >> 1) - (1 << 22); - - - - - u.x = u.x + x / u.x; - u.x = 0.25f * u.x + x / u.x; - - return u.x; -} -# 387 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_float.ino" -uint16_t changeUIntScale(uint16_t inum, uint16_t ifrom_min, uint16_t ifrom_max, - uint16_t ito_min, uint16_t ito_max) { - - if (ifrom_min >= ifrom_max) { - if (ito_min > ito_max) { - return ito_max; - } else { - return ito_min; - } - } - - uint32_t num = inum; - uint32_t from_min = ifrom_min; - uint32_t from_max = ifrom_max; - uint32_t to_min = ito_min; - uint32_t to_max = ito_max; - - - num = (num > from_max ? from_max : (num < from_min ? from_min : num)); - - - if (to_min > to_max) { - - num = (from_max - num) + from_min; - to_min = ito_max; - to_max = ito_min; - } - - uint32_t numerator = (num - from_min) * (to_max - to_min); - uint32_t result; - if (numerator >= 0x80000000L) { - - result = numerator / (from_max - from_min) + to_min; - } else { - result = (((numerator * 2) / (from_max - from_min)) + 1) / 2 + to_min; - } - return (uint32_t) (result > to_max ? to_max : (result < to_min ? to_min : result)); -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_legacy_cores.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_legacy_cores.ino" -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - - - - - -void* memchr(const void* ptr, int value, size_t num) -{ - unsigned char *p = (unsigned char*)ptr; - while (num--) { - if (*p != (unsigned char)value) { - p++; - } else { - return p; - } - } - return 0; -} - - - -size_t strcspn(const char *str1, const char *str2) -{ - size_t ret = 0; - while (*str1) { - if (strchr(str2, *str1)) { - return ret; - } else { - str1++; - ret++; - } - } - return ret; -} - - - -char* strpbrk(const char *s1, const char *s2) -{ - while(*s1) { - if (strchr(s2, *s1++)) { - return (char*)--s1; - } - } - return 0; -} - - - -#ifndef __LONG_LONG_MAX__ -#define __LONG_LONG_MAX__ 9223372036854775807LL -#endif -#ifndef ULLONG_MAX -#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1) -#endif - -unsigned long long strtoull(const char *__restrict nptr, char **__restrict endptr, int base) -{ - const char *s = nptr; - char c; - do { c = *s++; } while (isspace((unsigned char)c)); - - int neg = 0; - if (c == '-') { - neg = 1; - c = *s++; - } else { - if (c == '+') { - c = *s++; - } - } - - if ((base == 0 || base == 16) && (c == '0') && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) { base = (c == '0') ? 8 : 10; } - - unsigned long long acc = 0; - int any = 0; - if (base > 1 && base < 37) { - unsigned long long cutoff = ULLONG_MAX / base; - int cutlim = ULLONG_MAX % base; - for ( ; ; c = *s++) { - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'A' && c <= 'Z') - c -= 'A' - 10; - else if (c >= 'a' && c <= 'z') - c -= 'a' - 10; - else - break; - - if (c >= base) - break; - - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = ULLONG_MAX; - } - else if (any && neg) { - acc = -acc; - } - } - - if (endptr != nullptr) { *endptr = (char *)(any ? s - 1 : nptr); } - - return acc; -} - -#endif - - - -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) || defined(ARDUINO_ESP8266_RELEASE_2_5_0) || defined(ARDUINO_ESP8266_RELEASE_2_5_1) || defined(ARDUINO_ESP8266_RELEASE_2_5_2) - - - - - -void* memmove_P(void *dest, const void *src, size_t n) -{ - if (src > (void*)0x40000000) { - return memcpy_P(dest, src, n); - } else { - return memmove(dest, src, n); - } -} - -#endif -# 167 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_legacy_cores.ino" -void resetPins() -{ -# 178 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_legacy_cores.ino" -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_rotary.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_rotary.ino" -#ifdef USE_LIGHT - -#ifdef ROTARY_V1 - - - - -struct ROTARY { - unsigned long debounce = 0; - uint8_t present = 0; - uint8_t state = 0; - uint8_t position = 128; - uint8_t last_position = 128; - uint8_t interrupts_in_use_count = 0; - uint8_t changed = 0; -} Rotary; - - - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 -void update_rotary(void) ICACHE_RAM_ATTR; -#endif - -void update_rotary(void) -{ - if (MI_DESK_LAMP == my_module_type) { - if (LightPowerIRAM()) { - - - - - uint8_t s = Rotary.state & 3; - if (digitalRead(pin[GPIO_ROT1A])) { s |= 4; } - if (digitalRead(pin[GPIO_ROT1B])) { s |= 8; } - switch (s) { - case 0: case 5: case 10: case 15: - break; - case 1: case 7: case 8: case 14: - Rotary.position++; break; - case 2: case 4: case 11: case 13: - Rotary.position--; break; - case 3: case 12: - Rotary.position = Rotary.position + 2; break; - default: - Rotary.position = Rotary.position - 2; break; - } - Rotary.state = (s >> 2); - } - } -} - -bool RotaryButtonPressed(void) -{ - if ((MI_DESK_LAMP == my_module_type) && (Rotary.changed) && LightPower()) { - Rotary.changed = 0; - return true; - } - return false; -} - -void RotaryInit(void) -{ - Rotary.present = 0; - if ((pin[GPIO_ROT1A] < 99) && (pin[GPIO_ROT1B] < 99)) { - Rotary.present++; - pinMode(pin[GPIO_ROT1A], INPUT_PULLUP); - pinMode(pin[GPIO_ROT1B], INPUT_PULLUP); - - - - - if ((pin[GPIO_ROT1A] < 6) || (pin[GPIO_ROT1A] > 11)) { - attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT1A]), update_rotary, CHANGE); - Rotary.interrupts_in_use_count++; - } - if ((pin[GPIO_ROT1B] < 6) || (pin[GPIO_ROT1B] > 11)) { - attachInterrupt(digitalPinToInterrupt(pin[GPIO_ROT1B]), update_rotary, CHANGE); - Rotary.interrupts_in_use_count++; - } - } -} - - - - - -void RotaryHandler(void) -{ - if (Rotary.interrupts_in_use_count < 2) { - noInterrupts(); - update_rotary(); - } else { - noInterrupts(); - } - if (Rotary.last_position != Rotary.position) { - if (MI_DESK_LAMP == my_module_type) { - if (Button.hold_timer[0]) { - Rotary.changed = 1; - - int16_t t = LightGetColorTemp(); - t = t + (Rotary.position - Rotary.last_position); - if (t < 153) { - t = 153; - } - if (t > 500) { - t = 500; - } - DEBUG_CORE_LOG(PSTR("ROT: " D_CMND_COLORTEMPERATURE " %d"), Rotary.position - Rotary.last_position); - LightSetColorTemp((uint16_t)t); - } else { - int8_t d = Settings.light_dimmer; - d = d + (Rotary.position - Rotary.last_position); - if (d < 1) { - d = 1; - } - if (d > 100) { - d = 100; - } - DEBUG_CORE_LOG(PSTR("ROT: " D_CMND_DIMMER " %d"), Rotary.position - Rotary.last_position); - - LightSetDimmer((uint8_t)d); - Settings.light_dimmer = d; - } - } - Rotary.last_position = 128; - Rotary.position = 128; - } - interrupts(); -} - -void RotaryLoop(void) -{ - if (Rotary.present) { - if (TimeReached(Rotary.debounce)) { - SetNextTimeInterval(Rotary.debounce, Settings.button_debounce); - RotaryHandler(); - } - } -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_rtc.ino" -# 25 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_rtc.ino" -const uint32_t SECS_PER_MIN = 60UL; -const uint32_t SECS_PER_HOUR = 3600UL; -const uint32_t SECS_PER_DAY = SECS_PER_HOUR * 24UL; -const uint32_t MINS_PER_HOUR = 60UL; - -#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) - -extern "C" { -#include "sntp.h" -} -#include - -Ticker TickerRtc; - -static const uint8_t kDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -static const char kMonthNamesEnglish[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; - -struct RTC { - uint32_t utc_time = 0; - uint32_t local_time = 0; - uint32_t daylight_saving_time = 0; - uint32_t standard_time = 0; - uint32_t ntp_time = 0; - uint32_t midnight = 0; - uint32_t restart_time = 0; - int32_t time_timezone = 0; - uint8_t ntp_sync_minute = 0; - bool midnight_now = false; - bool user_time_entry = false; -} Rtc; - -uint32_t UtcTime(void) -{ - return Rtc.utc_time; -} - -uint32_t LocalTime(void) -{ - return Rtc.local_time; -} - -uint32_t Midnight(void) -{ - return Rtc.midnight; -} - -bool MidnightNow(void) -{ - if (Rtc.midnight_now) { - Rtc.midnight_now = false; - return true; - } - return false; -} - -bool IsDst(void) -{ - if (Rtc.time_timezone == Settings.toffset[1]) { - return true; - } - return false; -} - -String GetBuildDateAndTime(void) -{ - - char bdt[21]; - char *p; - char mdate[] = __DATE__; - char *smonth = mdate; - int day = 0; - int year = 0; - - - uint8_t i = 0; - for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(nullptr, " ", &p)) { - switch (i++) { - case 0: - smonth = str; - break; - case 1: - day = atoi(str); - break; - case 2: - year = atoi(str); - } - } - int month = (strstr(kMonthNamesEnglish, smonth) -kMonthNamesEnglish) /3 +1; - snprintf_P(bdt, sizeof(bdt), PSTR("%d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%s"), year, month, day, __TIME__); - return String(bdt); -} - -String GetMinuteTime(uint32_t minutes) -{ - char tm[6]; - snprintf_P(tm, sizeof(tm), PSTR("%02d:%02d"), minutes / 60, minutes % 60); - - return String(tm); -} - -String GetTimeZone(void) -{ - char tz[7]; - snprintf_P(tz, sizeof(tz), PSTR("%+03d:%02d"), Rtc.time_timezone / 60, abs(Rtc.time_timezone % 60)); - - return String(tz); -} - -String GetDuration(uint32_t time) -{ - char dt[16]; - - TIME_T ut; - BreakTime(time, ut); - - - - - - - snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second); - - return String(dt); -} - -String GetDT(uint32_t time) -{ - - - char dt[20]; - TIME_T tmpTime; - - BreakTime(time, tmpTime); - snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), - tmpTime.year +1970, tmpTime.month, tmpTime.day_of_month, tmpTime.hour, tmpTime.minute, tmpTime.second); - - return String(dt); -} -# 175 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_rtc.ino" -String GetDateAndTime(uint8_t time_type) -{ - - uint32_t time = Rtc.local_time; - - switch (time_type) { - case DT_UTC: - time = Rtc.utc_time; - break; - - - - case DT_DST: - time = Rtc.daylight_saving_time; - break; - case DT_STD: - time = Rtc.standard_time; - break; - case DT_RESTART: - if (Rtc.restart_time == 0) { - return ""; - } - time = Rtc.restart_time; - break; - case DT_ENERGY: - time = Settings.energy_kWhtotal_time; - break; - case DT_BOOTCOUNT: - time = Settings.bootcount_reset_time; - break; - } - String dt = GetDT(time); - if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { - dt += GetTimeZone(); - } - return dt; -} - -uint32_t UpTime(void) -{ - if (Rtc.restart_time) { - return Rtc.utc_time - Rtc.restart_time; - } else { - return uptime; - } -} - -uint32_t MinutesUptime(void) -{ - return (UpTime() / 60); -} - -String GetUptime(void) -{ - return GetDuration(UpTime()); -} - -uint32_t MinutesPastMidnight(void) -{ - uint32_t minutes = 0; - - if (RtcTime.valid) { - minutes = (RtcTime.hour *60) + RtcTime.minute; - } - return minutes; -} - -void BreakTime(uint32_t time_input, TIME_T &tm) -{ - - - - - uint8_t year; - uint8_t month; - uint8_t month_length; - uint32_t time; - unsigned long days; - - time = time_input; - tm.second = time % 60; - time /= 60; - tm.minute = time % 60; - time /= 60; - tm.hour = time % 24; - time /= 24; - tm.days = time; - tm.day_of_week = ((time + 4) % 7) + 1; - - year = 0; - days = 0; - while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { - year++; - } - tm.year = year; - - days -= LEAP_YEAR(year) ? 366 : 365; - time -= days; - tm.day_of_year = time; - - for (month = 0; month < 12; month++) { - if (1 == month) { - if (LEAP_YEAR(year)) { - month_length = 29; - } else { - month_length = 28; - } - } else { - month_length = kDaysInMonth[month]; - } - - if (time >= month_length) { - time -= month_length; - } else { - break; - } - } - strlcpy(tm.name_of_month, kMonthNames + (month *3), 4); - tm.month = month + 1; - tm.day_of_month = time + 1; - tm.valid = (time_input > START_VALID_TIME); -} - -uint32_t MakeTime(TIME_T &tm) -{ - - - - int i; - uint32_t seconds; - - - seconds = tm.year * (SECS_PER_DAY * 365); - for (i = 0; i < tm.year; i++) { - if (LEAP_YEAR(i)) { - seconds += SECS_PER_DAY; - } - } - - - for (i = 1; i < tm.month; i++) { - if ((2 == i) && LEAP_YEAR(tm.year)) { - seconds += SECS_PER_DAY * 29; - } else { - seconds += SECS_PER_DAY * kDaysInMonth[i-1]; - } - } - seconds+= (tm.day_of_month - 1) * SECS_PER_DAY; - seconds+= tm.hour * SECS_PER_HOUR; - seconds+= tm.minute * SECS_PER_MIN; - seconds+= tm.second; - return seconds; -} - -uint32_t RuleToTime(TimeRule r, int yr) -{ - TIME_T tm; - uint32_t t; - uint8_t m; - uint8_t w; - - m = r.month; - w = r.week; - if (0 == w) { - if (++m > 12) { - m = 1; - yr++; - } - w = 1; - } - - tm.hour = r.hour; - tm.minute = 0; - tm.second = 0; - tm.day_of_month = 1; - tm.month = m; - tm.year = yr - 1970; - t = MakeTime(tm); - BreakTime(t, tm); - t += (7 * (w - 1) + (r.dow - tm.day_of_week + 7) % 7) * SECS_PER_DAY; - if (0 == r.week) { - t -= 7 * SECS_PER_DAY; - } - return t; -} - -void RtcSecond(void) -{ - TIME_T tmpTime; - - if (!Rtc.user_time_entry && !global_state.wifi_down) { - uint8_t uptime_minute = (uptime / 60) % 60; - if ((Rtc.ntp_sync_minute > 59) && (uptime_minute > 2)) { - Rtc.ntp_sync_minute = 1; - } - uint8_t offset = (uptime < 30) ? RtcTime.second : (((ESP_getChipId() & 0xF) * 3) + 3) ; - if ( (((offset == RtcTime.second) && ( (RtcTime.year < 2016) || - (Rtc.ntp_sync_minute == uptime_minute))) || - ntp_force_sync ) ) { - Rtc.ntp_time = sntp_get_current_timestamp(); - if (Rtc.ntp_time > START_VALID_TIME) { - ntp_force_sync = false; - Rtc.utc_time = Rtc.ntp_time; - Rtc.ntp_sync_minute = 60; - if (Rtc.restart_time == 0) { - Rtc.restart_time = Rtc.utc_time - uptime; - } - BreakTime(Rtc.utc_time, tmpTime); - RtcTime.year = tmpTime.year + 1970; - Rtc.daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); - Rtc.standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); - - - PrepLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: " D_UTC_TIME " %s, " D_DST_TIME " %s, " D_STD_TIME " %s"), - GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str()); - - if (Rtc.local_time < START_VALID_TIME) { - rules_flag.time_init = 1; - } else { - rules_flag.time_set = 1; - } - } else { - Rtc.ntp_sync_minute++; - } - } - } - - Rtc.utc_time++; - Rtc.local_time = Rtc.utc_time; - if (Rtc.local_time > START_VALID_TIME) { - int16_t timezone_minutes = Settings.timezone_minutes; - if (Settings.timezone < 0) { timezone_minutes *= -1; } - Rtc.time_timezone = (Settings.timezone * SECS_PER_HOUR) + (timezone_minutes * SECS_PER_MIN); - if (99 == Settings.timezone) { - int32_t dstoffset = Settings.toffset[1] * SECS_PER_MIN; - int32_t stdoffset = Settings.toffset[0] * SECS_PER_MIN; - if (Settings.tflag[1].hemis) { - - if ((Rtc.utc_time >= (Rtc.standard_time - dstoffset)) && (Rtc.utc_time < (Rtc.daylight_saving_time - stdoffset))) { - Rtc.time_timezone = stdoffset; - } else { - Rtc.time_timezone = dstoffset; - } - } else { - - if ((Rtc.utc_time >= (Rtc.daylight_saving_time - stdoffset)) && (Rtc.utc_time < (Rtc.standard_time - dstoffset))) { - Rtc.time_timezone = dstoffset; - } else { - Rtc.time_timezone = stdoffset; - } - } - } - Rtc.local_time += Rtc.time_timezone; - Rtc.time_timezone /= 60; - if (!Settings.energy_kWhtotal_time) { - Settings.energy_kWhtotal_time = Rtc.local_time; - } - if (Settings.bootcount_reset_time < START_VALID_TIME) { - Settings.bootcount_reset_time = Rtc.local_time; - } - } - - BreakTime(Rtc.local_time, RtcTime); - if (RtcTime.valid) { - if (!Rtc.midnight) { - Rtc.midnight = Rtc.local_time - (RtcTime.hour * 3600) - (RtcTime.minute * 60) - RtcTime.second; - } - if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second) { - Rtc.midnight = Rtc.local_time; - Rtc.midnight_now = true; - } - } - - RtcTime.year += 1970; -} - -void RtcSetTime(uint32_t epoch) -{ - if (epoch < START_VALID_TIME) { - Rtc.user_time_entry = false; - ntp_force_sync = true; - sntp_init(); - } else { - sntp_stop(); - Rtc.user_time_entry = true; - Rtc.utc_time = epoch -1; - } - RtcSecond(); -} - -void RtcInit(void) -{ - sntp_setservername(0, SettingsText(SET_NTPSERVER1)); - sntp_setservername(1, SettingsText(SET_NTPSERVER2)); - sntp_setservername(2, SettingsText(SET_NTPSERVER3)); - sntp_stop(); - sntp_set_timezone(0); - sntp_init(); - Rtc.utc_time = 0; - BreakTime(Rtc.utc_time, RtcTime); - TickerRtc.attach(1, RtcSecond); -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_static_buffer.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_static_buffer.ino" -typedef struct SBuffer_impl { - uint16_t size; - uint16_t len; - uint8_t buf[]; -} SBuffer_impl; - - - -typedef class SBuffer { - -protected: - SBuffer(void) { - - } - -public: - SBuffer(const size_t size) { - _buf = (SBuffer_impl*) new char[size+4]; - _buf->size = size; - _buf->len = 0; - - } - - inline size_t getSize(void) const { return _buf->size; } - inline size_t size(void) const { return _buf->size; } - inline size_t getLen(void) const { return _buf->len; } - inline size_t len(void) const { return _buf->len; } - inline uint8_t *getBuffer(void) const { return _buf->buf; } - inline uint8_t *buf(size_t i = 0) const { return &_buf->buf[i]; } - inline char *charptr(size_t i = 0) const { return (char*) &_buf->buf[i]; } - - virtual ~SBuffer(void) { - delete[] _buf; - } - - inline void setLen(const size_t len) { - uint16_t old_len = _buf->len; - _buf->len = (len <= _buf->size) ? len : _buf->size; - if (old_len < _buf->len) { - memset((void*) &_buf->buf[old_len], 0, _buf->len - old_len); - } - } - - void set8(const size_t offset, const uint8_t data) { - if (offset < _buf->len) { - _buf->buf[offset] = data; - } - } - - size_t add8(const uint8_t data) { - if (_buf->len < _buf->size) { - _buf->buf[_buf->len++] = data; - } - return _buf->len; - } - size_t add16(const uint16_t data) { - if (_buf->len < _buf->size - 1) { - _buf->buf[_buf->len++] = data; - _buf->buf[_buf->len++] = data >> 8; - } - return _buf->len; - } - size_t add32(const uint32_t data) { - if (_buf->len < _buf->size - 3) { - _buf->buf[_buf->len++] = data; - _buf->buf[_buf->len++] = data >> 8; - _buf->buf[_buf->len++] = data >> 16; - _buf->buf[_buf->len++] = data >> 24; - } - return _buf->len; - } - size_t add64(const uint64_t data) { - if (_buf->len < _buf->size - 7) { - _buf->buf[_buf->len++] = data; - _buf->buf[_buf->len++] = data >> 8; - _buf->buf[_buf->len++] = data >> 16; - _buf->buf[_buf->len++] = data >> 24; - _buf->buf[_buf->len++] = data >> 32; - _buf->buf[_buf->len++] = data >> 40; - _buf->buf[_buf->len++] = data >> 48; - _buf->buf[_buf->len++] = data >> 56; - } - return _buf->len; - } - - size_t addBuffer(const SBuffer &buf2) { - if (len() + buf2.len() <= size()) { - for (uint32_t i = 0; i < buf2.len(); i++) { - _buf->buf[_buf->len++] = buf2.buf()[i]; - } - } - return _buf->len; - } - - size_t addBuffer(const uint8_t *buf2, size_t len2) { - if ((buf2) && (len() + len2 <= size())) { - for (uint32_t i = 0; i < len2; i++) { - _buf->buf[_buf->len++] = pgm_read_byte(&buf2[i]); - } - } - return _buf->len; - } - - size_t addBuffer(const char *buf2, size_t len2) { - if ((buf2) && (len() + len2 <= size())) { - for (uint32_t i = 0; i < len2; i++) { - _buf->buf[_buf->len++] = pgm_read_byte(&buf2[i]); - } - } - return _buf->len; - } - - uint8_t get8(size_t offset) const { - if (offset < _buf->len) { - return _buf->buf[offset]; - } else { - return 0; - } - } - uint8_t read8(const size_t offset) const { - if (offset < len()) { - return _buf->buf[offset]; - } - return 0; - } - uint16_t get16(const size_t offset) const { - if (offset < len() - 1) { - return _buf->buf[offset] | (_buf->buf[offset+1] << 8); - } - return 0; - } - uint32_t get32(const size_t offset) const { - if (offset < len() - 3) { - return _buf->buf[offset] | (_buf->buf[offset+1] << 8) | - (_buf->buf[offset+2] << 16) | (_buf->buf[offset+3] << 24); - } - return 0; - } - uint64_t get64(const size_t offset) const { - if (offset < len() - 7) { - return (uint64_t)_buf->buf[offset] | ((uint64_t)_buf->buf[offset+1] << 8) | - ((uint64_t)_buf->buf[offset+2] << 16) | ((uint64_t)_buf->buf[offset+3] << 24) | - ((uint64_t)_buf->buf[offset+4] << 32) | ((uint64_t)_buf->buf[offset+5] << 40) | - ((uint64_t)_buf->buf[offset+6] << 48) | ((uint64_t)_buf->buf[offset+7] << 56); - } - return 0; - } - - - inline size_t strlen(const size_t offset) const { - return strnlen((const char*) &_buf->buf[offset], len() - offset); - } - - size_t strlen_s(const size_t offset) const { - size_t slen = this->strlen(offset); - if (slen == len() - offset) { - return 0; - } else { - return slen; - } - } - - SBuffer subBuffer(const size_t start, size_t len) const { - if (start >= _buf->len) { - len = 0; - } else if (start + len > _buf->len) { - len = _buf->len - start; - } - - SBuffer buf2(len); - memcpy(buf2.buf(), buf()+start, len); - buf2._buf->len = len; - return buf2; - } - - static SBuffer SBufferFromHex(const char *hex, size_t len) { - size_t buf_len = (len + 3) / 2; - SBuffer buf2(buf_len); - uint8_t val; - - for (; len > 1; len -= 2) { - val = asc2byte(*hex++) << 4; - val |= asc2byte(*hex++); - buf2.add8(val); - } - return buf2; - } - -protected: - - static uint8_t asc2byte(char chr) { - uint8_t rVal = 0; - if (isdigit(chr)) { rVal = chr - '0'; } - else if (chr >= 'A' && chr <= 'F') { rVal = chr + 10 - 'A'; } - else if (chr >= 'a' && chr <= 'f') { rVal = chr + 10 - 'a'; } - return rVal; - } - - static void unHex(const char* in, uint8_t *out, size_t len) { - } - -protected: - SBuffer_impl * _buf; - -} SBuffer; - -typedef class PreAllocatedSBuffer : public SBuffer { - -public: - PreAllocatedSBuffer(const size_t size, void * buffer) { - _buf = (SBuffer_impl*) buffer; - _buf->size = size - 4; - _buf->len = 0; - } - - ~PreAllocatedSBuffer(void) { - - _buf = nullptr; - } -} PreAllocatedSBuffer; -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_statistics.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_statistics.ino" -#define USE_STATS_CODE - -#ifdef USE_STATS_CODE - - - - -String GetStatistics(void) -{ - char data[40]; - snprintf_P(data, sizeof(data), PSTR(",\"CR\":\"%d/%d\""), GetSettingsTextLen(), settings_text_size); - return String(data); -} - -#else - -String GetStatistics(void) -{ - return String(""); -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_switch.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_switch.ino" -#define SWITCH_V3 -#ifdef SWITCH_V3 - - - - - - -const uint8_t SWITCH_PROBE_INTERVAL = 10; - -#include - -Ticker TickerSwitch; - -struct SWITCH { - unsigned long debounce = 0; - uint16_t no_pullup_mask = 0; - uint8_t state[MAX_SWITCHES] = { 0 }; - uint8_t last_state[MAX_SWITCHES]; - uint8_t hold_timer[MAX_SWITCHES] = { 0 }; - uint8_t virtual_state[MAX_SWITCHES]; - uint8_t present = 0; -} Switch; - - - -void SwitchPullupFlag(uint16 switch_bit) -{ - bitSet(Switch.no_pullup_mask, switch_bit); -} - -void SwitchSetVirtual(uint32_t index, uint8_t state) -{ - Switch.virtual_state[index] = state; -} - -uint8_t SwitchGetVirtual(uint32_t index) -{ - return Switch.virtual_state[index]; -} - -uint8_t SwitchLastState(uint32_t index) -{ - return Switch.last_state[index]; -} - -bool SwitchState(uint32_t index) -{ - uint32_t switchmode = Settings.switchmode[index]; - return ((FOLLOW_INV == switchmode) || - (PUSHBUTTON_INV == switchmode) || - (PUSHBUTTONHOLD_INV == switchmode) || - (FOLLOWMULTI_INV == switchmode) || - (PUSHHOLDMULTI_INV == switchmode) || - (PUSHON_INV == switchmode) - ) ^ Switch.last_state[index]; -} - - - -void SwitchProbe(void) -{ - if (uptime < 4) { return; } - - uint8_t state_filter = Settings.switch_debounce / SWITCH_PROBE_INTERVAL; - uint8_t force_high = (Settings.switch_debounce % 50) &1; - uint8_t force_low = (Settings.switch_debounce % 50) &2; - - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if (pin[GPIO_SWT1 +i] < 99) { - - if (1 == digitalRead(pin[GPIO_SWT1 +i])) { - - if (force_high) { - if (1 == Switch.virtual_state[i]) { - Switch.state[i] = state_filter; - } - } - - if (Switch.state[i] < state_filter) { - Switch.state[i]++; - if (state_filter == Switch.state[i]) { - Switch.virtual_state[i] = 1; - } - } - } else { - - if (force_low) { - if (0 == Switch.virtual_state[i]) { - Switch.state[i] = 0; - } - } - - if (Switch.state[i] > 0) { - Switch.state[i]--; - if (0 == Switch.state[i]) { - Switch.virtual_state[i] = 0; - } - } - } - } - } - TickerSwitch.attach_ms(SWITCH_PROBE_INTERVAL, SwitchProbe); -} - -void SwitchInit(void) -{ - Switch.present = 0; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - Switch.last_state[i] = 1; - if (pin[GPIO_SWT1 +i] < 99) { - Switch.present++; - pinMode(pin[GPIO_SWT1 +i], bitRead(Switch.no_pullup_mask, i) ? INPUT : ((16 == pin[GPIO_SWT1 +i]) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); - Switch.last_state[i] = digitalRead(pin[GPIO_SWT1 +i]); - } - Switch.virtual_state[i] = Switch.last_state[i]; - } - if (Switch.present) { TickerSwitch.attach_ms(SWITCH_PROBE_INTERVAL, SwitchProbe); } -} - - - - - -void SwitchHandler(uint8_t mode) -{ - if (uptime < 4) { return; } - - uint16_t loops_per_second = 1000 / Settings.switch_debounce; - - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if ((pin[GPIO_SWT1 +i] < 99) || (mode)) { - uint8_t button = Switch.virtual_state[i]; - uint8_t switchflag = POWER_TOGGLE +1; - - if (Switch.hold_timer[i]) { - Switch.hold_timer[i]--; - if (0 == Switch.hold_timer[i]) { - - switch (Settings.switchmode[i]) { - case TOGGLEMULTI: - switchflag = POWER_TOGGLE; - break; - case FOLLOWMULTI: - switchflag = button &1; - break; - case FOLLOWMULTI_INV: - switchflag = ~button &1; - break; - case PUSHHOLDMULTI: - if (NOT_PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 25; - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); - } else { - SendKey(KEY_SWITCH, i +1, POWER_CLEAR); - } - break; - case PUSHHOLDMULTI_INV: - if (PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 25; - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); - } else { - SendKey(KEY_SWITCH, i +1, POWER_CLEAR); - } - break; - default: - SendKey(KEY_SWITCH, i +1, POWER_HOLD); - break; - } - } - } - - if (button != Switch.last_state[i]) { - switch (Settings.switchmode[i]) { - case TOGGLE: - case PUSHBUTTON_TOGGLE: - switchflag = POWER_TOGGLE; - break; - case FOLLOW: - switchflag = button &1; - break; - case FOLLOW_INV: - switchflag = ~button &1; - break; - case PUSHBUTTON: - - if (PRESSED == button) { - switchflag = POWER_TOGGLE; - } - break; - case PUSHBUTTON_INV: - - if (NOT_PRESSED == button) { - switchflag = POWER_TOGGLE; - } - break; - case PUSHBUTTONHOLD: - - if (PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - - if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) { - Switch.hold_timer[i] = 0; - switchflag = POWER_TOGGLE; - } - break; - case PUSHBUTTONHOLD_INV: - - if (NOT_PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - - if ((PRESSED == button) && (Switch.hold_timer[i])) { - Switch.hold_timer[i] = 0; - switchflag = POWER_TOGGLE; - } - break; -# 250 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_switch.ino" - case TOGGLEMULTI: - case FOLLOWMULTI: - case FOLLOWMULTI_INV: - if (Switch.hold_timer[i]) { - Switch.hold_timer[i] = 0; - SendKey(KEY_SWITCH, i +1, POWER_HOLD); - } else { - Switch.hold_timer[i] = loops_per_second / 2; - } - break; - case PUSHHOLDMULTI: - - if (NOT_PRESSED == button) { - if (Switch.hold_timer[i] != 0) { - SendKey(KEY_SWITCH, i +1, POWER_INV); - } - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - - if (PRESSED == button) { - if (Switch.hold_timer[i] > loops_per_second * Settings.param[P_HOLD_TIME] / 25) { - switchflag = POWER_TOGGLE; - } - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - break; - case PUSHHOLDMULTI_INV: - - if (PRESSED == button) { - if (Switch.hold_timer[i] != 0) { - SendKey(KEY_SWITCH, i +1, POWER_INV); - } - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - - if (NOT_PRESSED == button) { - if (Switch.hold_timer[i] > loops_per_second * Settings.param[P_HOLD_TIME] / 25) { - switchflag = POWER_TOGGLE; - } - Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; - } - break; - case PUSHON: - if (PRESSED == button) { - switchflag = POWER_ON; - } - break; - case PUSHON_INV: - if (NOT_PRESSED == button) { - switchflag = POWER_ON; - } - break; - } - Switch.last_state[i] = button; - } - if (switchflag <= POWER_TOGGLE) { - if (!SendKey(KEY_SWITCH, i +1, switchflag)) { - ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); - } - } - } - } -} - -void SwitchLoop(void) -{ - if (Switch.present) { - if (TimeReached(Switch.debounce)) { - SetNextTimeInterval(Switch.debounce, Settings.switch_debounce); - SwitchHandler(0); - } - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" -const char kSleepMode[] PROGMEM = "Dynamic|Normal"; -const char kPrefixes[] PROGMEM = D_CMND "|" D_STAT "|" D_TELE; - -char* Format(char* output, const char* input, int size) -{ - char *token; - uint32_t digits = 0; - - if (strstr(input, "%") != nullptr) { - strlcpy(output, input, size); - token = strtok(output, "%"); - if (strstr(input, "%") == input) { - output[0] = '\0'; - } else { - token = strtok(nullptr, ""); - } - if (token != nullptr) { - digits = atoi(token); - if (digits) { - char tmp[size]; - if (strchr(token, 'd')) { - snprintf_P(tmp, size, PSTR("%s%c0%dd"), output, '%', digits); - snprintf_P(output, size, tmp, ESP_getChipId() & 0x1fff); - } else { - snprintf_P(tmp, size, PSTR("%s%c0%dX"), output, '%', digits); - snprintf_P(output, size, tmp, ESP_getChipId()); - } - } else { - if (strchr(token, 'd')) { - snprintf_P(output, size, PSTR("%s%d"), output, ESP_getChipId()); - digits = 8; - } - } - } - } - if (!digits) { - strlcpy(output, input, size); - } - return output; -} - -char* GetOtaUrl(char *otaurl, size_t otaurl_size) -{ - if (strstr(SettingsText(SET_OTAURL), "%04d") != nullptr) { - snprintf(otaurl, otaurl_size, SettingsText(SET_OTAURL), ESP_getChipId() & 0x1fff); - } - else if (strstr(SettingsText(SET_OTAURL), "%d") != nullptr) { - snprintf_P(otaurl, otaurl_size, SettingsText(SET_OTAURL), ESP_getChipId()); - } - else { - strlcpy(otaurl, SettingsText(SET_OTAURL), otaurl_size); - } - - return otaurl; -} - -char* GetTopic_P(char *stopic, uint32_t prefix, char *topic, const char* subtopic) -{ -# 88 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" - char romram[CMDSZ]; - String fulltopic; - - snprintf_P(romram, sizeof(romram), subtopic); - if (fallback_topic_flag || (prefix > 3)) { - bool fallback = (prefix < 8); - prefix &= 3; - char stemp[11]; - fulltopic = GetTextIndexed(stemp, sizeof(stemp), prefix, kPrefixes); - fulltopic += F("/"); - if (fallback) { - fulltopic += mqtt_client; - fulltopic += F("_fb"); - } else { - fulltopic += topic; - } - } else { - fulltopic = SettingsText(SET_MQTT_FULLTOPIC); - if ((0 == prefix) && (-1 == fulltopic.indexOf(FPSTR(MQTT_TOKEN_PREFIX)))) { - fulltopic += F("/"); - fulltopic += FPSTR(MQTT_TOKEN_PREFIX); - } - for (uint32_t i = 0; i < MAX_MQTT_PREFIXES; i++) { - if (!strlen(SettingsText(SET_MQTTPREFIX1 + i))) { - char temp[TOPSZ]; - SettingsUpdateText(SET_MQTTPREFIX1 + i, GetTextIndexed(temp, sizeof(temp), i, kPrefixes)); - } - } - fulltopic.replace(FPSTR(MQTT_TOKEN_PREFIX), SettingsText(SET_MQTTPREFIX1 + prefix)); - - fulltopic.replace(FPSTR(MQTT_TOKEN_TOPIC), topic); - fulltopic.replace(F("%hostname%"), my_hostname); - String token_id = WiFi.macAddress(); - token_id.replace(":", ""); - fulltopic.replace(F("%id%"), token_id); - } - fulltopic.replace(F("#"), ""); - fulltopic.replace(F("//"), "/"); - if (!fulltopic.endsWith("/")) { - fulltopic += "/"; - } - snprintf_P(stopic, TOPSZ, PSTR("%s%s"), fulltopic.c_str(), romram); - return stopic; -} - -char* GetGroupTopic_P(char *stopic, const char* subtopic, uint32_t itopic) -{ - - - return GetTopic_P(stopic, (Settings.flag3.grouptopic_mode) ? CMND +8 : CMND, SettingsText(itopic), subtopic); -} - -char* GetFallbackTopic_P(char *stopic, const char* subtopic) -{ - return GetTopic_P(stopic, CMND +4, nullptr, subtopic); -} - -char* GetStateText(uint32_t state) -{ - if (state >= MAX_STATE_TEXT) { - state = 1; - } - return SettingsText(SET_STATE_TXT1 + state); -} - - - -void SetLatchingRelay(power_t lpower, uint32_t state) -{ - - - - - - if (state && !latching_relay_pulse) { - latching_power = lpower; - latching_relay_pulse = 2; - } - - for (uint32_t i = 0; i < devices_present; i++) { - uint32_t port = (i << 1) + ((latching_power >> i) &1); - DigitalWrite(GPIO_REL1 +port, bitRead(rel_inverted, port) ? !state : state); - } -} - -void SetDevicePower(power_t rpower, uint32_t source) -{ - ShowSource(source); - last_source = source; - - if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { - power = (1 << devices_present) -1; - rpower = power; - } - - if (Settings.flag.interlock) { - for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { - power_t mask = 1; - uint32_t count = 0; - for (uint32_t j = 0; j < devices_present; j++) { - if ((Settings.interlock[i] & mask) && (rpower & mask)) { - count++; - } - mask <<= 1; - } - if (count > 1) { - mask = ~Settings.interlock[i]; - power &= mask; - rpower &= mask; - } - } - } - - if (rpower) { - last_power = rpower; - } - - XdrvMailbox.index = rpower; - XdrvCall(FUNC_SET_POWER); - - XdrvMailbox.index = rpower; - XdrvMailbox.payload = source; - if (XdrvCall(FUNC_SET_DEVICE_POWER)) { - - } -#ifdef ESP8266 - else if ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { - Serial.write(0xA0); - Serial.write(0x04); - Serial.write(rpower &0xFF); - Serial.write(0xA1); - Serial.write('\n'); - Serial.flush(); - } - else if (EXS_RELAY == my_module_type) { - SetLatchingRelay(rpower, 1); - } - else -#endif - { - for (uint32_t i = 0; i < devices_present; i++) { - power_t state = rpower &1; - if (i < MAX_RELAYS) { - DigitalWrite(GPIO_REL1 +i, bitRead(rel_inverted, i) ? !state : state); - } - rpower >>= 1; - } - } -} - -void RestorePower(bool publish_power, uint32_t source) -{ - if (power != last_power) { - power = last_power; - SetDevicePower(power, source); - if (publish_power) { - MqttPublishAllPowerState(); - } - } -} - -void SetAllPower(uint32_t state, uint32_t source) -{ -# 259 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" - bool publish_power = true; - if ((state >= POWER_OFF_NO_STATE) && (state <= POWER_TOGGLE_NO_STATE)) { - state &= 3; - publish_power = false; - } - if ((state >= POWER_OFF) && (state <= POWER_TOGGLE)) { - power_t all_on = (1 << devices_present) -1; - switch (state) { - case POWER_OFF: - power = 0; - break; - case POWER_ON: - power = all_on; - break; - case POWER_TOGGLE: - power ^= all_on; - } - SetDevicePower(power, source); - } - if (publish_power) { - MqttPublishAllPowerState(); - } -} - -void SetPowerOnState(void) -{ -#ifdef ESP8266 - if (MOTOR == my_module_type) { - Settings.poweronstate = POWER_ALL_ON; - } -#endif - if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { - SetDevicePower(1, SRC_RESTART); - } else { - if ((ResetReason() == REASON_DEFAULT_RST) || (ResetReason() == REASON_EXT_SYS_RST)) { - switch (Settings.poweronstate) { - case POWER_ALL_OFF: - case POWER_ALL_OFF_PULSETIME_ON: - power = 0; - SetDevicePower(power, SRC_RESTART); - break; - case POWER_ALL_ON: - power = (1 << devices_present) -1; - SetDevicePower(power, SRC_RESTART); - break; - case POWER_ALL_SAVED_TOGGLE: - power = (Settings.power & ((1 << devices_present) -1)) ^ POWER_MASK; - if (Settings.flag.save_state) { - SetDevicePower(power, SRC_RESTART); - } - break; - case POWER_ALL_SAVED: - power = Settings.power & ((1 << devices_present) -1); - if (Settings.flag.save_state) { - SetDevicePower(power, SRC_RESTART); - } - break; - } - } else { - power = Settings.power & ((1 << devices_present) -1); - if (Settings.flag.save_state) { - SetDevicePower(power, SRC_RESTART); - } - } - } - - - for (uint32_t i = 0; i < devices_present; i++) { - if (!Settings.flag3.no_power_feedback) { - if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) { - bitWrite(power, i, digitalRead(pin[GPIO_REL1 +i]) ^ bitRead(rel_inverted, i)); - } - } - if ((i < MAX_PULSETIMERS) && (bitRead(power, i) || (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate))) { - SetPulseTimer(i, Settings.pulse_timer[i]); - } - } - blink_powersave = power; -} - -void SetLedPowerIdx(uint32_t led, uint32_t state) -{ - if ((99 == pin[GPIO_LEDLNK]) && (0 == led)) { - if (pin[GPIO_LED2] < 99) { - led = 1; - } - } - if (pin[GPIO_LED1 + led] < 99) { - uint32_t mask = 1 << led; - if (state) { - state = 1; - led_power |= mask; - } else { - led_power &= (0xFF ^ mask); - } - DigitalWrite(GPIO_LED1 + led, bitRead(led_inverted, led) ? !state : state); - } -#ifdef USE_BUZZER - if (led == 0) { - BuzzerSetStateToLed(state); - } -#endif -} - -void SetLedPower(uint32_t state) -{ - if (99 == pin[GPIO_LEDLNK]) { - SetLedPowerIdx(0, state); - } else { - power_t mask = 1; - for (uint32_t i = 0; i < leds_present; i++) { - bool tstate = (power & mask); - SetLedPowerIdx(i, tstate); - mask <<= 1; - } - } -} - -void SetLedPowerAll(uint32_t state) -{ - for (uint32_t i = 0; i < leds_present; i++) { - SetLedPowerIdx(i, state); - } -} - -void SetLedLink(uint32_t state) -{ - uint32_t led_pin = pin[GPIO_LEDLNK]; - uint32_t led_inv = ledlnk_inverted; - if (99 == led_pin) { - led_pin = pin[GPIO_LED1]; - led_inv = bitRead(led_inverted, 0); - } - if (led_pin < 99) { - if (state) { state = 1; } - digitalWrite(led_pin, (led_inv) ? !state : state); - } -#ifdef USE_BUZZER - BuzzerSetStateToLed(state); -#endif -} - -void SetPulseTimer(uint32_t index, uint32_t time) -{ - pulse_timer[index] = (time > 111) ? millis() + (1000 * (time - 100)) : (time > 0) ? millis() + (100 * time) : 0L; -} - -uint32_t GetPulseTimer(uint32_t index) -{ - long time = TimePassedSince(pulse_timer[index]); - if (time < 0) { - time *= -1; - return (time > 11100) ? (time / 1000) + 100 : (time > 0) ? time / 100 : 0; - } - return 0; -} - - - -bool SendKey(uint32_t key, uint32_t device, uint32_t state) -{ -# 428 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" - char stopic[TOPSZ]; - char scommand[CMDSZ]; - char key_topic[TOPSZ]; - bool result = false; - uint32_t device_save = device; - - char *tmp = (key) ? SettingsText(SET_MQTT_SWITCH_TOPIC) : SettingsText(SET_MQTT_BUTTON_TOPIC); - Format(key_topic, tmp, sizeof(key_topic)); - if (Settings.flag.mqtt_enabled && MqttIsConnected() && (strlen(key_topic) != 0) && strcmp(key_topic, "0")) { - if (!key && (device > devices_present)) { - device = 1; - } - GetTopic_P(stopic, CMND, key_topic, - GetPowerDevice(scommand, device, sizeof(scommand), (key + Settings.flag.device_index_enable))); - if (CLEAR_RETAIN == state) { - mqtt_data[0] = '\0'; - } else { - if ((Settings.flag3.button_switch_force_local || - !strcmp(mqtt_topic, key_topic) || - !strcmp(SettingsText(SET_MQTT_GRP_TOPIC), key_topic)) && - (POWER_TOGGLE == state)) { - state = ~(power >> (device -1)) &1; - } - snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(state)); - } -#ifdef USE_DOMOTICZ - if (!(DomoticzSendKey(key, device, state, strlen(mqtt_data)))) { -#endif - MqttPublish(stopic, ((key) ? Settings.flag.mqtt_switch_retain - : Settings.flag.mqtt_button_retain) && - (state != POWER_HOLD || !Settings.flag3.no_hold_retain)); -#ifdef USE_DOMOTICZ - } -#endif - result = !Settings.flag3.button_switch_force_local; - } else { - Response_P(PSTR("{\"%s%d\":{\"State\":%d}}"), (key) ? "Switch" : "Button", device, state); - result = XdrvRulesProcess(); - } - int32_t payload_save = XdrvMailbox.payload; - XdrvMailbox.payload = device_save << 24 | key << 16 | state << 8 | device; - XdrvCall(FUNC_ANY_KEY); - XdrvMailbox.payload = payload_save; - return result; -} - -void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source) -{ -# 489 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { - blink_mask &= 1; - Settings.flag.interlock = 0; - Settings.pulse_timer[1] = 0; - Settings.pulse_timer[2] = 0; - Settings.pulse_timer[3] = 0; - } -#endif - - bool publish_power = true; - if ((state >= POWER_OFF_NO_STATE) && (state <= POWER_TOGGLE_NO_STATE)) { - state &= 3; - publish_power = false; - } - - if ((device < 1) || (device > devices_present)) { - device = 1; - } - active_device = device; - - if (device <= MAX_PULSETIMERS) { - SetPulseTimer(device -1, 0); - } - power_t mask = 1 << (device -1); - if (state <= POWER_TOGGLE) { - if ((blink_mask & mask)) { - blink_mask &= (POWER_MASK ^ mask); - MqttPublishPowerBlinkState(device); - } - - if (Settings.flag.interlock && - !interlock_mutex && - ((POWER_ON == state) || ((POWER_TOGGLE == state) && !(power & mask))) - ) { - interlock_mutex = true; - for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { - if (Settings.interlock[i] & mask) { - for (uint32_t j = 0; j < devices_present; j++) { - power_t imask = 1 << j; - if ((Settings.interlock[i] & imask) && (power & imask) && (mask != imask)) { - ExecuteCommandPower(j +1, POWER_OFF, SRC_IGNORE); - delay(50); - } - } - break; - } - } - interlock_mutex = false; - } - - switch (state) { - case POWER_OFF: { - power &= (POWER_MASK ^ mask); - break; } - case POWER_ON: - power |= mask; - break; - case POWER_TOGGLE: - power ^= mask; - } -#ifdef USE_DEVICE_GROUPS - if (SRC_REMOTE != source && SRC_RETRY != source) SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_POWER, power); -#endif - SetDevicePower(power, source); -#ifdef USE_DOMOTICZ - DomoticzUpdatePowerState(device); -#endif -#ifdef USE_KNX - KnxUpdatePowerState(device, power); -#endif - if (publish_power && Settings.flag3.hass_tele_on_power) { - MqttPublishTeleState(); - } - if (device <= MAX_PULSETIMERS) { - SetPulseTimer(device -1, (((POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? ~power : power) & mask) ? Settings.pulse_timer[device -1] : 0); - } - } - else if (POWER_BLINK == state) { - if (!(blink_mask & mask)) { - blink_powersave = (blink_powersave & (POWER_MASK ^ mask)) | (power & mask); - blink_power = (power >> (device -1))&1; - } - blink_timer = millis() + 100; - blink_counter = ((!Settings.blinkcount) ? 64000 : (Settings.blinkcount *2)) +1; - blink_mask |= mask; - MqttPublishPowerBlinkState(device); - return; - } - else if (POWER_BLINK_STOP == state) { - bool flag = (blink_mask & mask); - blink_mask &= (POWER_MASK ^ mask); - MqttPublishPowerBlinkState(device); - if (flag) { - ExecuteCommandPower(device, (blink_powersave >> (device -1))&1, SRC_IGNORE); - } - return; - } - if (publish_power) { - MqttPublishPowerState(device); - } -} - -void StopAllPowerBlink(void) -{ - power_t mask; - - for (uint32_t i = 1; i <= devices_present; i++) { - mask = 1 << (i -1); - if (blink_mask & mask) { - blink_mask &= (POWER_MASK ^ mask); - MqttPublishPowerBlinkState(i); - ExecuteCommandPower(i, (blink_powersave >> (i -1))&1, SRC_IGNORE); - } - } -} - -void MqttShowPWMState(void) -{ - ResponseAppend_P(PSTR("\"" D_CMND_PWM "\":{")); - bool first = true; - for (uint32_t i = 0; i < MAX_PWMS; i++) { - if (pin[GPIO_PWM1 + i] < 99) { - ResponseAppend_P(PSTR("%s\"" D_CMND_PWM "%d\":%d"), first ? "" : ",", i+1, Settings.pwm_value[i]); - first = false; - } - } - ResponseJsonEnd(); -} - -void MqttShowState(void) -{ - char stemp1[TOPSZ]; - - ResponseAppendTime(); - ResponseAppend_P(PSTR(",\"" D_JSON_UPTIME "\":\"%s\",\"UptimeSec\":%u"), GetUptime().c_str(), UpTime()); - -#ifdef USE_ADC_VCC - dtostrfd((double)ESP.getVcc()/1000, 3, stemp1); - ResponseAppend_P(PSTR(",\"" D_JSON_VCC "\":%s"), stemp1); -#endif - - ResponseAppend_P(PSTR(",\"" D_JSON_HEAPSIZE "\":%d,\"SleepMode\":\"%s\",\"Sleep\":%u,\"LoadAvg\":%u,\"MqttCount\":%u"), - ESP.getFreeHeap()/1024, GetTextIndexed(stemp1, sizeof(stemp1), Settings.flag3.sleep_normal, kSleepMode), - ssleep, loop_load_avg, MqttConnectCount()); - - for (uint32_t i = 1; i <= devices_present; i++) { -#ifdef USE_LIGHT - if ((LightDevice()) && (i >= LightDevice())) { - if (i == LightDevice()) { LightState(1); } - } else { -#endif - ResponseAppend_P(PSTR(",\"%s\":\"%s\""), GetPowerDevice(stemp1, i, sizeof(stemp1), Settings.flag.device_index_enable), - GetStateText(bitRead(power, i-1))); -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { - ResponseAppend_P(PSTR(",\"" D_CMND_FANSPEED "\":%d"), GetFanspeed()); - break; - } -#endif -#ifdef USE_LIGHT - } -#endif - } - - if (pwm_present) { - ResponseAppend_P(PSTR(",")); - MqttShowPWMState(); - } - - int32_t rssi = WiFi.RSSI(); - ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}}"), - Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WiFi.BSSIDstr().c_str(), WiFi.channel(), - WifiGetRssiAsQuality(rssi), rssi, WifiLinkCount(), WifiDowntime().c_str()); -} - -void MqttPublishTeleState(void) -{ - mqtt_data[0] = '\0'; - MqttShowState(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN); -#if defined(USE_RULES) || defined(USE_SCRIPT) - RulesTeleperiod(); -#endif -} - -void TempHumDewShow(bool json, bool pass_on, const char *types, float f_temperature, float f_humidity) -{ - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{"), types); - ResponseAppendTHD(f_temperature, f_humidity); - ResponseJsonEnd(); -#ifdef USE_DOMOTICZ - if (pass_on) { - DomoticzTempHumPressureSensor(f_temperature, f_humidity); - } -#endif -#ifdef USE_KNX - if (pass_on) { - KnxSensor(KNX_TEMPERATURE, f_temperature); - KnxSensor(KNX_HUMIDITY, f_humidity); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_THD(types, f_temperature, f_humidity); -#endif - } -} - -bool MqttShowSensor(void) -{ - ResponseAppendTime(); - - int json_data_start = strlen(mqtt_data); - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { -#ifdef USE_TM1638 - if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) { -#else - if (pin[GPIO_SWT1 +i] < 99) { -#endif - ResponseAppend_P(PSTR(",\"" D_JSON_SWITCH "%d\":\"%s\""), i +1, GetStateText(SwitchState(i))); - } - } - XsnsCall(FUNC_JSON_APPEND); - XdrvCall(FUNC_JSON_APPEND); - - bool json_data_available = (strlen(mqtt_data) - json_data_start); - if (strstr_P(mqtt_data, PSTR(D_JSON_PRESSURE)) != nullptr) { - ResponseAppend_P(PSTR(",\"" D_JSON_PRESSURE_UNIT "\":\"%s\""), PressureUnit().c_str()); - } - if (strstr_P(mqtt_data, PSTR(D_JSON_TEMPERATURE)) != nullptr) { - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE_UNIT "\":\"%c\""), TempUnit()); - } - if ((strstr_P(mqtt_data, PSTR(D_JSON_SPEED)) != nullptr) && Settings.flag2.speed_conversion) { - ResponseAppend_P(PSTR(",\"" D_JSON_SPEED_UNIT "\":\"%s\""), SpeedUnit().c_str()); - } - ResponseJsonEnd(); - - if (json_data_available) { XdrvCall(FUNC_SHOW_SENSOR); } - return json_data_available; -} - -void MqttPublishSensor(void) -{ - mqtt_data[0] = '\0'; - if (MqttShowSensor()) { - MqttPublishTeleSensor(); - } -} -# 747 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" -void PerformEverySecond(void) -{ - uptime++; - - if (POWER_CYCLE_TIME == uptime) { - UpdateQuickPowerCycle(false); - } - - if (BOOT_LOOP_TIME == uptime) { - RtcRebootReset(); - -#ifdef USE_DEEPSLEEP - if (!(DeepSleepEnabled() && !Settings.flag3.bootcount_update)) { -#endif - Settings.bootcount++; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BOOT_COUNT " %d"), Settings.bootcount); -#ifdef USE_DEEPSLEEP - } -#endif - } - - if (mqtt_cmnd_blocked_reset) { - mqtt_cmnd_blocked_reset--; - if (!mqtt_cmnd_blocked_reset) { - mqtt_cmnd_blocked = 0; - } - } - - if (seriallog_timer) { - seriallog_timer--; - if (!seriallog_timer) { - if (seriallog_level) { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SERIAL_LOGGING_DISABLED)); - } - seriallog_level = 0; - } - } - - if (syslog_timer) { - syslog_timer--; - if (!syslog_timer) { - syslog_level = Settings.syslog_level; - if (Settings.syslog_level) { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SYSLOG_LOGGING_REENABLED)); - } - } - } - - ResetGlobalValues(); - - if (Settings.tele_period) { - if (tele_period >= 9999) { - if (!global_state.wifi_down) { - tele_period = 0; - } - } else { - tele_period++; - if (tele_period >= Settings.tele_period) { - tele_period = 0; - - MqttPublishTeleState(); - - mqtt_data[0] = '\0'; - if (MqttShowSensor()) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); -#if defined(USE_RULES) || defined(USE_SCRIPT) - RulesTeleperiod(); -#endif - } - - XsnsCall(FUNC_AFTER_TELEPERIOD); - XdrvCall(FUNC_AFTER_TELEPERIOD); - } - } - } - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 - - wifiKeepAlive(); -#endif - - -#ifdef ESP32 - if (11 == uptime) { - ESP_getSketchSize(); - } -#endif -} - - - - - -void Every100mSeconds(void) -{ - - power_t power_now; - - if (prepped_loglevel) { - AddLog(prepped_loglevel); - } - - if (latching_relay_pulse) { - latching_relay_pulse--; - if (!latching_relay_pulse) SetLatchingRelay(0, 0); - } - - for (uint32_t i = 0; i < MAX_PULSETIMERS; i++) { - if (pulse_timer[i] != 0L) { - if (TimeReached(pulse_timer[i])) { - pulse_timer[i] = 0L; - ExecuteCommandPower(i +1, (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? POWER_ON : POWER_OFF, SRC_PULSETIMER); - } - } - } - - if (blink_mask) { - if (TimeReached(blink_timer)) { - SetNextTimeInterval(blink_timer, 100 * Settings.blinktime); - blink_counter--; - if (!blink_counter) { - StopAllPowerBlink(); - } else { - blink_power ^= 1; - power_now = (power & (POWER_MASK ^ blink_mask)) | ((blink_power) ? blink_mask : 0); - SetDevicePower(power_now, SRC_IGNORE); - } - } - } -} - - - - - -void Every250mSeconds(void) -{ - - - uint32_t blinkinterval = 1; - - state_250mS++; - state_250mS &= 0x3; - - if (!Settings.flag.global_state) { - if (global_state.data) { - if (global_state.mqtt_down) { blinkinterval = 7; } - if (global_state.wifi_down) { blinkinterval = 3; } - blinks = 201; - } - } - if (blinks || restart_flag || ota_state_flag) { - if (restart_flag || ota_state_flag) { - blinkstate = true; - } else { - blinkspeed--; - if (!blinkspeed) { - blinkspeed = blinkinterval; - blinkstate ^= 1; - } - } - if ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) { - SetLedLink(blinkstate); - } - if (!blinkstate) { - blinks--; - if (200 == blinks) blinks = 0; - } - } - if (Settings.ledstate &1 && (pin[GPIO_LEDLNK] < 99 || !(blinks || restart_flag || ota_state_flag)) ) { - bool tstate = power & Settings.ledmask; -#ifdef ESP8266 - if ((SONOFF_TOUCH == my_module_type) || (SONOFF_T11 == my_module_type) || (SONOFF_T12 == my_module_type) || (SONOFF_T13 == my_module_type)) { - tstate = (!power) ? 1 : 0; - } -#endif - SetLedPower(tstate); - } - - - - - - switch (state_250mS) { - case 0: - if (ota_state_flag && BACKLOG_EMPTY) { - ota_state_flag--; - if (2 == ota_state_flag) { - RtcSettings.ota_loader = 0; - ota_retry_counter = OTA_ATTEMPTS; - ESPhttpUpdate.rebootOnUpdate(false); - SettingsSave(1); - } - if (ota_state_flag <= 0) { -#ifdef USE_WEBSERVER - if (Settings.webserver) StopWebserver(); -#endif -#ifdef USE_ARILUX_RF - AriluxRfDisable(); -#endif - ota_state_flag = 92; - ota_result = 0; - ota_retry_counter--; - if (ota_retry_counter) { - strlcpy(mqtt_data, GetOtaUrl(log_data, sizeof(log_data)), sizeof(mqtt_data)); -#ifndef FIRMWARE_MINIMAL - if (RtcSettings.ota_loader) { -# 970 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" - char *bch = strrchr(mqtt_data, '/'); - if (bch == nullptr) { bch = mqtt_data; } -# 981 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_tasmota.ino" - char *ech = strchr(bch, '.'); - if (ech == nullptr) { ech = mqtt_data + strlen(mqtt_data); } - - - - char ota_url_type[strlen(ech) +1]; - strncpy(ota_url_type, ech, sizeof(ota_url_type)); - - char *pch = strrchr(bch, '-'); - if (pch == nullptr) { pch = ech; } - *pch = '\0'; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s-" D_JSON_MINIMAL "%s"), mqtt_data, ota_url_type); - } -#endif - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "%s"), mqtt_data); -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) - ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(mqtt_data)); -#else - - WiFiClient OTAclient; - ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(OTAclient, mqtt_data)); -#endif - if (!ota_result) { -#ifndef FIRMWARE_MINIMAL - int ota_error = ESPhttpUpdate.getLastError(); - DEBUG_CORE_LOG(PSTR("OTA: Error %d"), ota_error); - if ((HTTP_UE_TOO_LESS_SPACE == ota_error) || (HTTP_UE_BIN_FOR_WRONG_FLASH == ota_error)) { - RtcSettings.ota_loader = 1; - } -#endif - ota_state_flag = 2; - } - } - } - if (90 == ota_state_flag) { - ota_state_flag = 0; - Response_P(PSTR("{\"" D_CMND_UPGRADE "\":\"")); - if (ota_result) { - - if (!VersionCompatible()) { - ResponseAppend_P(PSTR(D_JSON_FAILED " " D_UPLOAD_ERR_14)); - } else { - ResponseAppend_P(PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING)); - restart_flag = 2; - } - } else { - ResponseAppend_P(PSTR(D_JSON_FAILED " %s"), ESPhttpUpdate.getLastErrorString().c_str()); - } - ResponseAppend_P(PSTR("\"}")); - - MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_UPGRADE)); - } - } - break; - case 1: - if (MidnightNow()) { - XsnsCall(FUNC_SAVE_AT_MIDNIGHT); - } - if (save_data_counter && BACKLOG_EMPTY) { - save_data_counter--; - if (save_data_counter <= 0) { - if (Settings.flag.save_state) { - power_t mask = POWER_MASK; - for (uint32_t i = 0; i < MAX_PULSETIMERS; i++) { - if ((Settings.pulse_timer[i] > 0) && (Settings.pulse_timer[i] < 30)) { - mask &= ~(1 << i); - } - } - if (!((Settings.power &mask) == (power &mask))) { - Settings.power = power; - } - } else { - Settings.power = 0; - } - SettingsSave(0); - save_data_counter = Settings.save_data; - } - } - if (restart_flag && BACKLOG_EMPTY) { - if ((214 == restart_flag) || (215 == restart_flag) || (216 == restart_flag)) { - - char storage_ssid1[strlen(SettingsText(SET_STASSID1)) +1]; - strncpy(storage_ssid1, SettingsText(SET_STASSID1), sizeof(storage_ssid1)); - char storage_ssid2[strlen(SettingsText(SET_STASSID2)) +1]; - strncpy(storage_ssid2, SettingsText(SET_STASSID2), sizeof(storage_ssid2)); - char storage_pass1[strlen(SettingsText(SET_STAPWD1)) +1]; - strncpy(storage_pass1, SettingsText(SET_STAPWD1), sizeof(storage_pass1)); - char storage_pass2[strlen(SettingsText(SET_STAPWD2)) +1]; - strncpy(storage_pass2, SettingsText(SET_STAPWD2), sizeof(storage_pass2)); - - char storage_mqtthost[strlen(SettingsText(SET_MQTT_HOST)) +1]; - strncpy(storage_mqtthost, SettingsText(SET_MQTT_HOST), sizeof(storage_mqtthost)); - char storage_mqttuser[strlen(SettingsText(SET_MQTT_USER)) +1]; - strncpy(storage_mqttuser, SettingsText(SET_MQTT_USER), sizeof(storage_mqttuser)); - char storage_mqttpwd[strlen(SettingsText(SET_MQTT_PWD)) +1]; - strncpy(storage_mqttpwd, SettingsText(SET_MQTT_PWD), sizeof(storage_mqttpwd)); - char storage_mqtttopic[strlen(SettingsText(SET_MQTT_TOPIC)) +1]; - strncpy(storage_mqtttopic, SettingsText(SET_MQTT_TOPIC), sizeof(storage_mqtttopic)); - uint16_t mqtt_port = Settings.mqtt_port; - - - - - if ((215 == restart_flag) || (216 == restart_flag)) { - SettingsErase(0); - } - SettingsDefault(); - - SettingsUpdateText(SET_STASSID1, storage_ssid1); - SettingsUpdateText(SET_STASSID2, storage_ssid2); - SettingsUpdateText(SET_STAPWD1, storage_pass1); - SettingsUpdateText(SET_STAPWD2, storage_pass2); - if (216 == restart_flag) { - - SettingsUpdateText(SET_MQTT_HOST, storage_mqtthost); - SettingsUpdateText(SET_MQTT_USER, storage_mqttuser); - SettingsUpdateText(SET_MQTT_PWD, storage_mqttpwd); - SettingsUpdateText(SET_MQTT_TOPIC, storage_mqtttopic); - Settings.mqtt_port = mqtt_port; - } - restart_flag = 2; - } - else if (213 == restart_flag) { - SettingsSdkErase(); - restart_flag = 2; - } - else if (212 == restart_flag) { - SettingsErase(0); - restart_flag = 211; - } - if (211 == restart_flag) { - SettingsDefault(); - restart_flag = 2; - } - if (2 == restart_flag) { - SettingsSaveAll(); - } - restart_flag--; - if (restart_flag <= 0) { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING)); - EspRestart(); - } - } - break; - case 2: - WifiCheck(wifi_state_flag); - wifi_state_flag = WIFI_RESTART; - break; - case 3: - if (!global_state.wifi_down) { MqttCheck(); } - break; - } -} - -#ifdef USE_ARDUINO_OTA - - - - - - - -bool arduino_ota_triggered = false; -uint16_t arduino_ota_progress_dot_count = 0; - -void ArduinoOTAInit(void) -{ - ArduinoOTA.setPort(8266); - ArduinoOTA.setHostname(my_hostname); - if (strlen(SettingsText(SET_WEBPWD))) { - ArduinoOTA.setPassword(SettingsText(SET_WEBPWD)); - } - - ArduinoOTA.onStart([]() - { - SettingsSave(1); -#ifdef USE_WEBSERVER - if (Settings.webserver) { StopWebserver(); } -#endif -#ifdef USE_ARILUX_RF - AriluxRfDisable(); -#endif - if (Settings.flag.mqtt_enabled) { - MqttDisconnect(); - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA " D_UPLOAD_STARTED)); - arduino_ota_triggered = true; - arduino_ota_progress_dot_count = 0; - delay(100); - }); - - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) - { - if ((LOG_LEVEL_DEBUG <= seriallog_level)) { - arduino_ota_progress_dot_count++; - Serial.printf("."); - if (!(arduino_ota_progress_dot_count % 80)) { Serial.println(); } - } - }); - - ArduinoOTA.onError([](ota_error_t error) - { - - - - - char error_str[100]; - - if ((LOG_LEVEL_DEBUG <= seriallog_level) && arduino_ota_progress_dot_count) { Serial.println(); } - switch (error) { - case OTA_BEGIN_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_2), sizeof(error_str)); break; - case OTA_RECEIVE_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_5), sizeof(error_str)); break; - case OTA_END_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_7), sizeof(error_str)); break; - default: - snprintf_P(error_str, sizeof(error_str), PSTR(D_UPLOAD_ERROR_CODE " %d"), error); - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA %s. " D_RESTARTING), error_str); - EspRestart(); - }); - - ArduinoOTA.onEnd([]() - { - if ((LOG_LEVEL_DEBUG <= seriallog_level)) { Serial.println(); } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA " D_SUCCESSFUL ". " D_RESTARTING)); - EspRestart(); - }); - - ArduinoOTA.begin(); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD "Arduino OTA " D_ENABLED " " D_PORT " 8266")); -} - -void ArduinoOtaLoop(void) -{ - MDNS.update(); - ArduinoOTA.handle(); - - while (arduino_ota_triggered) { ArduinoOTA.handle(); } -} -#endif - - - -void SerialInput(void) -{ - while (Serial.available()) { - - delay(0); - serial_in_byte = Serial.read(); - -#ifdef ESP8266 - - - - if ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type)) { - serial_in_byte = ButtonSerial(serial_in_byte); - } -#endif - - - if (XdrvCall(FUNC_SERIAL)) { - serial_in_byte_counter = 0; - Serial.flush(); - return; - } - - - - if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { - serial_in_byte_counter = 0; - Serial.flush(); - return; - } - if (!Settings.flag.mqtt_serial) { - if (isprint(serial_in_byte)) { - if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - } else { - serial_in_byte_counter = 0; - } - } - } else { - if (serial_in_byte || Settings.flag.mqtt_serial_raw) { - if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && - ((isprint(serial_in_byte) && (128 == Settings.serial_delimiter)) || - ((serial_in_byte != Settings.serial_delimiter) && (128 != Settings.serial_delimiter)) || - Settings.flag.mqtt_serial_raw)) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - serial_polling_window = millis(); - } else { - serial_polling_window = 0; - break; - } - } - } - -#ifdef USE_SONOFF_SC - - - - if (SONOFF_SC == my_module_type) { - if (serial_in_byte == '\x1B') { - serial_in_buffer[serial_in_byte_counter] = 0; - SonoffScSerialInput(serial_in_buffer); - serial_in_byte_counter = 0; - Serial.flush(); - return; - } - } else -#endif - - - if (!Settings.flag.mqtt_serial && (serial_in_byte == '\n')) { - serial_in_buffer[serial_in_byte_counter] = 0; - seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings.seriallog_level; - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), serial_in_buffer); - ExecuteCommand(serial_in_buffer, SRC_SERIAL); - serial_in_byte_counter = 0; - serial_polling_window = 0; - Serial.flush(); - return; - } - } - - if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) { - serial_in_buffer[serial_in_byte_counter] = 0; - char hex_char[(serial_in_byte_counter * 2) + 2]; - bool assume_json = (!Settings.flag.mqtt_serial_raw && (serial_in_buffer[0] == '{')); - Response_P(PSTR("{\"" D_JSON_SERIALRECEIVED "\":%s%s%s}"), - (assume_json) ? "" : "\"", - (Settings.flag.mqtt_serial_raw) ? ToHex_P((unsigned char*)serial_in_buffer, serial_in_byte_counter, hex_char, sizeof(hex_char)) : serial_in_buffer, - (assume_json) ? "" : "\""); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED)); - XdrvRulesProcess(); - serial_in_byte_counter = 0; - } -} - - - -void ResetPwm(void) -{ - for (uint32_t i = 0; i < MAX_PWMS; i++) { - if (pin[GPIO_PWM1 +i] < 99) { - analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range : 0); - - } - } -} - - - -void GpioInit(void) -{ - uint32_t mpin; - - if (!ValidModule(Settings.module)) { - uint32_t module = MODULE; - if (!ValidModule(MODULE)) { -#ifdef ESP8266 - module = SONOFF_BASIC; -#endif -#ifdef ESP32 - module = WEMOS; -#endif - } - - Settings.module = module; - Settings.last_module = module; - } - SetModuleType(); - - if (Settings.module != Settings.last_module) { - Settings.baudrate = APP_BAUDRATE / 300; - Settings.serial_config = TS_SERIAL_8N1; - } - - for (uint32_t i = 0; i < sizeof(Settings.user_template.gp); i++) { - if ((Settings.user_template.gp.io[i] >= GPIO_SENSOR_END) && (Settings.user_template.gp.io[i] < GPIO_USER)) { - Settings.user_template.gp.io[i] = GPIO_USER; - } - } - - myio def_gp; - ModuleGpios(&def_gp); - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - if ((Settings.my_gp.io[i] >= GPIO_SENSOR_END) && (Settings.my_gp.io[i] < GPIO_USER)) { - Settings.my_gp.io[i] = GPIO_NONE; - } - else if (Settings.my_gp.io[i] > GPIO_NONE) { - my_module.io[i] = Settings.my_gp.io[i]; - } - if ((def_gp.io[i] > GPIO_NONE) && (def_gp.io[i] < GPIO_USER)) { - my_module.io[i] = def_gp.io[i]; - } - } - if ((Settings.my_adc0 >= ADC0_END) && (Settings.my_adc0 < ADC0_USER)) { - Settings.my_adc0 = ADC0_NONE; - } - else if (Settings.my_adc0 > ADC0_NONE) { - my_adc0 = Settings.my_adc0; - } - my_module_flag = ModuleFlag(); - uint32_t template_adc0 = my_module_flag.data &15; - if ((template_adc0 > ADC0_NONE) && (template_adc0 < ADC0_USER)) { - my_adc0 = template_adc0; - } - - for (uint32_t i = 0; i < GPIO_MAX; i++) { - pin[i] = 99; - } - for (uint32_t i = 0; i < sizeof(my_module.io); i++) { - mpin = ValidPin(i, my_module.io[i]); - - DEBUG_CORE_LOG(PSTR("INI: gpio pin %d, mpin %d"), i, mpin); - - if (mpin) { - XdrvMailbox.index = mpin; - XdrvMailbox.payload = i; - - if ((mpin >= GPIO_SWT1_NP) && (mpin < (GPIO_SWT1_NP + MAX_SWITCHES))) { - SwitchPullupFlag(mpin - GPIO_SWT1_NP); - mpin -= (GPIO_SWT1_NP - GPIO_SWT1); - } - else if ((mpin >= GPIO_KEY1_NP) && (mpin < (GPIO_KEY1_NP + MAX_KEYS))) { - ButtonPullupFlag(mpin - GPIO_KEY1_NP); - mpin -= (GPIO_KEY1_NP - GPIO_KEY1); - } - else if ((mpin >= GPIO_KEY1_INV) && (mpin < (GPIO_KEY1_INV + MAX_KEYS))) { - ButtonInvertFlag(mpin - GPIO_KEY1_INV); - mpin -= (GPIO_KEY1_INV - GPIO_KEY1); - } - else if ((mpin >= GPIO_KEY1_INV_NP) && (mpin < (GPIO_KEY1_INV_NP + MAX_KEYS))) { - ButtonPullupFlag(mpin - GPIO_KEY1_INV_NP); - ButtonInvertFlag(mpin - GPIO_KEY1_INV_NP); - mpin -= (GPIO_KEY1_INV_NP - GPIO_KEY1); - } - else if ((mpin >= GPIO_REL1_INV) && (mpin < (GPIO_REL1_INV + MAX_RELAYS))) { - bitSet(rel_inverted, mpin - GPIO_REL1_INV); - mpin -= (GPIO_REL1_INV - GPIO_REL1); - } - else if ((mpin >= GPIO_LED1_INV) && (mpin < (GPIO_LED1_INV + MAX_LEDS))) { - bitSet(led_inverted, mpin - GPIO_LED1_INV); - mpin -= (GPIO_LED1_INV - GPIO_LED1); - } - else if (mpin == GPIO_LEDLNK_INV) { - ledlnk_inverted = 1; - mpin -= (GPIO_LEDLNK_INV - GPIO_LEDLNK); - } - else if ((mpin >= GPIO_PWM1_INV) && (mpin < (GPIO_PWM1_INV + MAX_PWMS))) { - bitSet(pwm_inverted, mpin - GPIO_PWM1_INV); - mpin -= (GPIO_PWM1_INV - GPIO_PWM1); - } - else if (XdrvCall(FUNC_PIN_STATE)) { - mpin = XdrvMailbox.index; - } - else if (XsnsCall(FUNC_PIN_STATE)) { - mpin = XdrvMailbox.index; - }; - } - if (mpin) pin[mpin] = i; - } - -#ifdef ESP8266 - if ((2 == pin[GPIO_TXD]) || (H801 == my_module_type)) { Serial.set_tx(2); } -#endif - - analogWriteRange(Settings.pwm_range); - analogWriteFreq(Settings.pwm_frequency); - -#ifdef USE_SPI - spi_flg = ((((pin[GPIO_SPI_CS] < 99) && (pin[GPIO_SPI_CS] > 14)) || (pin[GPIO_SPI_CS] < 12)) || (((pin[GPIO_SPI_DC] < 99) && (pin[GPIO_SPI_DC] > 14)) || (pin[GPIO_SPI_DC] < 12))); - if (spi_flg) { - for (uint32_t i = 0; i < GPIO_MAX; i++) { - if ((pin[i] >= 12) && (pin[i] <=14)) pin[i] = 99; - } - my_module.io[12] = GPIO_SPI_MISO; - pin[GPIO_SPI_MISO] = 12; - my_module.io[13] = GPIO_SPI_MOSI; - pin[GPIO_SPI_MOSI] = 13; - my_module.io[14] = GPIO_SPI_CLK; - pin[GPIO_SPI_CLK] = 14; - } - soft_spi_flg = ((pin[GPIO_SSPI_CS] < 99) && (pin[GPIO_SSPI_SCLK] < 99) && ((pin[GPIO_SSPI_MOSI] < 99) || (pin[GPIO_SSPI_MOSI] < 99))); -#endif - - - - for (uint32_t i = 0; i < sizeof(my_module.io); i++) { - mpin = ValidPin(i, my_module.io[i]); - - if (((i < 6) || (i > 11)) && (0 == mpin)) { - if (!((1 == i) || (3 == i))) { - pinMode(i, INPUT); - } - } - } - -#ifdef USE_I2C - i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99)); - if (i2c_flg) { - Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]); - } -#endif - - devices_present = 0; - light_type = LT_BASIC; - if (XdrvCall(FUNC_MODULE_INIT)) { - - } -#ifdef ESP8266 - else if (YTF_IR_BRIDGE == my_module_type) { - ClaimSerial(); - - } - else if (SONOFF_DUAL == my_module_type) { - devices_present = 2; - SetSerial(19200, TS_SERIAL_8N1); - } - else if (CH4 == my_module_type) { - devices_present = 4; - SetSerial(19200, TS_SERIAL_8N1); - } -#ifdef USE_SONOFF_SC - else if (SONOFF_SC == my_module_type) { - SetSerial(19200, TS_SERIAL_8N1); - } -#endif -#endif - - for (uint32_t i = 0; i < MAX_PWMS; i++) { - if (pin[GPIO_PWM1 +i] < 99) { - pinMode(pin[GPIO_PWM1 +i], OUTPUT); - if (light_type) { - - analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range : 0); - } else { - pwm_present = true; - analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]); - } - } - } - - for (uint32_t i = 0; i < MAX_RELAYS; i++) { - if (pin[GPIO_REL1 +i] < 99) { - pinMode(pin[GPIO_REL1 +i], OUTPUT); - devices_present++; -#ifdef ESP8266 - if (EXS_RELAY == my_module_type) { - digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0); - if (i &1) { devices_present--; } - } -#endif - } - } - - for (uint32_t i = 0; i < MAX_LEDS; i++) { - if (pin[GPIO_LED1 +i] < 99) { -#ifdef USE_ARILUX_RF - if ((3 == i) && (leds_present < 2) && (99 == pin[GPIO_ARIRFSEL])) { - pin[GPIO_ARIRFSEL] = pin[GPIO_LED4]; - pin[GPIO_LED4] = 99; - } else { -#endif - pinMode(pin[GPIO_LED1 +i], OUTPUT); - leds_present++; - digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i)); -#ifdef USE_ARILUX_RF - } -#endif - } - } - if (pin[GPIO_LEDLNK] < 99) { - pinMode(pin[GPIO_LEDLNK], OUTPUT); - digitalWrite(pin[GPIO_LEDLNK], ledlnk_inverted); - } - -#ifdef USE_PWM_DIMMER - if (PWM_DIMMER == my_module_type && pin[GPIO_REL1] < 99) devices_present--; -#endif - - ButtonInit(); - SwitchInit(); -#ifdef ROTARY_V1 - RotaryInit(); -#endif - - SetLedPower(Settings.ledstate &8); - SetLedLink(Settings.ledstate &8); - - XdrvCall(FUNC_PRE_INIT); -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_udp.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_udp.ino" -#ifdef USE_EMULATION - -#define UDP_BUFFER_SIZE 200 -#define UDP_MSEARCH_SEND_DELAY 1500 - -#include -Ticker TickerMSearch; - -IPAddress udp_remote_ip; -uint16_t udp_remote_port; - -bool udp_connected = false; -bool udp_response_mutex = false; - - - - - -const char URN_BELKIN_DEVICE[] PROGMEM = "urn:belkin:device:**"; -const char URN_BELKIN_DEVICE_CAP[] PROGMEM = "urn:Belkin:device:**"; -const char UPNP_ROOTDEVICE[] PROGMEM = "upnp:rootdevice"; -const char SSDPSEARCH_ALL[] PROGMEM = "ssdpsearch:all"; -const char SSDP_ALL[] PROGMEM = "ssdp:all"; - - - - - -bool UdpDisconnect(void) -{ - if (udp_connected) { - PortUdp.flush(); - WiFiUDP::stopAll(); - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_MULTICAST_DISABLED)); - udp_connected = false; - } - return udp_connected; -} - -bool UdpConnect(void) -{ - if (!udp_connected && !restart_flag) { - - if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED)); - udp_response_mutex = false; - udp_connected = true; - } else { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_JOIN_FAILED)); - udp_connected = false; - } - } - return udp_connected; -} - -void PollUdp(void) -{ - if (udp_connected) { - while (PortUdp.parsePacket()) { - char packet_buffer[UDP_BUFFER_SIZE]; - - int len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1); - packet_buffer[len] = 0; - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len); - - - - if (Settings.flag2.emulation) { -#if defined(USE_SCRIPT_HUE) || defined(USE_ZIGBEE) - if (!udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) { -#else - if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) { -#endif - udp_response_mutex = true; - - udp_remote_ip = PortUdp.remoteIP(); - udp_remote_port = PortUdp.remotePort(); - - - - - uint32_t response_delay = UDP_MSEARCH_SEND_DELAY + ((millis() &0x7) * 100); - - LowerCase(packet_buffer, packet_buffer); - RemoveSpace(packet_buffer); - -#ifdef USE_EMULATION_WEMO - if (EMUL_WEMO == Settings.flag2.emulation) { - if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { - TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 1); - return; - } - else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || - (strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) || - (strstr_P(packet_buffer, SSDP_ALL) != nullptr)) { - TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 2); - return; - } - } -#endif - -#ifdef USE_EMULATION_HUE - if (EMUL_HUE == Settings.flag2.emulation) { - if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) || - (strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || - (strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) || - (strstr_P(packet_buffer, SSDP_ALL) != nullptr)) { - TickerMSearch.attach_ms(response_delay, HueRespondToMSearch); - return; - } - } -#endif - - udp_response_mutex = false; - continue; - } - } - -#ifdef USE_DEVICE_GROUPS - if (Settings.flag4.device_groups_enabled && !strncmp_P(packet_buffer, kDeviceGroupMessage, sizeof(DEVICE_GROUP_MESSAGE) - 1)) { - ProcessDeviceGroupMessage(packet_buffer, len); - } -#endif - } - optimistic_yield(100); - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_wifi.ino" -# 29 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_wifi.ino" -#ifndef WIFI_RSSI_THRESHOLD -#define WIFI_RSSI_THRESHOLD 10 -#endif -#ifndef WIFI_RESCAN_MINUTES -#define WIFI_RESCAN_MINUTES 44 -#endif - -const uint8_t WIFI_CONFIG_SEC = 180; -const uint8_t WIFI_CHECK_SEC = 20; -const uint8_t WIFI_RETRY_OFFSET_SEC = 12; - -#include -#if LWIP_IPV6 -#include -#endif - -struct WIFI { - uint32_t last_event = 0; - uint32_t downtime = 0; - uint16_t link_count = 0; - uint8_t counter; - uint8_t retry_init; - uint8_t retry; - uint8_t status; - uint8_t config_type = 0; - uint8_t config_counter = 0; - uint8_t mdns_begun = 0; - uint8_t scan_state; - uint8_t bssid[6]; - int8_t best_network_db; -} Wifi; - -int WifiGetRssiAsQuality(int rssi) -{ - int quality = 0; - - if (rssi <= -100) { - quality = 0; - } else if (rssi >= -50) { - quality = 100; - } else { - quality = 2 * (rssi + 100); - } - return quality; -} - -bool WifiConfigCounter(void) -{ - if (Wifi.config_counter) { - Wifi.config_counter = WIFI_CONFIG_SEC; - } - return (Wifi.config_counter); -} - -void WifiConfig(uint8_t type) -{ - if (!Wifi.config_type) { - if ((WIFI_RETRY == type) || (WIFI_WAIT == type)) { return; } -#ifdef USE_EMULATION - UdpDisconnect(); -#endif - WiFi.disconnect(); - Wifi.config_type = type; - -#ifndef USE_WEBSERVER - if (WIFI_MANAGER == Wifi.config_type) { - Wifi.config_type = WIFI_SERIAL; - } -#endif - - Wifi.config_counter = WIFI_CONFIG_SEC; - Wifi.counter = Wifi.config_counter +5; - blinks = 1999; - if (WIFI_RESTART == Wifi.config_type) { - restart_flag = 2; - } - else if (WIFI_SERIAL == Wifi.config_type) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_6_SERIAL " " D_ACTIVE_FOR_3_MINUTES)); - } -#ifdef USE_WEBSERVER - else if (WIFI_MANAGER == Wifi.config_type || WIFI_MANAGER_RESET_ONLY == Wifi.config_type) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES)); - WifiManagerBegin(WIFI_MANAGER_RESET_ONLY == Wifi.config_type); - } -#endif - } -} - -void WifiSetMode(WiFiMode_t wifi_mode) -{ - if (WiFi.getMode() == wifi_mode) { return; } - - if (wifi_mode != WIFI_OFF) { - - WiFi.forceSleepWake(); - delay(100); - } - - uint32_t retry = 2; - while (!WiFi.mode(wifi_mode) && retry--) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR("Retry set Mode...")); - delay(100); - } - - if (wifi_mode == WIFI_OFF) { - delay(1000); - WiFi.forceSleepBegin(); - delay(1); - } else { - delay(30); - } -} - -void WiFiSetSleepMode(void) -{ -# 157 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_wifi.ino" -#if defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) -#else - if (ssleep && Settings.flag3.sleep_normal) { - WiFi.setSleepMode(WIFI_LIGHT_SLEEP); - } else { - WiFi.setSleepMode(WIFI_MODEM_SLEEP); - } -#endif - WifiSetOutputPower(); -} - -void WifiBegin(uint8_t flag, uint8_t channel) -{ - const char kWifiPhyMode[] = " BGN"; - -#ifdef USE_EMULATION - UdpDisconnect(); -#endif - -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_PATCH_ISSUE_2186)); - - WifiSetMode(WIFI_OFF); -#endif - - WiFi.persistent(false); - WiFi.disconnect(true); - delay(200); - - WifiSetMode(WIFI_STA); - WiFiSetSleepMode(); - - - if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); } - - switch (flag) { - case 0: - case 1: - Settings.sta_active = flag; - break; - case 2: - Settings.sta_active ^= 1; - } - if (!strlen(SettingsText(SET_STASSID1 + Settings.sta_active))) { - Settings.sta_active ^= 1; - } - if (Settings.ip_address[0]) { - WiFi.config(Settings.ip_address[0], Settings.ip_address[1], Settings.ip_address[2], Settings.ip_address[3]); - } - WiFi.hostname(my_hostname); - - char stemp[40] = { 0 }; - if (channel) { - WiFi.begin(SettingsText(SET_STASSID1 + Settings.sta_active), SettingsText(SET_STAPWD1 + Settings.sta_active), channel, Wifi.bssid); - - char hex_char[18]; - snprintf_P(stemp, sizeof(stemp), PSTR(" Channel %d BSSId %s"), channel, ToHex_P((unsigned char*)Wifi.bssid, 6, hex_char, sizeof(hex_char), ':')); - } else { - WiFi.begin(SettingsText(SET_STASSID1 + Settings.sta_active), SettingsText(SET_STAPWD1 + Settings.sta_active)); - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECTING_TO_AP "%d %s%s " D_IN_MODE " 11%c " D_AS " %s..."), - Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), stemp, kWifiPhyMode[WiFi.getPhyMode() & 0x3], my_hostname); - -#if LWIP_IPV6 - for (bool configured = false; !configured;) { - uint16_t cfgcnt = 0; - for (auto addr : addrList) { - if ((configured = !addr.isLocal() && addr.isV6()) || cfgcnt==30) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI "Got IPv6 global address %s"), addr.toString().c_str()); - break; - } - delay(500); - cfgcnt++; - } - } -#endif -} - -void WifiBeginAfterScan(void) -{ - - if (0 == Wifi.scan_state) { return; } - - if (1 == Wifi.scan_state) { - memset((void*) &Wifi.bssid, 0, sizeof(Wifi.bssid)); - Wifi.best_network_db = -127; - Wifi.scan_state = 3; - } - - if (2 == Wifi.scan_state) { - uint8_t* bssid = WiFi.BSSID(); - memcpy((void*) &Wifi.bssid, (void*) bssid, sizeof(Wifi.bssid)); - Wifi.best_network_db = WiFi.RSSI(); - if (Wifi.best_network_db < -WIFI_RSSI_THRESHOLD) { - Wifi.best_network_db += WIFI_RSSI_THRESHOLD; - } - Wifi.scan_state = 3; - } - - if (3 == Wifi.scan_state) { - if (WiFi.scanComplete() != WIFI_SCAN_RUNNING) { - WiFi.scanNetworks(true); - Wifi.scan_state++; - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR("Network (re)scan started...")); - return; - } - } - int8_t wifi_scan_result = WiFi.scanComplete(); - - if (4 == Wifi.scan_state) { - if (wifi_scan_result != WIFI_SCAN_RUNNING) { - Wifi.scan_state++; - } - } - - if (5 == Wifi.scan_state) { - int32_t channel = 0; - int8_t ap = 3; - uint8_t last_bssid[6]; - memcpy((void*) &last_bssid, (void*) &Wifi.bssid, sizeof(last_bssid)); - - if (wifi_scan_result > 0) { - - for (uint32_t i = 0; i < wifi_scan_result; ++i) { - - String ssid_scan; - int32_t rssi_scan; - uint8_t sec_scan; - uint8_t* bssid_scan; - int32_t chan_scan; - bool hidden_scan; - - WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, bssid_scan, chan_scan, hidden_scan); - - bool known = false; - uint32_t j; - for (j = 0; j < MAX_SSIDS; j++) { - if (ssid_scan == SettingsText(SET_STASSID1 + j)) { - known = true; - if (rssi_scan > Wifi.best_network_db) { - if (sec_scan == ENC_TYPE_NONE || SettingsText(SET_STAPWD1 + j)) { - Wifi.best_network_db = (int8_t)rssi_scan; - channel = chan_scan; - ap = j; - memcpy((void*) &Wifi.bssid, (void*) bssid_scan, sizeof(Wifi.bssid)); - } - } - break; - } - } - char hex_char[18]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "Network %d, AP%c, SSId %s, Channel %d, BSSId %s, RSSI %d, Encryption %d"), - i, - (known) ? (j) ? '2' : '1' : '-', - ssid_scan.c_str(), - chan_scan, - ToHex_P((unsigned char*)bssid_scan, 6, hex_char, sizeof(hex_char), ':'), - rssi_scan, - (sec_scan == ENC_TYPE_NONE) ? 0 : 1); - delay(0); - } - WiFi.scanDelete(); - delay(0); - } - Wifi.scan_state = 0; - - for (uint32_t i = 0; i < sizeof(Wifi.bssid); i++) { - if (last_bssid[i] != Wifi.bssid[i]) { - WifiBegin(ap, channel); - break; - } - } - } -} - -uint16_t WifiLinkCount(void) -{ - return Wifi.link_count; -} - -String WifiDowntime(void) -{ - return GetDuration(Wifi.downtime); -} - -void WifiSetState(uint8_t state) -{ - if (state == global_state.wifi_down) { - if (state) { - rules_flag.wifi_connected = 1; - Wifi.link_count++; - Wifi.downtime += UpTime() - Wifi.last_event; - } else { - rules_flag.wifi_disconnected = 1; - Wifi.last_event = UpTime(); - } - } - global_state.wifi_down = state ^1; -} - -#if LWIP_IPV6 -bool WifiCheckIPv6(void) -{ - bool ipv6_global=false; - - for (auto a : addrList) { - if(!a.isLocal() && a.isV6()) ipv6_global=true; - } - return ipv6_global; -} - -String WifiGetIPv6(void) -{ - for (auto a : addrList) { - if(!a.isLocal() && a.isV6()) return a.toString(); - } - return ""; -} - -bool WifiCheckIPAddrStatus(void) -{ - bool ip_global=false; - - for (auto a : addrList) { - if(!a.isLocal()) ip_global=true; - } - return ip_global; -} -#endif - -void WifiCheckIp(void) -{ -#if LWIP_IPV6 - if(WifiCheckIPAddrStatus()) { - Wifi.status = WL_CONNECTED; -#else - if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0)) { -#endif - WifiSetState(1); - Wifi.counter = WIFI_CHECK_SEC; - Wifi.retry = Wifi.retry_init; - if (Wifi.status != WL_CONNECTED) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECTED)); - - Settings.ip_address[1] = (uint32_t)WiFi.gatewayIP(); - Settings.ip_address[2] = (uint32_t)WiFi.subnetMask(); - Settings.ip_address[3] = (uint32_t)WiFi.dnsIP(); - - - Settings.wifi_channel = WiFi.channel(); - uint8_t *bssid = WiFi.BSSID(); - memcpy((void*) &Settings.wifi_bssid, (void*) bssid, sizeof(Settings.wifi_bssid)); - } - Wifi.status = WL_CONNECTED; -#ifdef USE_DISCOVERY -#ifdef WEBSERVER_ADVERTISE - if (2 == Wifi.mdns_begun) { - MDNS.update(); - AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update"); - } -#endif -#endif - } else { - WifiSetState(0); - uint8_t wifi_config_tool = Settings.sta_config; - Wifi.status = WiFi.status(); - switch (Wifi.status) { - case WL_CONNECTED: - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_NO_IP_ADDRESS)); - Wifi.status = 0; - Wifi.retry = Wifi.retry_init; - break; - case WL_NO_SSID_AVAIL: - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_NOT_REACHED)); - Settings.wifi_channel = 0; - if (WIFI_WAIT == Settings.sta_config) { - Wifi.retry = Wifi.retry_init; - } else { - if (Wifi.retry > (Wifi.retry_init / 2)) { - Wifi.retry = Wifi.retry_init / 2; - } - else if (Wifi.retry) { - Wifi.retry = 0; - } - } - break; - case WL_CONNECT_FAILED: - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_WRONG_PASSWORD)); - Settings.wifi_channel = 0; - if (Wifi.retry > (Wifi.retry_init / 2)) { - Wifi.retry = Wifi.retry_init / 2; - } - else if (Wifi.retry) { - Wifi.retry = 0; - } - break; - default: - if (!Wifi.retry || ((Wifi.retry_init / 2) == Wifi.retry)) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_TIMEOUT)); - Settings.wifi_channel = 0; - } else { - if (!strlen(SettingsText(SET_STASSID1)) && !strlen(SettingsText(SET_STASSID2))) { - Settings.wifi_channel = 0; - wifi_config_tool = WIFI_MANAGER; - Wifi.retry = 0; - } else { - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_ATTEMPTING_CONNECTION)); - } - } - } - if (Wifi.retry) { - if (Settings.flag3.use_wifi_scan) { - if (Wifi.retry_init == Wifi.retry) { - Wifi.scan_state = 1; - } - } else { - if (Wifi.retry_init == Wifi.retry) { - WifiBegin(3, Settings.wifi_channel); - } - if ((Settings.sta_config != WIFI_WAIT) && ((Wifi.retry_init / 2) == Wifi.retry)) { - WifiBegin(2, 0); - } - } - Wifi.counter = 1; - Wifi.retry--; - } else { - WifiConfig(wifi_config_tool); - Wifi.counter = 1; - Wifi.retry = Wifi.retry_init; - } - } -} - -void WifiCheck(uint8_t param) -{ - Wifi.counter--; - switch (param) { - case WIFI_SERIAL: - case WIFI_MANAGER: - WifiConfig(param); - break; - default: - if (Wifi.config_counter) { - Wifi.config_counter--; - Wifi.counter = Wifi.config_counter +5; - if (Wifi.config_counter) { - if (!Wifi.config_counter) { - if (strlen(WiFi.SSID().c_str())) { - SettingsUpdateText(SET_STASSID1, WiFi.SSID().c_str()); - } - if (strlen(WiFi.psk().c_str())) { - SettingsUpdateText(SET_STAPWD1, WiFi.psk().c_str()); - } - Settings.sta_active = 0; - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_WCFG_2_WIFIMANAGER D_CMND_SSID "1 %s"), SettingsText(SET_STASSID1)); - } - } - if (!Wifi.config_counter) { - - restart_flag = 2; - } - } else { - if (Wifi.scan_state) { WifiBeginAfterScan(); } - - if (Wifi.counter <= 0) { - AddLog_P(LOG_LEVEL_DEBUG_MORE, S_LOG_WIFI, PSTR(D_CHECKING_CONNECTION)); - Wifi.counter = WIFI_CHECK_SEC; - WifiCheckIp(); - } -#if LWIP_IPV6 - if (WifiCheckIPAddrStatus()) { -#else - if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0) && !Wifi.config_type) { -#endif - WifiSetState(1); - - if (Settings.flag3.use_wifi_rescan) { - if (!(uptime % (60 * WIFI_RESCAN_MINUTES))) { - Wifi.scan_state = 2; - } - } - -#ifdef FIRMWARE_MINIMAL - if (1 == RtcSettings.ota_loader) { - RtcSettings.ota_loader = 0; - ota_state_flag = 3; - } -#endif - -#ifdef USE_DISCOVERY - if (Settings.flag3.mdns_enabled) { - if (!Wifi.mdns_begun) { - - - - - - Wifi.mdns_begun = (uint8_t)MDNS.begin(my_hostname); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Wifi.mdns_begun) ? D_INITIALIZED : D_FAILED); - - } - } -#endif - -#ifdef USE_WEBSERVER - if (Settings.webserver) { - StartWebserver(Settings.webserver, WiFi.localIP()); -#ifdef USE_DISCOVERY -#ifdef WEBSERVER_ADVERTISE - if (1 == Wifi.mdns_begun) { - Wifi.mdns_begun = 2; - MDNS.addService("http", "tcp", WEB_PORT); - } -#endif -#endif - } else { - StopWebserver(); - } -#ifdef USE_EMULATION -#ifdef USE_DEVICE_GROUPS - if (Settings.flag2.emulation || Settings.flag4.device_groups_enabled) { UdpConnect(); } -#else - if (Settings.flag2.emulation) { UdpConnect(); } -#endif -#endif -#endif - -#ifdef USE_KNX - if (!knx_started && Settings.flag.knx_enabled) { - KNXStart(); - knx_started = true; - } -#endif - - } else { - WifiSetState(0); -#ifdef USE_EMULATION - UdpDisconnect(); -#endif - Wifi.mdns_begun = 0; -#ifdef USE_KNX - knx_started = false; -#endif - } - } - } -} - -int WifiState(void) -{ - int state = -1; - - if (!global_state.wifi_down) { state = WIFI_RESTART; } - if (Wifi.config_type) { state = Wifi.config_type; } - return state; -} - -String WifiGetOutputPower(void) -{ - char stemp1[TOPSZ]; - dtostrfd((float)(Settings.wifi_output_power) / 10, 1, stemp1); - return String(stemp1); -} - -void WifiSetOutputPower(void) -{ - WiFi.setOutputPower((float)(Settings.wifi_output_power) / 10); -} -# 633 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/support_wifi.ino" -#ifdef WIFI_RF_MODE_RF_CAL -#ifndef USE_DEEPSLEEP -RF_MODE(RF_CAL); -#endif -#endif - -#ifdef WIFI_RF_PRE_INIT -bool rf_pre_init_flag = false; -RF_PRE_INIT() -{ -#ifndef USE_DEEPSLEEP - system_deep_sleep_set_option(1); - system_phy_set_rfoption(RF_CAL); -#endif - system_phy_set_powerup_option(3); - rf_pre_init_flag = true; -} -#endif - -void WifiConnect(void) -{ - WifiSetState(0); - WifiSetOutputPower(); - WiFi.persistent(false); - Wifi.status = 0; - Wifi.retry_init = WIFI_RETRY_OFFSET_SEC + (ESP_getChipId() & 0xF); - Wifi.retry = Wifi.retry_init; - Wifi.counter = 1; - - memcpy((void*) &Wifi.bssid, (void*) Settings.wifi_bssid, sizeof(Wifi.bssid)); - -#ifdef WIFI_RF_PRE_INIT - if (rf_pre_init_flag) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "Pre-init done")); - } -#endif -} - -void WifiShutdown(bool option = false) -{ - - - delay(100); - -#ifdef USE_EMULATION - UdpDisconnect(); - delay(100); -#endif - - if (Settings.flag.mqtt_enabled) { - MqttDisconnect(); - delay(100); - } - -#ifdef WIFI_FORCE_RF_CAL_ERASE - if (option) { - WiFi.disconnect(false); - SettingsErase(4); - } else -#endif - { - - - - - ETS_UART_INTR_DISABLE(); - wifi_station_disconnect(); - ETS_UART_INTR_ENABLE(); - - } - delay(100); -} - -void EspRestart(void) -{ - ResetPwm(); - WifiShutdown(true); - CrashDumpClear(); - - ESP_reset(); -} - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 - - - -extern "C" { -#if LWIP_VERSION_MAJOR == 1 -#include "netif/wlan_lwip_if.h" -#include "netif/etharp.h" -#else -#include "lwip/etharp.h" -#endif -} - -unsigned long wifiTimer = 0; - -void stationKeepAliveNow(void) { - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_WIFI "Sending Gratuitous ARP")); - for (netif* interface = netif_list; interface != nullptr; interface = interface->next) - if ( - (interface->flags & NETIF_FLAG_LINK_UP) - && (interface->flags & NETIF_FLAG_UP) -#if LWIP_VERSION_MAJOR == 1 - && interface == eagle_lwip_getif(STATION_IF) - && (!ip_addr_isany(&interface->ip_addr)) -#else - && interface->num == STATION_IF - && (!ip4_addr_isany_val(*netif_ip4_addr(interface))) -#endif - ) - { - etharp_gratuitous(interface); - break; - } -} - -void wifiKeepAlive(void) { - uint32_t wifiTimerSec = Settings.param[P_ARP_GRATUITOUS]; - - if ((WL_CONNECTED != Wifi.status) || (0 == wifiTimerSec)) { return; } - - if (TimeReached(wifiTimer)) { - stationKeepAliveNow(); - if (wifiTimerSec > 100) { - wifiTimerSec = (wifiTimerSec - 100) * 60; - } - SetNextTimeInterval(wifiTimer, wifiTimerSec * 1000); - } -} -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota_ca.ino" -# 24 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota_ca.ino" -#ifdef USE_MQTT_TLS_CA_CERT - -#ifndef USE_MQTT_AWS_IOT -# 38 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota_ca.ino" -static const unsigned char PROGMEM TA0_DN[] = { - 0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A, - 0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, - 0x13, 0x1A, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, - 0x79, 0x20, 0x58, 0x33 -}; - -static const unsigned char PROGMEM TA0_RSA_N[] = { - 0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37, - 0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1, - 0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05, - 0xAB, 0xA9, 0x9E, 0x35, 0x08, 0x58, 0xEC, 0xB1, 0x2A, 0xC4, 0x68, 0x87, - 0x0B, 0xA3, 0xE3, 0x75, 0xE4, 0xE6, 0xF3, 0xA7, 0x62, 0x71, 0xBA, 0x79, - 0x81, 0x60, 0x1F, 0xD7, 0x91, 0x9A, 0x9F, 0xF3, 0xD0, 0x78, 0x67, 0x71, - 0xC8, 0x69, 0x0E, 0x95, 0x91, 0xCF, 0xFE, 0xE6, 0x99, 0xE9, 0x60, 0x3C, - 0x48, 0xCC, 0x7E, 0xCA, 0x4D, 0x77, 0x12, 0x24, 0x9D, 0x47, 0x1B, 0x5A, - 0xEB, 0xB9, 0xEC, 0x1E, 0x37, 0x00, 0x1C, 0x9C, 0xAC, 0x7B, 0xA7, 0x05, - 0xEA, 0xCE, 0x4A, 0xEB, 0xBD, 0x41, 0xE5, 0x36, 0x98, 0xB9, 0xCB, 0xFD, - 0x6D, 0x3C, 0x96, 0x68, 0xDF, 0x23, 0x2A, 0x42, 0x90, 0x0C, 0x86, 0x74, - 0x67, 0xC8, 0x7F, 0xA5, 0x9A, 0xB8, 0x52, 0x61, 0x14, 0x13, 0x3F, 0x65, - 0xE9, 0x82, 0x87, 0xCB, 0xDB, 0xFA, 0x0E, 0x56, 0xF6, 0x86, 0x89, 0xF3, - 0x85, 0x3F, 0x97, 0x86, 0xAF, 0xB0, 0xDC, 0x1A, 0xEF, 0x6B, 0x0D, 0x95, - 0x16, 0x7D, 0xC4, 0x2B, 0xA0, 0x65, 0xB2, 0x99, 0x04, 0x36, 0x75, 0x80, - 0x6B, 0xAC, 0x4A, 0xF3, 0x1B, 0x90, 0x49, 0x78, 0x2F, 0xA2, 0x96, 0x4F, - 0x2A, 0x20, 0x25, 0x29, 0x04, 0xC6, 0x74, 0xC0, 0xD0, 0x31, 0xCD, 0x8F, - 0x31, 0x38, 0x95, 0x16, 0xBA, 0xA8, 0x33, 0xB8, 0x43, 0xF1, 0xB1, 0x1F, - 0xC3, 0x30, 0x7F, 0xA2, 0x79, 0x31, 0x13, 0x3D, 0x2D, 0x36, 0xF8, 0xE3, - 0xFC, 0xF2, 0x33, 0x6A, 0xB9, 0x39, 0x31, 0xC5, 0xAF, 0xC4, 0x8D, 0x0D, - 0x1D, 0x64, 0x16, 0x33, 0xAA, 0xFA, 0x84, 0x29, 0xB6, 0xD4, 0x0B, 0xC0, - 0xD8, 0x7D, 0xC3, 0x93 -}; - -static const unsigned char TA0_RSA_E[] = { - 0x01, 0x00, 0x01 -}; - -static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = { - { (unsigned char *)TA0_DN, sizeof TA0_DN }, - BR_X509_TA_CA, - { - BR_KEYTYPE_RSA, - { .rsa = { - (unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N, - (unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E, - } } - } -}; - -#define TAs_NUM 1 - -#endif - -#ifdef USE_MQTT_AWS_IOT -# 106 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/tasmota_ca.ino" -const unsigned char PROGMEM TA0_DN[] = { - 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A, - 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, - 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6D, 0x61, 0x7A, 0x6F, - 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31 -}; - -const unsigned char PROGMEM TA0_RSA_N[] = { - 0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 0x71, 0xAF, 0x47, 0x80, - 0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7, - 0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 0xAC, 0x02, 0x2D, 0x86, - 0xD3, 0xA0, 0x43, 0x7A, 0x4E, 0xB2, 0xA4, 0xD0, 0x36, 0xBA, 0x01, 0xBE, - 0x8D, 0xDB, 0x48, 0xC8, 0x07, 0x17, 0x36, 0x4C, 0xF4, 0xEE, 0x88, 0x23, - 0xC7, 0x3E, 0xEB, 0x37, 0xF5, 0xB5, 0x19, 0xF8, 0x49, 0x68, 0xB0, 0xDE, - 0xD7, 0xB9, 0x76, 0x38, 0x1D, 0x61, 0x9E, 0xA4, 0xFE, 0x82, 0x36, 0xA5, - 0xE5, 0x4A, 0x56, 0xE4, 0x45, 0xE1, 0xF9, 0xFD, 0xB4, 0x16, 0xFA, 0x74, - 0xDA, 0x9C, 0x9B, 0x35, 0x39, 0x2F, 0xFA, 0xB0, 0x20, 0x50, 0x06, 0x6C, - 0x7A, 0xD0, 0x80, 0xB2, 0xA6, 0xF9, 0xAF, 0xEC, 0x47, 0x19, 0x8F, 0x50, - 0x38, 0x07, 0xDC, 0xA2, 0x87, 0x39, 0x58, 0xF8, 0xBA, 0xD5, 0xA9, 0xF9, - 0x48, 0x67, 0x30, 0x96, 0xEE, 0x94, 0x78, 0x5E, 0x6F, 0x89, 0xA3, 0x51, - 0xC0, 0x30, 0x86, 0x66, 0xA1, 0x45, 0x66, 0xBA, 0x54, 0xEB, 0xA3, 0xC3, - 0x91, 0xF9, 0x48, 0xDC, 0xFF, 0xD1, 0xE8, 0x30, 0x2D, 0x7D, 0x2D, 0x74, - 0x70, 0x35, 0xD7, 0x88, 0x24, 0xF7, 0x9E, 0xC4, 0x59, 0x6E, 0xBB, 0x73, - 0x87, 0x17, 0xF2, 0x32, 0x46, 0x28, 0xB8, 0x43, 0xFA, 0xB7, 0x1D, 0xAA, - 0xCA, 0xB4, 0xF2, 0x9F, 0x24, 0x0E, 0x2D, 0x4B, 0xF7, 0x71, 0x5C, 0x5E, - 0x69, 0xFF, 0xEA, 0x95, 0x02, 0xCB, 0x38, 0x8A, 0xAE, 0x50, 0x38, 0x6F, - 0xDB, 0xFB, 0x2D, 0x62, 0x1B, 0xC5, 0xC7, 0x1E, 0x54, 0xE1, 0x77, 0xE0, - 0x67, 0xC8, 0x0F, 0x9C, 0x87, 0x23, 0xD6, 0x3F, 0x40, 0x20, 0x7F, 0x20, - 0x80, 0xC4, 0x80, 0x4C, 0x3E, 0x3B, 0x24, 0x26, 0x8E, 0x04, 0xAE, 0x6C, - 0x9A, 0xC8, 0xAA, 0x0D -}; - -static const unsigned char PROGMEM TA0_RSA_E[] = { - 0x01, 0x00, 0x01 -}; - -const br_x509_trust_anchor PROGMEM AmazonRootCA1_TA = { - { (unsigned char *)TA0_DN, sizeof TA0_DN }, - BR_X509_TA_CA, - { - BR_KEYTYPE_RSA, - { .rsa = { - (unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N, - (unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E, - } } - } -}; - -#define TAs_NUM 1 - -#endif - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_01_webserver.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_01_webserver.ino" -#ifdef USE_WEBSERVER - - - - - - - -#define XDRV_01 1 - -#ifndef WIFI_SOFT_AP_CHANNEL -#define WIFI_SOFT_AP_CHANNEL 1 -#endif - -const uint16_t CHUNKED_BUFFER_SIZE = (MESSZ / 2) - 100; - -const uint16_t HTTP_REFRESH_TIME = 2345; -#define HTTP_RESTART_RECONNECT_TIME 9000 -#define HTTP_OTA_RESTART_RECONNECT_TIME 20000 - -#include -#include - -#ifdef USE_RF_FLASH -uint8_t *efm8bb1_update = nullptr; -#endif - -enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTASLAVE }; - -static const char * HEADER_KEYS[] = { "User-Agent", }; - -const char HTTP_HEADER1[] PROGMEM = - "" - "" - "" - "" - "%s - %s" - - ""; - -const char HTTP_HEAD_STYLE1[] PROGMEM = - "" - - "" - "" - "
" -#ifdef FIRMWARE_MINIMAL - "

" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "

" -#endif - "
" -#ifdef LANGUAGE_MODULE_NAME - "

" D_MODULE " %s

" -#else - "

%s " D_MODULE "

" -#endif - "

%s

"; - -const char HTTP_MSG_SLIDER_GRADIENT[] PROGMEM = - "
" - "" - "
"; -const char HTTP_MSG_SLIDER_SHUTTER[] PROGMEM = - "
" D_CLOSE "" D_OPEN "
" - "
"; - -const char HTTP_MSG_RSTRT[] PROGMEM = - "
" D_DEVICE_WILL_RESTART "

"; - -const char HTTP_FORM_LOGIN[] PROGMEM = - "
" - "
" - "

" D_USER "

" - "

" D_PASSWORD "

" - "
" - "" - "
"; - -const char HTTP_FORM_TEMPLATE[] PROGMEM = - "
 " D_TEMPLATE_PARAMETERS " " - "
"; -const char HTTP_FORM_TEMPLATE_FLAG[] PROGMEM = - "

" - "
 " D_TEMPLATE_FLAGS " 

" - - "

"; - -const char HTTP_FORM_MODULE[] PROGMEM = - "
 " D_MODULE_PARAMETERS " " - "" - "

" D_MODULE_TYPE " (%s)

" - "
"; - -const char HTTP_FORM_WIFI[] PROGMEM = - "
 " D_WIFI_PARAMETERS " " - "" - "

" D_AP1_SSID " (" STA_SSID1 ")

" - "


" - "

" D_AP2_SSID " (" STA_SSID2 ")

" - "


" - "

" D_HOSTNAME " (%s)

" - "

" D_CORS_DOMAIN "

"; - -const char HTTP_FORM_LOG1[] PROGMEM = - "
 " D_LOGGING_PARAMETERS " " - ""; -const char HTTP_FORM_LOG2[] PROGMEM = - "

" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" - "

" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" - "

" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; - -const char HTTP_FORM_OTHER[] PROGMEM = - "
 " D_OTHER_PARAMETERS " " - "" - "

" - "
 " D_TEMPLATE " " - "

" - "

" - "
" - "
" - "

" - "
" - "
" - "
"; - -const char HTTP_FORM_END[] PROGMEM = - "
" - "" - "
"; - -const char HTTP_FORM_RST[] PROGMEM = - "
" - "
 " D_RESTORE_CONFIGURATION " "; -const char HTTP_FORM_UPG[] PROGMEM = - "
" - "
 " D_UPGRADE_BY_WEBSERVER " " - "
" - "
" D_OTA_URL "

" - "
" - "


" - "
 " D_UPGRADE_BY_FILE_UPLOAD " "; -const char HTTP_FORM_RST_UPG[] PROGMEM = - "
" - "

" - "
" - "
" - "
" - ""; - -const char HTTP_FORM_CMND[] PROGMEM = - "


" - "
" - "
" - - ""; - -const char HTTP_TABLE100[] PROGMEM = - "
"; - -const char HTTP_COUNTER[] PROGMEM = - "
"; - -const char HTTP_END[] PROGMEM = - "" - "" - "" - ""; - -const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; -const char HTTP_DEVICE_STATE[] PROGMEM = ""; - -enum ButtonTitle { - BUTTON_RESTART, BUTTON_RESET_CONFIGURATION, - BUTTON_MAIN, BUTTON_CONFIGURATION, BUTTON_INFORMATION, BUTTON_FIRMWARE_UPGRADE, BUTTON_CONSOLE, - BUTTON_MODULE, BUTTON_WIFI, BUTTON_LOGGING, BUTTON_OTHER, BUTTON_TEMPLATE, BUTTON_BACKUP, BUTTON_RESTORE }; -const char kButtonTitle[] PROGMEM = - D_RESTART "|" D_RESET_CONFIGURATION "|" - D_MAIN_MENU "|" D_CONFIGURATION "|" D_INFORMATION "|" D_FIRMWARE_UPGRADE "|" D_CONSOLE "|" - D_CONFIGURE_MODULE "|" D_CONFIGURE_WIFI"|" D_CONFIGURE_LOGGING "|" D_CONFIGURE_OTHER "|" D_CONFIGURE_TEMPLATE "|" D_BACKUP_CONFIGURATION "|" D_RESTORE_CONFIGURATION; -const char kButtonAction[] PROGMEM = - ".|rt|" - ".|cn|in|up|cs|" - "md|wi|lg|co|tp|dl|rs"; -const char kButtonConfirm[] PROGMEM = D_CONFIRM_RESTART "|" D_CONFIRM_RESET_CONFIGURATION; - -enum CTypes { CT_HTML, CT_PLAIN, CT_XML, CT_JSON, CT_STREAM }; -const char kContentTypes[] PROGMEM = "text/html|text/plain|text/xml|application/json|application/octet-stream"; - -const char kLoggingOptions[] PROGMEM = D_SERIAL_LOG_LEVEL "|" D_WEB_LOG_LEVEL "|" D_MQTT_LOG_LEVEL "|" D_SYS_LOG_LEVEL; -const char kLoggingLevels[] PROGMEM = D_NONE "|" D_ERROR "|" D_INFO "|" D_DEBUG "|" D_MORE_DEBUG; - -const char kEmulationOptions[] PROGMEM = D_NONE "|" D_BELKIN_WEMO "|" D_HUE_BRIDGE; - -const char kUploadErrors[] PROGMEM = - D_UPLOAD_ERR_1 "|" D_UPLOAD_ERR_2 "|" D_UPLOAD_ERR_3 "|" D_UPLOAD_ERR_4 "|" D_UPLOAD_ERR_5 "|" D_UPLOAD_ERR_6 "|" D_UPLOAD_ERR_7 "|" D_UPLOAD_ERR_8 "|" D_UPLOAD_ERR_9 -#ifdef USE_RF_FLASH - "|" D_UPLOAD_ERR_10 "|" D_UPLOAD_ERR_11 "|" D_UPLOAD_ERR_12 "|" D_UPLOAD_ERR_13 -#endif - "|" D_UPLOAD_ERR_14 - ; - -const uint16_t DNS_PORT = 53; -enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY}; - -DNSServer *DnsServer; -ESP8266WebServer *Webserver; - -struct WEB { - String chunk_buffer = ""; - bool reset_web_log_flag = false; - uint8_t state = HTTP_OFF; - uint8_t upload_error = 0; - uint8_t upload_file_type; - uint8_t upload_progress_dot_count; - uint8_t config_block_count = 0; - uint8_t config_xor_on = 0; - uint8_t config_xor_on_set = CONFIG_FILE_XOR; -} Web; - - -static void WebGetArg(const char* arg, char* out, size_t max) -{ - String s = Webserver->arg(arg); - strlcpy(out, s.c_str(), max); - -} - -static bool WifiIsInManagerMode(){ - return (HTTP_MANAGER == Web.state || HTTP_MANAGER_RESET_ONLY == Web.state); -} - -void ShowWebSource(uint32_t source) -{ - if ((source > 0) && (source < SRC_MAX)) { - char stemp1[20]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), Webserver->client().remoteIP().toString().c_str()); - } -} - -void ExecuteWebCommand(char* svalue, uint32_t source) -{ - ShowWebSource(source); - last_source = source; - ExecuteCommand(svalue, SRC_IGNORE); -} - -void StartWebserver(int type, IPAddress ipweb) -{ - if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; } - if (!Web.state) { - if (!Webserver) { - Webserver = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT); - Webserver->on("/", HandleRoot); - Webserver->onNotFound(HandleNotFound); - Webserver->on("/up", HandleUpgradeFirmware); - Webserver->on("/u1", HandleUpgradeFirmwareStart); - Webserver->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop); - Webserver->on("/u2", HTTP_OPTIONS, HandlePreflightRequest); - Webserver->on("/cs", HTTP_GET, HandleConsole); - Webserver->on("/cs", HTTP_OPTIONS, HandlePreflightRequest); - Webserver->on("/cm", HandleHttpCommand); -#ifndef FIRMWARE_MINIMAL - Webserver->on("/cn", HandleConfiguration); - Webserver->on("/md", HandleModuleConfiguration); - Webserver->on("/wi", HandleWifiConfiguration); - Webserver->on("/lg", HandleLoggingConfiguration); - Webserver->on("/tp", HandleTemplateConfiguration); - Webserver->on("/co", HandleOtherConfiguration); - Webserver->on("/dl", HandleBackupConfiguration); - Webserver->on("/rs", HandleRestoreConfiguration); - Webserver->on("/rt", HandleResetConfiguration); - Webserver->on("/in", HandleInformation); - XdrvCall(FUNC_WEB_ADD_HANDLER); - XsnsCall(FUNC_WEB_ADD_HANDLER); -#endif - } - Web.reset_web_log_flag = false; - - - - Webserver->collectHeaders(HEADER_KEYS, sizeof(HEADER_KEYS)/sizeof(char*)); - - Webserver->begin(); - } - if (Web.state != type) { -#if LWIP_IPV6 - String ipv6_addr = WifiGetIPv6(); - if(ipv6_addr!="") AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str(),ipv6_addr.c_str()); - else AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str()); -#else - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str()); -#endif - rules_flag.http_init = 1; - } - if (type) { Web.state = type; } -} - -void StopWebserver(void) -{ - if (Web.state) { - Webserver->close(); - Web.state = HTTP_OFF; - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_STOPPED)); - } -} - -void WifiManagerBegin(bool reset_only) -{ - - if (!global_state.wifi_down) { - - WifiSetMode(WIFI_AP_STA); - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION)); - } else { - - WifiSetMode(WIFI_AP); - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT)); - } - - StopWebserver(); - - DnsServer = new DNSServer(); - - int channel = WIFI_SOFT_AP_CHANNEL; - if ((channel < 1) || (channel > 13)) { channel = 1; } - -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - - WiFi.softAP(my_hostname, WIFI_AP_PASSPHRASE, channel, 0); -#else - - WiFi.softAP(my_hostname, WIFI_AP_PASSPHRASE, channel, 0, 1); -#endif - - delay(500); - - DnsServer->setErrorReplyCode(DNSReplyCode::NoError); - DnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); - - StartWebserver((reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER), WiFi.softAPIP()); -} - -void PollDnsWebserver(void) -{ - if (DnsServer) { DnsServer->processNextRequest(); } - if (Webserver) { Webserver->handleClient(); } -} - - - -bool WebAuthenticate(void) -{ - if (strlen(SettingsText(SET_WEBPWD)) && (HTTP_MANAGER_RESET_ONLY != Web.state)) { - return Webserver->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD)); - } else { - return true; - } -} - -bool HttpCheckPriviledgedAccess(bool autorequestauth = true) -{ - if (HTTP_USER == Web.state) { - HandleRoot(); - return false; - } - if (autorequestauth && !WebAuthenticate()) { - Webserver->requestAuthentication(); - return false; - } - return true; -} - -void HttpHeaderCors(void) -{ - if (strlen(SettingsText(SET_CORS))) { - Webserver->sendHeader(F("Access-Control-Allow-Origin"), SettingsText(SET_CORS)); - } -} - -void WSHeaderSend(void) -{ - Webserver->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); - Webserver->sendHeader(F("Pragma"), F("no-cache")); - Webserver->sendHeader(F("Expires"), F("-1")); - HttpHeaderCors(); -} - - - - - -void WSSend(int code, int ctype, const String& content) -{ - char ct[25]; - Webserver->send(code, GetTextIndexed(ct, sizeof(ct), ctype, kContentTypes), content); -} - - - - - -void WSContentBegin(int code, int ctype) -{ - Webserver->client().flush(); - WSHeaderSend(); -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - Webserver->sendHeader(F("Accept-Ranges"),F("none")); - Webserver->sendHeader(F("Transfer-Encoding"),F("chunked")); -#endif - Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); - WSSend(code, ctype, ""); - Web.chunk_buffer = ""; -} - -void _WSContentSend(const String& content) -{ - size_t len = content.length(); - -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - const char * footer = "\r\n"; - char chunk_size[11]; - sprintf(chunk_size, "%x\r\n", len); - Webserver->sendContent(String() + chunk_size + content + footer); -#else - Webserver->sendContent(content); -#endif - -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("WSContentSend")); -#endif - DEBUG_CORE_LOG(PSTR("WEB: Chunk size %d/%d"), len, sizeof(mqtt_data)); -} - -void WSContentFlush(void) -{ - if (Web.chunk_buffer.length() > 0) { - _WSContentSend(Web.chunk_buffer); - Web.chunk_buffer = ""; - } -} - -void _WSContentSendBuffer(void) -{ - int len = strlen(mqtt_data); - - if (0 == len) { - return; - } - else if (len == sizeof(mqtt_data)) { - AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: Content too large")); - } - else if (len < CHUNKED_BUFFER_SIZE) { - Web.chunk_buffer += mqtt_data; - len = Web.chunk_buffer.length(); - } - - if (len >= CHUNKED_BUFFER_SIZE) { - WSContentFlush(); - } - if (strlen(mqtt_data) >= CHUNKED_BUFFER_SIZE) { - _WSContentSend(mqtt_data); - } -} - -void WSContentSend_P(const char* formatP, ...) -{ - - va_list arg; - va_start(arg, formatP); - int len = vsnprintf_P(mqtt_data, sizeof(mqtt_data), formatP, arg); - va_end(arg); - -#ifdef DEBUG_TASMOTA_CORE - if (len > (sizeof(mqtt_data) -1)) { - mqtt_data[33] = '\0'; - DEBUG_CORE_LOG(PSTR("ERROR: WSContentSend_P size %d > mqtt_data size %d. Start of data [%s...]"), len, sizeof(mqtt_data), mqtt_data); - } -#endif - - _WSContentSendBuffer(); -} - -void WSContentSend_PD(const char* formatP, ...) -{ - - va_list arg; - va_start(arg, formatP); - int len = vsnprintf_P(mqtt_data, sizeof(mqtt_data), formatP, arg); - va_end(arg); - -#ifdef DEBUG_TASMOTA_CORE - if (len > (sizeof(mqtt_data) -1)) { - mqtt_data[33] = '\0'; - DEBUG_CORE_LOG(PSTR("ERROR: WSContentSend_PD size %d > mqtt_data size %d. Start of data [%s...]"), len, sizeof(mqtt_data), mqtt_data); - } -#endif - - if (D_DECIMAL_SEPARATOR[0] != '.') { - for (uint32_t i = 0; i < len; i++) { - if ('.' == mqtt_data[i]) { - mqtt_data[i] = D_DECIMAL_SEPARATOR[0]; - } - } - } - - _WSContentSendBuffer(); -} - -void WSContentStart_P(const char* title, bool auth) -{ - if (auth && strlen(SettingsText(SET_WEBPWD)) && !Webserver->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD))) { - return Webserver->requestAuthentication(); - } - - WSContentBegin(200, CT_HTML); - - if (title != nullptr) { - char ctitle[strlen_P(title) +1]; - strcpy_P(ctitle, title); - WSContentSend_P(HTTP_HEADER1, SettingsText(SET_FRIENDLYNAME1), ctitle); - } -} - -void WSContentStart_P(const char* title) -{ - WSContentStart_P(title, true); -} - -void WSContentSendStyle_P(const char* formatP, ...) -{ - if (WifiIsInManagerMode()) { - if (WifiConfigCounter()) { - WSContentSend_P(HTTP_SCRIPT_COUNTER); - } - } - WSContentSend_P(HTTP_HEAD_LAST_SCRIPT); - - WSContentSend_P(HTTP_HEAD_STYLE1, WebColor(COL_FORM), WebColor(COL_INPUT), WebColor(COL_INPUT_TEXT), WebColor(COL_INPUT), - WebColor(COL_INPUT_TEXT), WebColor(COL_CONSOLE), WebColor(COL_CONSOLE_TEXT), WebColor(COL_BACKGROUND)); - WSContentSend_P(HTTP_HEAD_STYLE2, WebColor(COL_BUTTON), WebColor(COL_BUTTON_TEXT), WebColor(COL_BUTTON_HOVER), - WebColor(COL_BUTTON_RESET), WebColor(COL_BUTTON_RESET_HOVER), WebColor(COL_BUTTON_SAVE), WebColor(COL_BUTTON_SAVE_HOVER), - WebColor(COL_BUTTON)); - if (formatP != nullptr) { - - va_list arg; - va_start(arg, formatP); - int len = vsnprintf_P(mqtt_data, sizeof(mqtt_data), formatP, arg); - va_end(arg); - -#ifdef DEBUG_TASMOTA_CORE - if (len > (sizeof(mqtt_data) -1)) { - mqtt_data[33] = '\0'; - DEBUG_CORE_LOG(PSTR("ERROR: WSContentSendStyle_P size %d > mqtt_data size %d. Start of data [%s...]"), len, sizeof(mqtt_data), mqtt_data); - } -#endif - - _WSContentSendBuffer(); - } - WSContentSend_P(HTTP_HEAD_STYLE3, WebColor(COL_TEXT), -#ifdef FIRMWARE_MINIMAL - WebColor(COL_TEXT_WARNING), -#endif - WebColor(COL_TITLE), - ModuleName().c_str(), SettingsText(SET_FRIENDLYNAME1)); - if (Settings.flag3.gui_hostname_ip) { - bool lip = (static_cast(WiFi.localIP()) != 0); - bool sip = (static_cast(WiFi.softAPIP()) != 0); - WSContentSend_P(PSTR("

%s%s (%s%s%s)

"), - my_hostname, - (Wifi.mdns_begun) ? ".local" : "", - (lip) ? WiFi.localIP().toString().c_str() : "", - (lip && sip) ? ", " : "", - (sip) ? WiFi.softAPIP().toString().c_str() : ""); - } - WSContentSend_P(PSTR("")); -} - -void WSContentSendStyle(void) -{ - WSContentSendStyle_P(nullptr); -} - -void WSContentButton(uint32_t title_index) -{ - char action[4]; - char title[100]; - - if (title_index <= BUTTON_RESET_CONFIGURATION) { - char confirm[100]; - WSContentSend_P(PSTR("

"), - GetTextIndexed(action, sizeof(action), title_index, kButtonAction), - GetTextIndexed(confirm, sizeof(confirm), title_index, kButtonConfirm), - (!title_index) ? "rst" : "non", - GetTextIndexed(title, sizeof(title), title_index, kButtonTitle)); - } else { - WSContentSend_P(PSTR("

"), - GetTextIndexed(action, sizeof(action), title_index, kButtonAction), - GetTextIndexed(title, sizeof(title), title_index, kButtonTitle)); - } -} - -void WSContentSpaceButton(uint32_t title_index) -{ - WSContentSend_P(PSTR("
")); - WSContentButton(title_index); -} - -void WSContentSend_THD(const char *types, float f_temperature, float f_humidity) -{ - char parameter[FLOATSZ]; - dtostrfd(f_temperature, Settings.flag2.temperature_resolution, parameter); - WSContentSend_PD(HTTP_SNS_TEMP, types, parameter, TempUnit()); - dtostrfd(f_humidity, Settings.flag2.humidity_resolution, parameter); - WSContentSend_PD(HTTP_SNS_HUM, types, parameter); - dtostrfd(CalcTempHumToDew(f_temperature, f_humidity), Settings.flag2.temperature_resolution, parameter); - WSContentSend_PD(HTTP_SNS_DEW, types, parameter, TempUnit()); -} - -void WSContentEnd(void) -{ - WSContentFlush(); - _WSContentSend(""); - Webserver->client().stop(); -} - -void WSContentStop(void) -{ - if (WifiIsInManagerMode()) { - if (WifiConfigCounter()) { - WSContentSend_P(HTTP_COUNTER); - } - } - WSContentSend_P(HTTP_END, my_version); - WSContentEnd(); -} - - - -void WebRestart(uint32_t type) -{ - - - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTART); - - bool reset_only = (HTTP_MANAGER_RESET_ONLY == Web.state); - - WSContentStart_P((type) ? S_SAVE_CONFIGURATION : S_RESTART, !reset_only); - WSContentSend_P(HTTP_SCRIPT_RELOAD); - WSContentSendStyle(); - if (type) { - WSContentSend_P(PSTR("
" D_CONFIGURATION_SAVED "
")); - if (2 == type) { - WSContentSend_P(PSTR("
" D_TRYING_TO_CONNECT "
")); - } - WSContentSend_P(PSTR("
")); - } - WSContentSend_P(HTTP_MSG_RSTRT); - if (HTTP_MANAGER == Web.state || reset_only) { - Web.state = HTTP_ADMIN; - } else { - WSContentSpaceButton(BUTTON_MAIN); - } - WSContentStop(); - - ShowWebSource(SRC_WEBGUI); - restart_flag = 2; -} - - - -void HandleWifiLogin(void) -{ - WSContentStart_P(S_CONFIGURE_WIFI, false); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_LOGIN); - - if (HTTP_MANAGER_RESET_ONLY == Web.state) { - WSContentSpaceButton(BUTTON_RESTART); -#ifndef FIRMWARE_MINIMAL - WSContentSpaceButton(BUTTON_RESET_CONFIGURATION); -#endif - } - - WSContentStop(); -} - -#ifdef USE_LIGHT -void WebSliderColdWarm(void) -{ - WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, - "a", - "#fff", "#ff0", - 1, - 153, 500, - LightGetColorTemp(), - 't', 0); -} -#endif - -void HandleRoot(void) -{ - if (CaptivePortal()) { return; } - - if (Webserver->hasArg("rst")) { - WebRestart(0); - return; - } - - if (WifiIsInManagerMode()) { -#ifndef FIRMWARE_MINIMAL - if (strlen(SettingsText(SET_WEBPWD)) && !(Webserver->hasArg("USER1")) && !(Webserver->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != Web.state) { - HandleWifiLogin(); - } else { - if (!strlen(SettingsText(SET_WEBPWD)) || (((Webserver->arg("USER1") == WEB_USERNAME ) && (Webserver->arg("PASS1") == SettingsText(SET_WEBPWD) )) || HTTP_MANAGER_RESET_ONLY == Web.state)) { - HandleWifiConfiguration(); - } else { - - HandleWifiLogin(); - } - } -#endif - return; - } - - if (HandleRootStatusRefresh()) { - return; - } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_MAIN_MENU); - - char stemp[33]; - - WSContentStart_P(S_MAIN_MENU); -#ifdef USE_SCRIPT_WEB_DISPLAY - WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh, Settings.web_refresh); -#else - WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh); -#endif - WSContentSend_P(HTTP_SCRIPT_ROOT_PART2); - - WSContentSendStyle(); - - WSContentSend_P(PSTR("
")); - if (devices_present) { -#ifdef USE_LIGHT - if (light_type) { - uint8_t light_subtype = light_type &7; - if (!Settings.flag3.pwm_multi_channels) { - bool split_white = ((LST_RGBW <= light_subtype) && (devices_present > 1)); - - if ((LST_COLDWARM == light_subtype) || ((LST_RGBCW == light_subtype) && !split_white)) { - WebSliderColdWarm(); - } - - if (light_subtype > 2) { - uint16_t hue; - uint8_t sat; - LightGetHSB(&hue, &sat, nullptr); - - WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, - "b", - "#800", "#f00 5%,#ff0 20%,#0f0 35%,#0ff 50%,#00f 65%,#f0f 80%,#f00 95%,#800", - 2, - 1, 359, - hue, - 'h', 0); - - uint8_t dcolor = changeUIntScale(Settings.light_dimmer, 0, 100, 0, 255); - char scolor[8]; - snprintf_P(scolor, sizeof(scolor), PSTR("#%02X%02X%02X"), dcolor, dcolor, dcolor); - uint8_t red, green, blue; - LightHsToRgb(hue, 255, &red, &green, &blue); - snprintf_P(stemp, sizeof(stemp), PSTR("#%02X%02X%02X"), red, green, blue); - - WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, - "s", - scolor, stemp, - 3, - 0, 100, - changeUIntScale(sat, 0, 255, 0, 100), - 'n', 0); - } - - WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, - "c", - "#000", "#fff", - 4, - Settings.flag3.slider_dimmer_stay_on, 100, - Settings.light_dimmer, - 'd', 0); - - if (split_white) { - if (LST_RGBCW == light_subtype) { - WebSliderColdWarm(); - } - WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, - "f", - "#000", "#fff", - 5, - Settings.flag3.slider_dimmer_stay_on, 100, - LightGetDimmer(2), - 'w', 0); - } - } else { - uint32_t pwm_channels = light_subtype > LST_MAX ? LST_MAX : light_subtype; - stemp[0] = 'e'; stemp[1] = '0'; stemp[2] = '\0'; - for (uint32_t i = 0; i < pwm_channels; i++) { - stemp[1]++; - - WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, - stemp, - "#000", "#fff", - i+1, - 1, 100, - changeUIntScale(Settings.light_color[i], 0, 255, 0, 100), - 'e', i+1); - } - } - } -#endif -#ifdef USE_SHUTTER - if (Settings.flag3.shutter_mode) { - for (uint32_t i = 0; i < shutters_present; i++) { - WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, Settings.shutter_position[i], i+1); - } - } -#endif - WSContentSend_P(HTTP_TABLE100); - WSContentSend_P(PSTR("
")); -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { - WSContentSend_P(HTTP_DEVICE_CONTROL, 36, 1, - (strlen(SettingsText(SET_BUTTON1))) ? SettingsText(SET_BUTTON1) : D_BUTTON_TOGGLE, - ""); - for (uint32_t i = 0; i < MaxFanspeed(); i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); - WSContentSend_P(HTTP_DEVICE_CONTROL, 16, i +2, - (strlen(SettingsText(SET_BUTTON2 + i))) ? SettingsText(SET_BUTTON2 + i) : stemp, - ""); - } - } else { -#endif - for (uint32_t idx = 1; idx <= devices_present; idx++) { - bool set_button = ((idx <= MAX_BUTTON_TEXT) && strlen(SettingsText(SET_BUTTON1 + idx -1))); -#ifdef USE_SHUTTER - int32_t ShutterWebButton; - if (ShutterWebButton = IsShutterWebButton(idx)) { - WSContentSend_P(HTTP_DEVICE_CONTROL, 100 / devices_present, idx, - (set_button) ? SettingsText(SET_BUTTON1 + idx -1) : ((Settings.shutter_options[abs(ShutterWebButton)-1] & 2) ? "-" : ((Settings.shutter_options[abs(ShutterWebButton)-1] & 8) ? ((ShutterWebButton>0) ? "▼" : "▲") : ((ShutterWebButton>0) ? "▲" : "▼"))), - ""); - continue; - } -#endif - snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); - WSContentSend_P(HTTP_DEVICE_CONTROL, 100 / devices_present, idx, - (set_button) ? SettingsText(SET_BUTTON1 + idx -1) : (devices_present < 5) ? D_BUTTON_TOGGLE : "", - (set_button) ? "" : (devices_present > 1) ? stemp : ""); - } -#ifdef USE_SONOFF_IFAN - } -#endif - WSContentSend_P(PSTR("
%s
")); - } -#ifdef USE_SONOFF_RF - if (SONOFF_BRIDGE == my_module_type) { - WSContentSend_P(HTTP_TABLE100); - WSContentSend_P(PSTR("")); - uint32_t idx = 0; - for (uint32_t i = 0; i < 4; i++) { - if (idx > 0) { WSContentSend_P(PSTR("")); } - for (uint32_t j = 0; j < 4; j++) { - idx++; - snprintf_P(stemp, sizeof(stemp), PSTR("%d"), idx); - WSContentSend_P(PSTR(""), idx, - (strlen(SettingsText(SET_BUTTON1 + idx -1))) ? SettingsText(SET_BUTTON1 + idx -1) : stemp); - } - } - WSContentSend_P(PSTR("")); - } -#endif - -#ifndef FIRMWARE_MINIMAL - XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); - XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); -#endif - - if (HTTP_ADMIN == Web.state) { -#ifdef FIRMWARE_MINIMAL - WSContentSpaceButton(BUTTON_FIRMWARE_UPGRADE); -#else - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentButton(BUTTON_INFORMATION); - WSContentButton(BUTTON_FIRMWARE_UPGRADE); -#endif - WSContentButton(BUTTON_CONSOLE); - WSContentButton(BUTTON_RESTART); - } - WSContentStop(); -} - -bool HandleRootStatusRefresh(void) -{ - if (!WebAuthenticate()) { - Webserver->requestAuthentication(); - return true; - } - - if (!Webserver->hasArg("m")) { - return false; - } - - #ifdef USE_SCRIPT_WEB_DISPLAY - Script_Check_HTML_Setvars(); - #endif - - char tmp[8]; - char svalue[32]; - char webindex[5]; - - WebGetArg("o", tmp, sizeof(tmp)); - if (strlen(tmp)) { - ShowWebSource(SRC_WEBGUI); - uint32_t device = atoi(tmp); -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { - if (device < 2) { - ExecuteCommandPower(1, POWER_TOGGLE, SRC_IGNORE); - } else { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_FANSPEED " %d"), device -2); - ExecuteCommand(svalue, SRC_WEBGUI); - } - } else { -#endif -#ifdef USE_SHUTTER - int32_t ShutterWebButton; - if (ShutterWebButton = IsShutterWebButton(device)) { - snprintf_P(svalue, sizeof(svalue), PSTR("ShutterPosition%d %s"), abs(ShutterWebButton), (ShutterWebButton>0) ? PSTR(D_CMND_SHUTTER_STOPOPEN) : PSTR(D_CMND_SHUTTER_STOPCLOSE)); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } else { -#endif - ExecuteCommandPower(device, POWER_TOGGLE, SRC_IGNORE); -#ifdef USE_SHUTTER - } -#endif -#ifdef USE_SONOFF_IFAN - } -#endif - } -#ifdef USE_LIGHT - WebGetArg("d0", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } - WebGetArg("w0", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_WHITE " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } - uint32_t light_device = LightDevice(); - uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7); - for (uint32_t j = 0; j < pwm_channels; j++) { - snprintf_P(webindex, sizeof(webindex), PSTR("e%d"), j +1); - WebGetArg(webindex, tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_CHANNEL "%d %s"), j +light_device, tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } - } - WebGetArg("t0", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } - WebGetArg("h0", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_HSBCOLOR "1 %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } - WebGetArg("n0", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_HSBCOLOR "2 %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } -#endif -#ifdef USE_SHUTTER - for (uint32_t j = 1; j <= shutters_present; j++) { - snprintf_P(webindex, sizeof(webindex), PSTR("u%d"), j); - WebGetArg(webindex, tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR("ShutterPosition%d %s"), j, tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } - } -#endif -#ifdef USE_SONOFF_RF - WebGetArg("k", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RFKEY "%s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); - } -#endif - WSContentBegin(200, CT_HTML); - WSContentSend_P(PSTR("{t}")); - XsnsCall(FUNC_WEB_SENSOR); -#ifdef USE_SCRIPT_WEB_DISPLAY - XdrvCall(FUNC_WEB_SENSOR); -#endif - - WSContentSend_P(PSTR("")); - - if (devices_present) { - WSContentSend_P(PSTR("{t}")); - uint32_t fsize = (devices_present < 5) ? 70 - (devices_present * 8) : 32; -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { - WSContentSend_P(HTTP_DEVICE_STATE, 36, (bitRead(power, 0)) ? "bold" : "normal", 54, GetStateText(bitRead(power, 0))); - uint32_t fanspeed = GetFanspeed(); - snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fanspeed); - WSContentSend_P(HTTP_DEVICE_STATE, 64, (fanspeed) ? "bold" : "normal", 54, (fanspeed) ? svalue : GetStateText(0)); - } else { -#endif - for (uint32_t idx = 1; idx <= devices_present; idx++) { - snprintf_P(svalue, sizeof(svalue), PSTR("%d"), bitRead(power, idx -1)); - WSContentSend_P(HTTP_DEVICE_STATE, 100 / devices_present, (bitRead(power, idx -1)) ? "bold" : "normal", fsize, (devices_present < 5) ? GetStateText(bitRead(power, idx -1)) : svalue); - } -#ifdef USE_SONOFF_IFAN - } -#endif - WSContentSend_P(PSTR("")); - } - WSContentEnd(); - - return true; -} - -#ifdef USE_SHUTTER -int32_t IsShutterWebButton(uint32_t idx) { - - int32_t ShutterWebButton = 0; - if (Settings.flag3.shutter_mode) { - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { - if (Settings.shutter_startrelay[i] && ((Settings.shutter_startrelay[i] == idx) || (Settings.shutter_startrelay[i] == (idx-1)))) { - ShutterWebButton = (Settings.shutter_startrelay[i] == idx) ? (i+1): (-1-i); - break; - } - } - } - return ShutterWebButton; -} -#endif - - - -#ifndef FIRMWARE_MINIMAL - -void HandleConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURATION); - - WSContentStart_P(S_CONFIGURATION); - WSContentSendStyle(); - - WSContentButton(BUTTON_MODULE); - WSContentButton(BUTTON_WIFI); - - XdrvCall(FUNC_WEB_ADD_BUTTON); - XsnsCall(FUNC_WEB_ADD_BUTTON); - - WSContentButton(BUTTON_LOGGING); - WSContentButton(BUTTON_OTHER); - WSContentButton(BUTTON_TEMPLATE); - - WSContentSpaceButton(BUTTON_RESET_CONFIGURATION); - WSContentButton(BUTTON_BACKUP); - WSContentButton(BUTTON_RESTORE); - - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); -} - - - -void HandleTemplateConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - if (Webserver->hasArg("save")) { - TemplateSaveSettings(); - WebRestart(1); - return; - } - - char stemp[30]; - - if (Webserver->hasArg("m")) { - WSContentBegin(200, CT_PLAIN); - for (uint32_t i = 0; i < sizeof(kModuleNiceList); i++) { - uint32_t midx = pgm_read_byte(kModuleNiceList + i); - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, midx, AnyModuleName(midx).c_str(), midx +1); - } - WSContentEnd(); - return; - } - - WebGetArg("t", stemp, sizeof(stemp)); - if (strlen(stemp)) { - uint32_t module = atoi(stemp); - uint32_t module_save = Settings.module; - Settings.module = module; - myio cmodule; - ModuleGpios(&cmodule); - gpio_flag flag = ModuleFlag(); - Settings.module = module_save; - - WSContentBegin(200, CT_PLAIN); - WSContentSend_P(PSTR("%s}1"), AnyModuleName(module).c_str()); - for (uint32_t i = 0; i < sizeof(kGpioNiceList); i++) { - if (1 == i) { - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, 255, D_SENSOR_USER, 255); - } - uint32_t midx = pgm_read_byte(kGpioNiceList + i); - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, midx, GetTextIndexed(stemp, sizeof(stemp), midx, kSensorNames), midx); - } - WSContentSend_P(PSTR("}1")); - - for (uint32_t i = 0; i < ADC0_END; i++) { - if (1 == i) { - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, ADC0_USER, D_SENSOR_USER, ADC0_USER); - } - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, i, GetTextIndexed(stemp, sizeof(stemp), i, kAdc0Names), i); - } - WSContentSend_P(PSTR("}1")); - - for (uint32_t i = 0; i < sizeof(cmodule); i++) { - if (!FlashPin(i)) { - WSContentSend_P(PSTR("%s%d"), (i>0)?",":"", cmodule.io[i]); - } - } - WSContentSend_P(PSTR("}1%d}1%d"), flag, Settings.user_template_base); - WSContentEnd(); - return; - } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TEMPLATE); - - WSContentStart_P(S_CONFIGURE_TEMPLATE); - WSContentSend_P(HTTP_SCRIPT_MODULE_TEMPLATE); - WSContentSend_P(HTTP_SCRIPT_TEMPLATE); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_TEMPLATE); - WSContentSend_P(HTTP_TABLE100); - WSContentSend_P(PSTR("" D_TEMPLATE_NAME "" - "" D_BASE_TYPE "" - "" - "
")); - WSContentSend_P(HTTP_TABLE100); - for (uint32_t i = 0; i < MAX_GPIO_PIN; i++) { - if (!FlashPin(i)) { - WSContentSend_P(PSTR("" D_GPIO "%d"), - ((9==i)||(10==i)) ? WebColor(COL_TEXT_WARNING) : WebColor(COL_TEXT), i, (0==i) ? " style='width:200px'" : "", i); - } - } -#ifdef ESP8266 - WSContentSend_P(PSTR("" D_ADC "0"), WebColor(COL_TEXT)); -#endif - WSContentSend_P(PSTR("")); - gpio_flag flag = ModuleFlag(); - if (flag.data > ADC0_USER) { - WSContentSend_P(HTTP_FORM_TEMPLATE_FLAG); - } - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void TemplateSaveSettings(void) -{ - char tmp[TOPSZ]; - char webindex[5]; - char svalue[300]; - - WebGetArg("s1", tmp, sizeof(tmp)); - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " {\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), tmp); - - uint32_t j = 0; - for (uint32_t i = 0; i < sizeof(Settings.user_template.gp); i++) { -#ifdef ESP8266 - if (6 == i) { j = 9; } - if (8 == i) { j = 12; } -#else - if (6 == i) { j = 12; } -#endif - snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), j); - WebGetArg(webindex, tmp, sizeof(tmp)); - uint8_t gpio = atoi(tmp); - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s%d"), svalue, (i>0)?",":"", gpio); - j++; - } - - WebGetArg("g" STR(ADC0_PIN), tmp, sizeof(tmp)); - uint32_t flag = atoi(tmp); - for (uint32_t i = 0; i < GPIO_FLAG_USED; i++) { - snprintf_P(webindex, sizeof(webindex), PSTR("c%d"), i); - uint32_t state = Webserver->hasArg(webindex) << i +4; - flag += state; - } - WebGetArg("g99", tmp, sizeof(tmp)); - uint32_t base = atoi(tmp) +1; - - snprintf_P(svalue, sizeof(svalue), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), svalue, flag, base); - ExecuteWebCommand(svalue, SRC_WEBGUI); -} - - - -void HandleModuleConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - if (Webserver->hasArg("save")) { - ModuleSaveSettings(); - WebRestart(1); - return; - } - - char stemp[30]; - uint32_t midx; - myio cmodule; - ModuleGpios(&cmodule); - - if (Webserver->hasArg("m")) { - WSContentBegin(200, CT_PLAIN); - uint32_t vidx = 0; - for (uint32_t i = 0; i <= sizeof(kModuleNiceList); i++) { - if (0 == i) { - midx = USER_MODULE; - vidx = 0; - } else { - midx = pgm_read_byte(kModuleNiceList + i -1); - vidx = midx +1; - } - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, midx, AnyModuleName(midx).c_str(), vidx); - } - WSContentEnd(); - return; - } - - if (Webserver->hasArg("g")) { - WSContentBegin(200, CT_PLAIN); - for (uint32_t j = 0; j < sizeof(kGpioNiceList); j++) { - midx = pgm_read_byte(kGpioNiceList + j); - if (!GetUsedInModule(midx, cmodule.io)) { - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, midx, GetTextIndexed(stemp, sizeof(stemp), midx, kSensorNames), midx); - } - } - WSContentEnd(); - return; - } - -#ifndef USE_ADC_VCC - if (Webserver->hasArg("a")) { - WSContentBegin(200, CT_PLAIN); - for (uint32_t j = 0; j < ADC0_END; j++) { - WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, j, GetTextIndexed(stemp, sizeof(stemp), j, kAdc0Names), j); - } - WSContentEnd(); - return; - } -#endif - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE); - - WSContentStart_P(S_CONFIGURE_MODULE); - WSContentSend_P(HTTP_SCRIPT_MODULE_TEMPLATE); - WSContentSend_P(HTTP_SCRIPT_MODULE1, Settings.module); - for (uint32_t i = 0; i < sizeof(cmodule); i++) { - if (ValidGPIO(i, cmodule.io[i])) { - WSContentSend_P(PSTR("sk(%d,%d);"), my_module.io[i], i); - } - } - WSContentSend_P(HTTP_SCRIPT_MODULE2, Settings.my_adc0); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_MODULE, AnyModuleName(MODULE).c_str()); - for (uint32_t i = 0; i < sizeof(cmodule); i++) { - if (ValidGPIO(i, cmodule.io[i])) { - snprintf_P(stemp, 3, PINS_WEMOS +i*2); -#ifdef ESP8266 - char sesp8285[40]; - snprintf_P(sesp8285, sizeof(sesp8285), PSTR("ESP8285"), WebColor(COL_TEXT_WARNING)); - WSContentSend_P(PSTR("%s " D_GPIO "%d %s"), - (WEMOS==my_module_type)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :((9==i)||(10==i))? sesp8285 :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i); -#else - WSContentSend_P(PSTR("%s " D_GPIO "%d"), - (WEMOS==my_module_type)?stemp:"", i, i); -#endif - } - } -#ifdef ESP8266 -#ifndef USE_ADC_VCC - if (ValidAdc()) { - WSContentSend_P(PSTR("%s " D_ADC "0"), (WEMOS==my_module_type)?"A0":""); - } -#endif -#endif - WSContentSend_P(PSTR("")); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void ModuleSaveSettings(void) -{ - char tmp[8]; - char webindex[5]; - - WebGetArg("g99", tmp, sizeof(tmp)); - uint32_t new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); - Settings.last_module = Settings.module; - Settings.module = new_module; - SetModuleType(); - myio cmodule; - ModuleGpios(&cmodule); - String gpios = ""; - for (uint32_t i = 0; i < sizeof(cmodule); i++) { - if (Settings.last_module != new_module) { - Settings.my_gp.io[i] = GPIO_NONE; - } else { - if (ValidGPIO(i, cmodule.io[i])) { - snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), i); - WebGetArg(webindex, tmp, sizeof(tmp)); - uint8_t value = (!strlen(tmp)) ? 0 : atoi(tmp); -#ifdef ESP8266 - Settings.my_gp.io[i] = value; -#else - if (i == ADC0_PIN) { - Settings.my_adc0 = value; - } else { - Settings.my_gp.io[i] = value; - } -#endif - gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(value); - } - } - } -#ifdef ESP8266 -#ifndef USE_ADC_VCC - - WebGetArg("g" STR(ADC0_PIN), tmp, sizeof(tmp)); - Settings.my_adc0 = (!strlen(tmp)) ? 0 : atoi(tmp); - gpios += F(", " D_ADC "0 "); gpios += String(Settings.my_adc0); -#endif -#endif - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str()); -} - - - -const char kUnescapeCode[] = "&><\"\'"; -const char kEscapeCode[] PROGMEM = "&|>|<|"|'"; - -String HtmlEscape(const String unescaped) { - char escaped[10]; - size_t ulen = unescaped.length(); - String result = ""; - for (size_t i = 0; i < ulen; i++) { - char c = unescaped[i]; - char *p = strchr(kUnescapeCode, c); - if (p != nullptr) { - result += GetTextIndexed(escaped, sizeof(escaped), p - kUnescapeCode, kEscapeCode); - } else { - result += c; - } - } - return result; -} - - -const char kEncryptionType[] PROGMEM = "|||" D_WPA_PSK "||" D_WPA2_PSK "|" D_WEP "||" D_NONE "|" D_AUTO; - -void HandleWifiConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); - - if (Webserver->hasArg("save") && HTTP_MANAGER_RESET_ONLY != Web.state) { - WifiSaveSettings(); - WebRestart(2); - return; - } - - WSContentStart_P(S_CONFIGURE_WIFI, !WifiIsInManagerMode()); - WSContentSend_P(HTTP_SCRIPT_WIFI); - WSContentSendStyle(); - - if (HTTP_MANAGER_RESET_ONLY != Web.state) { - if (Webserver->hasArg("scan")) { -#ifdef USE_EMULATION - UdpDisconnect(); -#endif - int n = WiFi.scanNetworks(); - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SCAN_DONE)); - - if (0 == n) { - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, S_NO_NETWORKS_FOUND); - WSContentSend_P(S_NO_NETWORKS_FOUND); - WSContentSend_P(PSTR(". " D_REFRESH_TO_SCAN_AGAIN ".")); - } else { - - int indices[n]; - for (uint32_t i = 0; i < n; i++) { - indices[i] = i; - } - - - for (uint32_t i = 0; i < n; i++) { - for (uint32_t j = i + 1; j < n; j++) { - if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { - std::swap(indices[i], indices[j]); - } - } - } - - - String cssid; - for (uint32_t i = 0; i < n; i++) { - if (-1 == indices[i]) { continue; } - cssid = WiFi.SSID(indices[i]); - uint32_t cschn = WiFi.channel(indices[i]); - for (uint32_t j = i + 1; j < n; j++) { - if ((cssid == WiFi.SSID(indices[j])) && (cschn == WiFi.channel(indices[j]))) { - DEBUG_CORE_LOG(PSTR(D_LOG_WIFI D_DUPLICATE_ACCESSPOINT " %s"), WiFi.SSID(indices[j]).c_str()); - indices[j] = -1; - } - } - } - - - for (uint32_t i = 0; i < n; i++) { - if (-1 == indices[i]) { continue; } - int32_t rssi = WiFi.RSSI(indices[i]); - DEBUG_CORE_LOG(PSTR(D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d"), - WiFi.SSID(indices[i]).c_str(), WiFi.BSSIDstr(indices[i]).c_str(), WiFi.channel(indices[i]), rssi); - int quality = WifiGetRssiAsQuality(rssi); - int auth = WiFi.encryptionType(indices[i]); - char encryption[20]; - WSContentSend_P(PSTR("
%s (%d) %s %d%% (%d dBm)
"), - HtmlEscape(WiFi.SSID(indices[i])).c_str(), - WiFi.channel(indices[i]), - GetTextIndexed(encryption, sizeof(encryption), auth +1, kEncryptionType), - quality, rssi - ); - delay(0); - - } - WSContentSend_P(PSTR("
")); - } - } else { - WSContentSend_P(PSTR("
")); - } - - - WSContentSend_P(HTTP_FORM_WIFI, SettingsText(SET_STASSID1), SettingsText(SET_STASSID2), WIFI_HOSTNAME, WIFI_HOSTNAME, SettingsText(SET_HOSTNAME), SettingsText(SET_CORS)); - WSContentSend_P(HTTP_FORM_END); - } - - if (WifiIsInManagerMode()) { -#ifndef FIRMWARE_MINIMAL - WSContentSpaceButton(BUTTON_RESTORE); - WSContentButton(BUTTON_RESET_CONFIGURATION); -#endif - WSContentSpaceButton(BUTTON_RESTART); - } else { - WSContentSpaceButton(BUTTON_CONFIGURATION); - } - WSContentStop(); -} - -void WifiSaveSettings(void) -{ - char tmp[TOPSZ]; - - WebGetArg("h", tmp, sizeof(tmp)); - SettingsUpdateText(SET_HOSTNAME, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp); - if (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) { - SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); - } - WebGetArg("c", tmp, sizeof(tmp)); - SettingsUpdateText(SET_CORS, (!strlen(tmp)) ? CORS_DOMAIN : tmp); - WebGetArg("s1", tmp, sizeof(tmp)); - SettingsUpdateText(SET_STASSID1, (!strlen(tmp)) ? STA_SSID1 : tmp); - WebGetArg("s2", tmp, sizeof(tmp)); - SettingsUpdateText(SET_STASSID2, (!strlen(tmp)) ? STA_SSID2 : tmp); - WebGetArg("p1", tmp, sizeof(tmp)); - SettingsUpdateText(SET_STAPWD1, (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? SettingsText(SET_STAPWD1) : tmp); - WebGetArg("p2", tmp, sizeof(tmp)); - SettingsUpdateText(SET_STAPWD2, (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? SettingsText(SET_STAPWD2) : tmp); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s, " D_CMND_CORS " %s"), - SettingsText(SET_HOSTNAME), SettingsText(SET_STASSID1), SettingsText(SET_STASSID2), SettingsText(SET_CORS)); -} - - - -void HandleLoggingConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING); - - if (Webserver->hasArg("save")) { - LoggingSaveSettings(); - HandleConfiguration(); - return; - } - - WSContentStart_P(S_CONFIGURE_LOGGING); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_LOG1); - char stemp1[45]; - char stemp2[32]; - uint8_t dlevel[4] = { LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_NONE, LOG_LEVEL_NONE }; - for (uint32_t idx = 0; idx < 4; idx++) { - if ((2==idx) && !Settings.flag.mqtt_enabled) { continue; } - uint32_t llevel = (0==idx)?Settings.seriallog_level:(1==idx)?Settings.weblog_level:(2==idx)?Settings.mqttlog_level:Settings.syslog_level; - WSContentSend_P(PSTR("

%s (%s)

")); - } - WSContentSend_P(HTTP_FORM_LOG2, SettingsText(SET_SYSLOG_HOST), Settings.syslog_port, Settings.tele_period); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void LoggingSaveSettings(void) -{ - char tmp[TOPSZ]; - - WebGetArg("l0", tmp, sizeof(tmp)); - SetSeriallog((!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp)); - WebGetArg("l1", tmp, sizeof(tmp)); - Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); - WebGetArg("l2", tmp, sizeof(tmp)); - Settings.mqttlog_level = (!strlen(tmp)) ? MQTT_LOG_LEVEL : atoi(tmp); - WebGetArg("l3", tmp, sizeof(tmp)); - SetSyslog((!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp)); - WebGetArg("lh", tmp, sizeof(tmp)); - SettingsUpdateText(SET_SYSLOG_HOST, (!strlen(tmp)) ? SYS_LOG_HOST : tmp); - WebGetArg("lp", tmp, sizeof(tmp)); - Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp); - WebGetArg("lt", tmp, sizeof(tmp)); - Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp); - if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { - Settings.tele_period = 10; - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_MQTTLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), - Settings.seriallog_level, Settings.weblog_level, Settings.mqttlog_level, Settings.syslog_level, SettingsText(SET_SYSLOG_HOST), Settings.syslog_port, Settings.tele_period); -} - - - -void HandleOtherConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER); - - if (Webserver->hasArg("save")) { - OtherSaveSettings(); - WebRestart(1); - return; - } - - WSContentStart_P(S_CONFIGURE_OTHER); - WSContentSendStyle(); - - TemplateJson(); - char stemp[strlen(mqtt_data) +1]; - strlcpy(stemp, mqtt_data, sizeof(stemp)); - WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "", (Settings.flag.mqtt_enabled) ? " checked" : ""); - - uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { maxfn = 1; } -#endif - for (uint32_t i = 0; i < maxfn; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i +1); - WSContentSend_P(PSTR("" D_FRIENDLY_NAME " %d (" FRIENDLY_NAME "%s)

"), - i +1, - (i) ? stemp : "", - i, - (i) ? stemp : "", - SettingsText(SET_FRIENDLYNAME1 + i)); - } - -#ifdef USE_EMULATION -#if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE) - WSContentSend_P(PSTR("

 " D_EMULATION " 

")); - for (uint32_t i = 0; i < EMUL_MAX; i++) { -#ifndef USE_EMULATION_WEMO - if (i == EMUL_WEMO) { i++; } -#endif -#ifndef USE_EMULATION_HUE - if (i == EMUL_HUE) { i++; } -#endif - if (i < EMUL_MAX) { - WSContentSend_P(PSTR("%s %s
"), - i, i, - (i == Settings.flag2.emulation) ? " checked" : "", - GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions), - (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE); - } - } - WSContentSend_P(PSTR("

")); -#endif -#endif - - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void OtherSaveSettings(void) -{ - char tmp[TOPSZ]; - char webindex[5]; - char friendlyname[TOPSZ]; - char message[LOGSZ]; - - WebGetArg("wp", tmp, sizeof(tmp)); - SettingsUpdateText(SET_WEBPWD, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? SettingsText(SET_WEBPWD) : tmp); - Settings.flag.mqtt_enabled = Webserver->hasArg("b1"); -#ifdef USE_EMULATION - UdpDisconnect(); -#if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE) - WebGetArg("b2", tmp, sizeof(tmp)); - Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); -#endif -#endif - - snprintf_P(message, sizeof(message), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); - for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) { - snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i); - WebGetArg(webindex, tmp, sizeof(tmp)); - snprintf_P(friendlyname, sizeof(friendlyname), PSTR(FRIENDLY_NAME"%d"), i +1); - SettingsUpdateText(SET_FRIENDLYNAME1 +i, (!strlen(tmp)) ? (i) ? friendlyname : FRIENDLY_NAME : tmp); - snprintf_P(message, sizeof(message), PSTR("%s%s %s"), message, (i) ? "," : "", SettingsText(SET_FRIENDLYNAME1 +i)); - } - AddLog_P(LOG_LEVEL_INFO, message); -# 2014 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_01_webserver.ino" - WebGetArg("t1", tmp, sizeof(tmp)); - if (strlen(tmp)) { - snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (Webserver->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : ""); - ExecuteWebCommand(message, SRC_WEBGUI); - } -} - - - -void HandleBackupConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION)); - - if (!SettingsBufferAlloc()) { return; } - - WiFiClient myClient = Webserver->client(); - Webserver->setContentLength(sizeof(Settings)); - - char attachment[TOPSZ]; - - - - - char hostname[sizeof(my_hostname)]; - snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, my_hostname), my_version); - - Webserver->sendHeader(F("Content-Disposition"), attachment); - - WSSend(200, CT_STREAM, ""); - - uint32_t cfg_crc32 = Settings.cfg_crc32; - Settings.cfg_crc32 = GetSettingsCrc32(); - - memcpy(settings_buffer, &Settings, sizeof(Settings)); - if (Web.config_xor_on_set) { - for (uint32_t i = 2; i < sizeof(Settings); i++) { - settings_buffer[i] ^= (Web.config_xor_on_set +i); - } - } - -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - size_t written = myClient.write((const char*)settings_buffer, sizeof(Settings)); - if (written < sizeof(Settings)) { - myClient.write((const char*)settings_buffer +written, sizeof(Settings) -written); - } -#else - myClient.write((const char*)settings_buffer, sizeof(Settings)); -#endif - - SettingsBufferFree(); - - Settings.cfg_crc32 = cfg_crc32; -} - - - -void HandleResetConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESET_CONFIGURATION); - - WSContentStart_P(S_RESET_CONFIGURATION, !WifiIsInManagerMode()); - WSContentSendStyle(); - WSContentSend_P(PSTR("
" D_CONFIGURATION_RESET "
")); - WSContentSend_P(HTTP_MSG_RSTRT); - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); - - char command[CMDSZ]; - snprintf_P(command, sizeof(command), PSTR(D_CMND_RESET " 1")); - ExecuteWebCommand(command, SRC_WEBGUI); -} - -void HandleRestoreConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTORE_CONFIGURATION); - - WSContentStart_P(S_RESTORE_CONFIGURATION); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_RST); - WSContentSend_P(HTTP_FORM_RST_UPG, D_RESTORE); - if (WifiIsInManagerMode()) { - WSContentSpaceButton(BUTTON_MAIN); - } else { - WSContentSpaceButton(BUTTON_CONFIGURATION); - } - WSContentStop(); - - Web.upload_error = 0; - Web.upload_file_type = UPL_SETTINGS; -} - - - -void HandleInformation(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_INFORMATION); - - char stopic[TOPSZ]; - - int freeMem = ESP.getFreeHeap(); - - WSContentStart_P(S_INFORMATION); - - - - WSContentSend_P(HTTP_SCRIPT_INFO_BEGIN); - WSContentSend_P(PSTR("
")); - WSContentSend_P(PSTR(D_PROGRAM_VERSION "}2%s%s"), my_version, my_image); - WSContentSend_P(PSTR("}1" D_BUILD_DATE_AND_TIME "}2%s"), GetBuildDateAndTime().c_str()); - WSContentSend_P(PSTR("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_CORE_RELEASE "/%s"), ESP.getSdkVersion()); - WSContentSend_P(PSTR("}1" D_UPTIME "}2%s"), GetUptime().c_str()); - WSContentSend_P(PSTR("}1" D_FLASH_WRITE_COUNT "}2%d at 0x%X"), Settings.save_flag, GetSettingsAddress()); - WSContentSend_P(PSTR("}1" D_BOOT_COUNT "}2%d"), Settings.bootcount); - WSContentSend_P(PSTR("}1" D_RESTART_REASON "}2%s"), GetResetReason().c_str()); - uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present; -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { maxfn = 1; } -#endif - for (uint32_t i = 0; i < maxfn; i++) { - WSContentSend_P(PSTR("}1" D_FRIENDLY_NAME " %d}2%s"), i +1, SettingsText(SET_FRIENDLYNAME1 +i)); - } - WSContentSend_P(PSTR("}1}2 ")); - int32_t rssi = WiFi.RSSI(); - WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WifiGetRssiAsQuality(rssi), rssi); - WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Wifi.mdns_begun) ? ".local" : ""); -#if LWIP_IPV6 - String ipv6_addr = WifiGetIPv6(); - if(ipv6_addr != ""){ - WSContentSend_P(PSTR("}1 IPv6 Address }2%s"), ipv6_addr.c_str()); - } -#endif - if (static_cast(WiFi.localIP()) != 0) { - WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str()); - WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), IPAddress(Settings.ip_address[1]).toString().c_str()); - WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%s"), IPAddress(Settings.ip_address[2]).toString().c_str()); - WSContentSend_P(PSTR("}1" D_DNS_SERVER "}2%s"), IPAddress(Settings.ip_address[3]).toString().c_str()); - WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str()); - } - if (static_cast(WiFi.softAPIP()) != 0) { - WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.softAPIP().toString().c_str()); - WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str()); - WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str()); - } - WSContentSend_P(PSTR("}1}2 ")); - if (Settings.flag.mqtt_enabled) { - WSContentSend_P(PSTR("}1" D_MQTT_HOST "}2%s"), SettingsText(SET_MQTT_HOST)); - WSContentSend_P(PSTR("}1" D_MQTT_PORT "}2%d"), Settings.mqtt_port); - WSContentSend_P(PSTR("}1" D_MQTT_USER "}2%s"), SettingsText(SET_MQTT_USER)); - WSContentSend_P(PSTR("}1" D_MQTT_CLIENT "}2%s"), mqtt_client); - WSContentSend_P(PSTR("}1" D_MQTT_TOPIC "}2%s"), SettingsText(SET_MQTT_TOPIC)); - uint32_t real_index = SET_MQTT_GRP_TOPIC; - for (uint32_t i = 0; i < MAX_GROUP_TOPICS; i++) { - if (1 == i) { real_index = SET_MQTT_GRP_TOPIC2 -1; } - if (strlen(SettingsText(real_index +i))) { - WSContentSend_P(PSTR("}1" D_MQTT_GROUP_TOPIC " %d}2%s"), 1 +i, GetGroupTopic_P(stopic, "", real_index +i)); - } - } - WSContentSend_P(PSTR("}1" D_MQTT_FULL_TOPIC "}2%s"), GetTopic_P(stopic, CMND, mqtt_topic, "")); - WSContentSend_P(PSTR("}1" D_MQTT " " D_FALLBACK_TOPIC "}2%s"), GetFallbackTopic_P(stopic, "")); - } else { - WSContentSend_P(PSTR("}1" D_MQTT "}2" D_DISABLED)); - } - WSContentSend_P(PSTR("}1}2 ")); - -#ifdef USE_EMULATION - WSContentSend_P(PSTR("}1" D_EMULATION "}2%s"), GetTextIndexed(stopic, sizeof(stopic), Settings.flag2.emulation, kEmulationOptions)); -#else - WSContentSend_P(PSTR("}1" D_EMULATION "}2" D_DISABLED)); -#endif - -#ifdef USE_DISCOVERY - WSContentSend_P(PSTR("}1" D_MDNS_DISCOVERY "}2%s"), (Settings.flag3.mdns_enabled) ? D_ENABLED : D_DISABLED); - if (Settings.flag3.mdns_enabled) { -#ifdef WEBSERVER_ADVERTISE - WSContentSend_P(PSTR("}1" D_MDNS_ADVERTISE "}2" D_WEB_SERVER)); -#else - WSContentSend_P(PSTR("}1" D_MDNS_ADVERTISE "}2" D_DISABLED)); -#endif - } -#else - WSContentSend_P(PSTR("}1" D_MDNS_DISCOVERY "}2" D_DISABLED)); -#endif - - WSContentSend_P(PSTR("}1}2 ")); - WSContentSend_P(PSTR("}1" D_ESP_CHIP_ID "}2%d"), ESP_getChipId()); - WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP_getFlashChipId()); - WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024); - WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024); - WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP_getSketchSize() / 1024); - WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024); - WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%dkB"), freeMem / 1024); - WSContentSend_P(PSTR("
")); - - WSContentSend_P(HTTP_SCRIPT_INFO_END); - WSContentSendStyle(); - - WSContentSend_P(PSTR("" - "
")); - - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); -} -#endif - - - -void HandleUpgradeFirmware(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_FIRMWARE_UPGRADE); - - WSContentStart_P(S_FIRMWARE_UPGRADE); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_UPG, SettingsText(SET_OTAURL)); - WSContentSend_P(HTTP_FORM_RST_UPG, D_UPGRADE); - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); - - Web.upload_error = 0; - Web.upload_file_type = UPL_TASMOTA; -} - -void HandleUpgradeFirmwareStart(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - char command[TOPSZ + 10]; - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPGRADE_STARTED)); - WifiConfigCounter(); - - char otaurl[TOPSZ]; - WebGetArg("o", otaurl, sizeof(otaurl)); - if (strlen(otaurl)) { - snprintf_P(command, sizeof(command), PSTR(D_CMND_OTAURL " %s"), otaurl); - ExecuteWebCommand(command, SRC_WEBGUI); - } - - WSContentStart_P(S_INFORMATION); - WSContentSend_P(HTTP_SCRIPT_RELOAD_OTA); - WSContentSendStyle(); - WSContentSend_P(PSTR("
" D_UPGRADE_STARTED " ...
")); - WSContentSend_P(HTTP_MSG_RSTRT); - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); - - snprintf_P(command, sizeof(command), PSTR(D_CMND_UPGRADE " 1")); - ExecuteWebCommand(command, SRC_WEBGUI); -} - -void HandleUploadDone(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPLOAD_DONE)); - - char error[100]; - - WifiConfigCounter(); - restart_flag = 0; - MqttRetryCounter(0); - - WSContentStart_P(S_INFORMATION); - if (!Web.upload_error) { - WSContentSend_P(HTTP_SCRIPT_RELOAD_OTA); - } - WSContentSendStyle(); - WSContentSend_P(PSTR("
" D_UPLOAD " " D_FAILED "

"), WebColor(COL_TEXT_WARNING)); -#ifdef USE_RF_FLASH - if (Web.upload_error < 15) { -#else - if ((Web.upload_error < 10) || (14 == Web.upload_error)) { - if (14 == Web.upload_error) { Web.upload_error = 10; } -#endif - GetTextIndexed(error, sizeof(error), Web.upload_error -1, kUploadErrors); - } else { - snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), Web.upload_error); - } - WSContentSend_P(error); - DEBUG_CORE_LOG(PSTR("UPL: %s"), error); - stop_flash_rotate = Settings.flag.stop_flash_rotate; - } else { - WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS)); - WSContentSend_P(HTTP_MSG_RSTRT); - ShowWebSource(SRC_WEBGUI); -#ifdef USE_TASMOTA_SLAVE - if (TasmotaSlave_GetFlagFlashing()) { - restart_flag = 0; - } else { - restart_flag = 2; - } -#else - restart_flag = 2; -#endif - } - SettingsBufferFree(); - WSContentSend_P(PSTR("

")); - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); -#ifdef USE_TASMOTA_SLAVE - if (TasmotaSlave_GetFlagFlashing()) { - TasmotaSlave_Flash(); - } -#endif -} - -void HandleUploadLoop(void) -{ - - bool _serialoutput = (LOG_LEVEL_DEBUG <= seriallog_level); - - if (HTTP_USER == Web.state) { return; } - if (Web.upload_error) { - if (UPL_TASMOTA == Web.upload_file_type) { Update.end(); } - return; - } - - HTTPUpload& upload = Webserver->upload(); - - if (UPLOAD_FILE_START == upload.status) { - restart_flag = 60; - if (0 == upload.filename.c_str()[0]) { - Web.upload_error = 1; - return; - } - SettingsSave(1); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_FILE " %s ..."), upload.filename.c_str()); - if (UPL_SETTINGS == Web.upload_file_type) { - if (!SettingsBufferAlloc()) { - Web.upload_error = 2; - return; - } - } else { - MqttRetryCounter(60); -#ifdef USE_EMULATION - UdpDisconnect(); -#endif -#ifdef USE_ARILUX_RF - AriluxRfDisable(); -#endif - if (Settings.flag.mqtt_enabled) { - MqttDisconnect(); - } - uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; - if (!Update.begin(maxSketchSpace)) { - - - - - - - Web.upload_error = 2; - return; - } - } - Web.upload_progress_dot_count = 0; - } else if (!Web.upload_error && (UPLOAD_FILE_WRITE == upload.status)) { - if (0 == upload.totalSize) { - if (UPL_SETTINGS == Web.upload_file_type) { - Web.config_block_count = 0; - } - else { -#ifdef USE_RF_FLASH - if ((SONOFF_BRIDGE == my_module_type) && (upload.buf[0] == ':')) { - Update.end(); - Web.upload_file_type = UPL_EFM8BB1; - - Web.upload_error = SnfBrUpdateInit(); - if (Web.upload_error != 0) { return; } - } else -#endif -#ifdef USE_TASMOTA_SLAVE - if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { - Update.end(); - Web.upload_file_type = UPL_TASMOTASLAVE; - Web.upload_error = TasmotaSlave_UpdateInit(); - if (Web.upload_error != 0) { return; } - } else -#endif - { - if ((upload.buf[0] != 0xE9) && (upload.buf[0] != 0x1F)) { - Web.upload_error = 3; - return; - } - if (0xE9 == upload.buf[0]) { - uint32_t bin_flash_size = ESP.magicFlashChipSize((upload.buf[3] & 0xf0) >> 4); - if (bin_flash_size > ESP.getFlashChipRealSize()) { - Web.upload_error = 4; - return; - } - - } - } - } - } - if (UPL_SETTINGS == Web.upload_file_type) { - if (!Web.upload_error) { - if (upload.currentSize > (sizeof(Settings) - (Web.config_block_count * HTTP_UPLOAD_BUFLEN))) { - Web.upload_error = 9; - return; - } - memcpy(settings_buffer + (Web.config_block_count * HTTP_UPLOAD_BUFLEN), upload.buf, upload.currentSize); - Web.config_block_count++; - } - } -#ifdef USE_RF_FLASH - else if (UPL_EFM8BB1 == Web.upload_file_type) { - if (efm8bb1_update != nullptr) { - ssize_t result = rf_glue_remnant_with_new_data_and_write(efm8bb1_update, upload.buf, upload.currentSize); - free(efm8bb1_update); - efm8bb1_update = nullptr; - if (result != 0) { - Web.upload_error = abs(result); - return; - } - } - ssize_t result = rf_search_and_write(upload.buf, upload.currentSize); - if (result < 0) { - Web.upload_error = abs(result); - return; - } else if (result > 0) { - if ((size_t)result > upload.currentSize) { - - Web.upload_error = 9; - return; - } - - size_t remnant_sz = upload.currentSize - result; - efm8bb1_update = (uint8_t *) malloc(remnant_sz + 1); - if (efm8bb1_update == nullptr) { - Web.upload_error = 2; - return; - } - memcpy(efm8bb1_update, upload.buf + result, remnant_sz); - - efm8bb1_update[remnant_sz] = '\0'; - } - } -#endif -#ifdef USE_TASMOTA_SLAVE - else if (UPL_TASMOTASLAVE == Web.upload_file_type) { - TasmotaSlave_WriteBuffer(upload.buf, upload.currentSize); - } -#endif - else { - if (!Web.upload_error && (Update.write(upload.buf, upload.currentSize) != upload.currentSize)) { - Web.upload_error = 5; - return; - } - if (_serialoutput) { - Serial.printf("."); - Web.upload_progress_dot_count++; - if (!(Web.upload_progress_dot_count % 80)) { Serial.println(); } - } - } - } else if(!Web.upload_error && (UPLOAD_FILE_END == upload.status)) { - if (_serialoutput && (Web.upload_progress_dot_count % 80)) { - Serial.println(); - } - if (UPL_SETTINGS == Web.upload_file_type) { - if (Web.config_xor_on_set) { - for (uint32_t i = 2; i < sizeof(Settings); i++) { - settings_buffer[i] ^= (Web.config_xor_on_set +i); - } - } - bool valid_settings = false; - unsigned long buffer_version = settings_buffer[11] << 24 | settings_buffer[10] << 16 | settings_buffer[9] << 8 | settings_buffer[8]; - if (buffer_version > 0x06000000) { - uint32_t buffer_size = settings_buffer[3] << 8 | settings_buffer[2]; - if (buffer_version > 0x0606000A) { - uint32_t buffer_crc32 = settings_buffer[4095] << 24 | settings_buffer[4094] << 16 | settings_buffer[4093] << 8 | settings_buffer[4092]; - valid_settings = (GetCfgCrc32(settings_buffer, buffer_size -4) == buffer_crc32); - } else { - uint16_t buffer_crc16 = settings_buffer[15] << 8 | settings_buffer[14]; - valid_settings = (GetCfgCrc16(settings_buffer, buffer_size) == buffer_crc16); - } - } else { - valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN); - } - - if (valid_settings) { -#ifdef ESP8266 - valid_settings = (0 == settings_buffer[0xF36]); -#endif -#ifdef ESP32 - valid_settings = (1 == settings_buffer[0xF36]); -#endif - } - - if (valid_settings) { - SettingsDefaultSet2(); - memcpy((char*)&Settings +16, settings_buffer +16, sizeof(Settings) -16); - Settings.version = buffer_version; - SettingsBufferFree(); - } else { - Web.upload_error = 8; - return; - } - } -#ifdef USE_RF_FLASH - else if (UPL_EFM8BB1 == Web.upload_file_type) { - - Web.upload_file_type = UPL_TASMOTA; - } -#endif -#ifdef USE_TASMOTA_SLAVE - else if (UPL_TASMOTASLAVE == Web.upload_file_type) { - - TasmotaSlave_SetFlagFlashing(true); - Web.upload_file_type = UPL_TASMOTA; - } -#endif - else { - if (!Update.end(true)) { - if (_serialoutput) { Update.printError(Serial); } - Web.upload_error = 6; - return; - } - if (!VersionCompatible()) { - Web.upload_error = 14; - return; - } - } - if (!Web.upload_error) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_SUCCESSFUL " %u bytes. " D_RESTARTING), upload.totalSize); - } - } else if (UPLOAD_FILE_ABORTED == upload.status) { - restart_flag = 0; - MqttRetryCounter(0); - Web.upload_error = 7; - if (UPL_TASMOTA == Web.upload_file_type) { Update.end(); } - } - delay(0); -} - - - -void HandlePreflightRequest(void) -{ - HttpHeaderCors(); - Webserver->sendHeader(F("Access-Control-Allow-Methods"), F("GET, POST")); - Webserver->sendHeader(F("Access-Control-Allow-Headers"), F("authorization")); - WSSend(200, CT_HTML, ""); -} - - - -void HandleHttpCommand(void) -{ - if (!HttpCheckPriviledgedAccess(false)) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND)); - - if (strlen(SettingsText(SET_WEBPWD))) { - char tmp1[33]; - WebGetArg("user", tmp1, sizeof(tmp1)); - char tmp2[strlen(SettingsText(SET_WEBPWD)) +1]; - WebGetArg("password", tmp2, sizeof(tmp2)); - if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, SettingsText(SET_WEBPWD)))) { - WSContentBegin(401, CT_JSON); - WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_NEED_USER_AND_PASSWORD "\"}")); - WSContentEnd(); - return; - } - } - - WSContentBegin(200, CT_JSON); - uint32_t curridx = web_log_index; - String svalue = Webserver->arg("cmnd"); - if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) { - ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND); - if (web_log_index != curridx) { - uint32_t counter = curridx; - WSContentSend_P(PSTR("{")); - bool cflg = false; - do { - char* tmp; - size_t len; - GetLog(counter, &tmp, &len); - if (len) { - - char* JSON = (char*)memchr(tmp, '{', len); - if (JSON) { - size_t JSONlen = len - (JSON - tmp); - if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); } - char stemp[JSONlen]; - strlcpy(stemp, JSON +1, JSONlen -2); - WSContentSend_P(PSTR("%s%s"), (cflg) ? "," : "", stemp); - cflg = true; - } - } - counter++; - counter &= 0xFF; - if (!counter) counter++; - } while (counter != web_log_index); - WSContentSend_P(PSTR("}")); - } else { - WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}")); - } - } else { - WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENTER_COMMAND " cmnd=\"}")); - } - WSContentEnd(); -} - - - -void HandleConsole(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - if (Webserver->hasArg("c2")) { - HandleConsoleRefresh(); - return; - } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONSOLE); - - WSContentStart_P(S_CONSOLE); - WSContentSend_P(HTTP_SCRIPT_CONSOL, Settings.web_refresh); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_CMND); - WSContentSpaceButton(BUTTON_MAIN); - WSContentStop(); -} - -void HandleConsoleRefresh(void) -{ - bool cflg = true; - uint32_t counter = 0; - - String svalue = Webserver->arg("c1"); - if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), svalue.c_str()); - ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE); - } - - char stmp[8]; - WebGetArg("c2", stmp, sizeof(stmp)); - if (strlen(stmp)) { counter = atoi(stmp); } - - WSContentBegin(200, CT_PLAIN); - WSContentSend_P(PSTR("%d}1%d}1"), web_log_index, Web.reset_web_log_flag); - if (!Web.reset_web_log_flag) { - counter = 0; - Web.reset_web_log_flag = true; - } - if (counter != web_log_index) { - if (!counter) { - counter = web_log_index; - cflg = false; - } - do { - char* tmp; - size_t len; - GetLog(counter, &tmp, &len); - if (len) { - if (len > sizeof(mqtt_data) -2) { len = sizeof(mqtt_data); } - char stemp[len +1]; - strlcpy(stemp, tmp, len); - WSContentSend_P(PSTR("%s%s"), (cflg) ? "\n" : "", stemp); - cflg = true; - } - counter++; - counter &= 0xFF; - if (!counter) { counter++; } - } while (counter != web_log_index); - } - WSContentSend_P(PSTR("}1")); - WSContentEnd(); -} - - - -void HandleNotFound(void) -{ - - - if (CaptivePortal()) { return; } - -#ifdef USE_EMULATION -#ifdef USE_EMULATION_HUE - String path = Webserver->uri(); - if ((EMUL_HUE == Settings.flag2.emulation) && (path.startsWith("/api"))) { - HandleHueApi(&path); - } else -#endif -#endif - { - WSContentBegin(404, CT_PLAIN); - WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), Webserver->uri().c_str(), (Webserver->method() == HTTP_GET) ? "GET" : "POST", Webserver->args()); - for (uint32_t i = 0; i < Webserver->args(); i++) { - WSContentSend_P(PSTR(" %s: %s\n"), Webserver->argName(i).c_str(), Webserver->arg(i).c_str()); - } - WSContentEnd(); - } -} - - -bool CaptivePortal(void) -{ - - if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED)); - - Webserver->sendHeader(F("Location"), String("http://") + Webserver->client().localIP().toString(), true); - WSSend(302, CT_PLAIN, ""); - Webserver->client().stop(); - return true; - } - return false; -} - - - -String UrlEncode(const String& text) -{ - const char hex[] = "0123456789ABCDEF"; - - String encoded = ""; - int len = text.length(); - int i = 0; - while (i < len) { - char decodedChar = text.charAt(i++); -# 2762 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_01_webserver.ino" - if ((' ' == decodedChar) || ('+' == decodedChar)) { - encoded += '%'; - encoded += hex[decodedChar >> 4]; - encoded += hex[decodedChar & 0xF]; - } else { - encoded += decodedChar; - } - - } - return encoded; -} - -int WebSend(char *buffer) -{ - - - - - - char *host; - char *user; - char *password; - char *command; - int status = 1; - - - host = strtok_r(buffer, "]", &command); - if (host && command) { - RemoveSpace(host); - host++; - host = strtok_r(host, ",", &user); - String url = F("http://"); - url += host; - - command = Trim(command); - if (command[0] != '/') { - url += F("/cm?"); - if (user) { - user = strtok_r(user, ":", &password); - if (user && password) { - char userpass[200]; - snprintf_P(userpass, sizeof(userpass), PSTR("user=%s&password=%s&"), user, password); - url += userpass; - } - } - url += F("cmnd="); - } - url += command; - - DEBUG_CORE_LOG(PSTR("WEB: Uri |%s|"), url.c_str()); - -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) - HTTPClient http; - if (http.begin(UrlEncode(url))) { -#else - WiFiClient http_client; - HTTPClient http; - if (http.begin(http_client, UrlEncode(url))) { -#endif - int http_code = http.GET(); - if (http_code > 0) { - if (http_code == HTTP_CODE_OK || http_code == HTTP_CODE_MOVED_PERMANENTLY) { -#ifdef USE_WEBSEND_RESPONSE - - const char* read = http.getString().c_str(); - uint32_t j = 0; - char text = '.'; - while (text != '\0') { - text = *read++; - if (text > 31) { - mqtt_data[j++] = text; - if (j == sizeof(mqtt_data) -2) { break; } - } - } - mqtt_data[j] = '\0'; - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_WEBSEND)); -#ifdef USE_SCRIPT -extern uint8_t tasm_cmd_activ; - - tasm_cmd_activ=0; - XdrvRulesProcess(); -#endif -#endif - } - status = 0; - } else { - status = 2; - } - http.end(); - } else { - status = 3; - } - } - return status; -} - -bool JsonWebColor(const char* dataBuf) -{ - - - - - - char dataBufLc[strlen(dataBuf) +1]; - LowerCase(dataBufLc, dataBuf); - RemoveSpace(dataBufLc); - if (strlen(dataBufLc) < 9) { return false; } - - StaticJsonBuffer<450> jb; - JsonObject& obj = jb.parseObject(dataBufLc); - if (!obj.success()) { return false; } - - char parm_lc[10]; - if (obj[LowerCase(parm_lc, D_CMND_WEBCOLOR)].success()) { - for (uint32_t i = 0; i < COL_LAST; i++) { - const char* color = obj[parm_lc][i]; - if (color != nullptr) { - WebHexCode(i, color); - } - } - } - return true; -} - -const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND "|" D_JSON_MEMORY_ERROR; - -const char kWebCommands[] PROGMEM = "|" -#ifdef USE_EMULATION - D_CMND_EMULATION "|" -#endif -#ifdef USE_SENDMAIL - D_CMND_SENDMAIL "|" -#endif - D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" - D_CMND_WEBSENSOR "|" D_CMND_WEBBUTTON "|" D_CMND_CORS; - -void (* const WebCommand[])(void) PROGMEM = { -#ifdef USE_EMULATION - &CmndEmulation, -#endif -#ifdef USE_SENDMAIL - &CmndSendmail, -#endif - &CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, - &CmndWebSensor, &CmndWebButton, &CmndCors }; - - - - - -#ifdef USE_EMULATION -void CmndEmulation(void) -{ -#if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE) -#if defined(USE_EMULATION_WEMO) && defined(USE_EMULATION_HUE) - if ((XdrvMailbox.payload >= EMUL_NONE) && (XdrvMailbox.payload < EMUL_MAX)) { -#else -#ifndef USE_EMULATION_WEMO - if ((EMUL_NONE == XdrvMailbox.payload) || (EMUL_HUE == XdrvMailbox.payload)) { -#endif -#ifndef USE_EMULATION_HUE - if ((EMUL_NONE == XdrvMailbox.payload) || (EMUL_WEMO == XdrvMailbox.payload)) { -#endif -#endif - Settings.flag2.emulation = XdrvMailbox.payload; - restart_flag = 2; - } -#endif - ResponseCmndNumber(Settings.flag2.emulation); -} -#endif - -#ifdef USE_SENDMAIL -void CmndSendmail(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t result = SendMail(XdrvMailbox.data); - char stemp1[20]; - ResponseCmndChar(GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus)); - } -} -#endif - - -void CmndWebServer(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { - Settings.webserver = XdrvMailbox.payload; - } - if (Settings.webserver) { - Response_P(PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"), - (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str()); - } else { - ResponseCmndStateText(0); - } -} - -void CmndWebPassword(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_WEBPWD, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? WEB_PASSWORD : XdrvMailbox.data); - ResponseCmndChar(SettingsText(SET_WEBPWD)); - } else { - Response_P(S_JSON_COMMAND_ASTERISK, XdrvMailbox.command); - } -} - -void CmndWeblog(void) -{ - if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { - Settings.weblog_level = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.weblog_level); -} - -void CmndWebRefresh(void) -{ - if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload <= 10000)) { - Settings.web_refresh = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.web_refresh); -} - -void CmndWebSend(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t result = WebSend(XdrvMailbox.data); - char stemp1[20]; - ResponseCmndChar(GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus)); - } -} - -void CmndWebColor(void) -{ - if (XdrvMailbox.data_len > 0) { - if (strstr(XdrvMailbox.data, "{") == nullptr) { - if ((XdrvMailbox.data_len > 3) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= COL_LAST)) { - WebHexCode(XdrvMailbox.index -1, XdrvMailbox.data); - } - else if (0 == XdrvMailbox.payload) { - SettingsDefaultWebColor(); - } - } - else { - JsonWebColor(XdrvMailbox.data); - } - } - Response_P(PSTR("{\"" D_CMND_WEBCOLOR "\":[")); - for (uint32_t i = 0; i < COL_LAST; i++) { - if (i) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(PSTR("\"#%06x\""), WebColor(i)); - } - ResponseAppend_P(PSTR("]}")); -} - -void CmndWebSensor(void) -{ - if (XdrvMailbox.index < MAX_XSNS_DRIVERS) { - if (XdrvMailbox.payload >= 0) { - bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1); - } - } - Response_P(PSTR("{\"" D_CMND_WEBSENSOR "\":")); - XsnsSensorState(); - ResponseJsonEnd(); -} - -void CmndWebButton(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_BUTTON_TEXT)) { - if (!XdrvMailbox.usridx) { - ResponseCmndAll(SET_BUTTON1, MAX_BUTTON_TEXT); - } else { - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_BUTTON1 + XdrvMailbox.index -1, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data); - } - ResponseCmndIdxChar(SettingsText(SET_BUTTON1 + XdrvMailbox.index -1)); - } - } -} - -void CmndCors(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_CORS, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? WEB_PASSWORD : XdrvMailbox.data); - } - ResponseCmndChar(SettingsText(SET_CORS)); -} - - - - - -bool Xdrv01(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_LOOP: - PollDnsWebserver(); -#ifdef USE_EMULATION -#ifdef USE_DEVICE_GROUPS - if (Settings.flag2.emulation || Settings.flag4.device_groups_enabled) { PollUdp(); } -#else - if (Settings.flag2.emulation) { PollUdp(); } -#endif -#endif - break; - case FUNC_COMMAND: - result = DecodeCommand(kWebCommands, WebCommand); - break; - } - return result; -} -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_02_mqtt.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_02_mqtt.ino" -#define XDRV_02 2 - - - -#ifdef USE_MQTT_TLS - #include "WiFiClientSecureLightBearSSL.h" - BearSSL::WiFiClientSecure_light *tlsClient; -#else - WiFiClient EspClient; -#endif - -const char kMqttCommands[] PROGMEM = "|" -#if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT) - D_CMND_MQTTFINGERPRINT "|" -#endif - D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - D_CMND_TLSKEY "|" -#endif - D_CMND_MQTTHOST "|" D_CMND_MQTTPORT "|" D_CMND_MQTTRETRY "|" D_CMND_STATETEXT "|" D_CMND_MQTTCLIENT "|" - D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|" D_CMND_MQTTLOG "|" - D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ; - -void (* const MqttCommand[])(void) PROGMEM = { -#if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT) - &CmndMqttFingerprint, -#endif - &CmndMqttUser, &CmndMqttPassword, -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - &CmndTlsKey, -#endif - &CmndMqttHost, &CmndMqttPort, &CmndMqttRetry, &CmndStateText, &CmndMqttClient, - &CmndFullTopic, &CmndPrefix, &CmndGroupTopic, &CmndTopic, &CmndPublish, &CmndMqttlog, - &CmndButtonTopic, &CmndSwitchTopic, &CmndButtonRetain, &CmndSwitchRetain, &CmndPowerRetain, &CmndSensorRetain }; - -struct MQTT { - uint16_t connect_count = 0; - uint16_t retry_counter = 1; - uint8_t initial_connection_state = 2; - bool connected = false; - bool allowed = false; -} Mqtt; - -#ifdef USE_MQTT_TLS - -#ifdef USE_MQTT_AWS_IOT -#include - -const br_ec_private_key *AWS_IoT_Private_Key = nullptr; -const br_x509_certificate *AWS_IoT_Client_Certificate = nullptr; - -class tls_entry_t { -public: - uint32_t name; - uint16_t start; - uint16_t len; -}; - -const static uint32_t TLS_NAME_SKEY = 0x2079656B; -const static uint32_t TLS_NAME_CRT = 0x20747263; - -class tls_dir_t { -public: - tls_entry_t entry[4]; -}; - -tls_dir_t tls_dir; - -#endif - - - - -bool is_fingerprint_mono_value(uint8_t finger[20], uint8_t value) { - for (uint32_t i = 0; i<20; i++) { - if (finger[i] != value) { - return false; - } - } - return true; -} -#endif - -void MakeValidMqtt(uint32_t option, char* str) -{ - - - uint32_t i = 0; - while (str[i] > 0) { - - if ((str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) { - if (option) { - uint32_t j = i; - while (str[j] > 0) { - str[j] = str[j +1]; - j++; - } - i--; - } else { - str[i] = '_'; - } - } - i++; - } -} - -#ifdef USE_DISCOVERY -#ifdef MQTT_HOST_DISCOVERY -void MqttDiscoverServer(void) -{ - if (!Wifi.mdns_begun) { return; } - - int n = MDNS.queryService("mqtt", "tcp"); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n); - - if (n > 0) { - uint32_t i = 0; -#ifdef MDNS_HOSTNAME - for (i = n; i > 0; i--) { - if (!strcmp(MDNS.hostname(i).c_str(), MDNS_HOSTNAME)) { - break; - } - } -#endif - SettingsUpdateText(SET_MQTT_HOST, MDNS.IP(i).toString().c_str()); - Settings.mqtt_port = MDNS.port(i); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), MDNS.hostname(i).c_str(), SettingsText(SET_MQTT_HOST), Settings.mqtt_port); - } -} -#endif -#endif -# 163 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_02_mqtt.ino" -#include - - -#if (MQTT_MAX_PACKET_SIZE -TOPSZ -7) < MIN_MESSZ - #error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 1200" -#endif - -#ifdef USE_MQTT_TLS -PubSubClient MqttClient; -#else -PubSubClient MqttClient(EspClient); -#endif - -void MqttInit(void) -{ -#ifdef USE_MQTT_TLS - tlsClient = new BearSSL::WiFiClientSecure_light(1024,1024); - -#ifdef USE_MQTT_AWS_IOT - loadTlsDir(); - tlsClient->setClientECCert(AWS_IoT_Client_Certificate, - AWS_IoT_Private_Key, - 0xFFFF , 0); -#endif - -#ifdef USE_MQTT_TLS_CA_CERT -#ifdef USE_MQTT_AWS_IOT - tlsClient->setTrustAnchor(&AmazonRootCA1_TA); -#else - tlsClient->setTrustAnchor(&LetsEncryptX3CrossSigned_TA); -#endif -#endif - - MqttClient.setClient(*tlsClient); -#endif -} - -bool MqttIsConnected(void) -{ - return MqttClient.connected(); -} - -void MqttDisconnect(void) -{ - MqttClient.disconnect(); -} - -void MqttSubscribeLib(const char *topic) -{ - MqttClient.subscribe(topic); - MqttClient.loop(); -} - -void MqttUnsubscribeLib(const char *topic) -{ - MqttClient.unsubscribe(topic); - MqttClient.loop(); -} - -bool MqttPublishLib(const char* topic, bool retained) -{ - - if (!strcmp(SettingsText(SET_MQTTPREFIX1), SettingsText(SET_MQTTPREFIX2))) { - char *str = strstr(topic, SettingsText(SET_MQTTPREFIX1)); - if (str == topic) { - mqtt_cmnd_blocked_reset = 4; - mqtt_cmnd_blocked++; - } - } - - bool result = MqttClient.publish(topic, mqtt_data, retained); - yield(); - return result; -} - -void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len) -{ -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("MqttDataHandler")); -#endif - - - if (data_len >= MQTT_MAX_PACKET_SIZE) { return; } - - - if (!strcmp(SettingsText(SET_MQTTPREFIX1), SettingsText(SET_MQTTPREFIX2))) { - char *str = strstr(mqtt_topic, SettingsText(SET_MQTTPREFIX1)); - if ((str == mqtt_topic) && mqtt_cmnd_blocked) { - mqtt_cmnd_blocked--; - return; - } - } - - - char topic[TOPSZ]; - strlcpy(topic, mqtt_topic, sizeof(topic)); - mqtt_data[data_len] = 0; - char data[data_len +1]; - memcpy(data, mqtt_data, sizeof(data)); - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " \"%s\", " D_DATA_SIZE " %d, " D_DATA " \"%s\""), topic, data_len, data); - - - - XdrvMailbox.index = strlen(topic); - XdrvMailbox.data_len = data_len; - XdrvMailbox.topic = topic; - XdrvMailbox.data = (char*)data; - if (XdrvCall(FUNC_MQTT_DATA)) { return; } - - ShowSource(SRC_MQTT); - - CommandHandler(topic, data, data_len); -} - - - -void MqttRetryCounter(uint8_t value) -{ - Mqtt.retry_counter = value; -} - -void MqttSubscribe(const char *topic) -{ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT D_SUBSCRIBE_TO " %s"), topic); - MqttSubscribeLib(topic); -} - -void MqttUnsubscribe(const char *topic) -{ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT D_UNSUBSCRIBE_FROM " %s"), topic); - MqttUnsubscribeLib(topic); -} - -void MqttPublishLogging(const char *mxtime) -{ - char saved_mqtt_data[strlen(mqtt_data) +1]; - memcpy(saved_mqtt_data, mqtt_data, sizeof(saved_mqtt_data)); - - - Response_P(PSTR("%s%s"), mxtime, log_data); - char stopic[TOPSZ]; - GetTopic_P(stopic, STAT, mqtt_topic, PSTR("LOGGING")); - MqttPublishLib(stopic, false); - - memcpy(mqtt_data, saved_mqtt_data, sizeof(saved_mqtt_data)); -} - -void MqttPublish(const char* topic, bool retained) -{ -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("MqttPublish")); -#endif - -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) || defined(MQTT_NO_RETAIN) - - - - retained = false; -#endif - - char sretained[CMDSZ]; - sretained[0] = '\0'; - char slog_type[20]; - snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_RESULT)); - - if (Settings.flag.mqtt_enabled) { - if (MqttPublishLib(topic, retained)) { - snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_MQTT)); - if (retained) { - snprintf_P(sretained, sizeof(sretained), PSTR(" (" D_RETAINED ")")); - } - } - } - - snprintf_P(log_data, sizeof(log_data), PSTR("%s%s = %s"), slog_type, (Settings.flag.mqtt_enabled) ? topic : strrchr(topic,'/')+1, mqtt_data); - if (strlen(log_data) >= (sizeof(log_data) - strlen(sretained) -1)) { - log_data[sizeof(log_data) - strlen(sretained) -5] = '\0'; - snprintf_P(log_data, sizeof(log_data), PSTR("%s ..."), log_data); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s%s"), log_data, sretained); - AddLog(LOG_LEVEL_INFO); - - if (Settings.ledstate &0x04) { - blinks++; - } -} - -void MqttPublish(const char* topic) -{ - MqttPublish(topic, false); -} - -void MqttPublishPrefixTopic_P(uint32_t prefix, const char* subtopic, bool retained) -{ - - - - - - - - char romram[64]; - char stopic[TOPSZ]; - - snprintf_P(romram, sizeof(romram), ((prefix > 3) && !Settings.flag.mqtt_response) ? S_RSLT_RESULT : subtopic); - for (uint32_t i = 0; i < strlen(romram); i++) { - romram[i] = toupper(romram[i]); - } - prefix &= 3; - GetTopic_P(stopic, prefix, mqtt_topic, romram); - MqttPublish(stopic, retained); - -#ifdef USE_MQTT_AWS_IOT - if ((prefix > 0) && (Settings.flag4.awsiot_shadow) && (Mqtt.connected)) { - - char *topic = SettingsText(SET_MQTT_TOPIC); - char topic2[strlen(topic)+1]; - strcpy(topic2, topic); - - char *s = topic2; - while (*s) { - if ('/' == *s) { - *s = '_'; - } - s++; - } - - snprintf_P(romram, sizeof(romram), PSTR("$aws/things/%s/shadow/update"), topic2); - - - char *mqtt_save = (char*) malloc(strlen(mqtt_data)+1); - if (!mqtt_save) { return; } - strcpy(mqtt_save, mqtt_data); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"state\":{\"reported\":%s}}"), mqtt_save); - free(mqtt_save); - - bool result = MqttClient.publish(romram, mqtt_data, false); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "Updated shadow: %s"), romram); - yield(); - } -#endif -} - -void MqttPublishPrefixTopic_P(uint32_t prefix, const char* subtopic) -{ - MqttPublishPrefixTopic_P(prefix, subtopic, false); -} - -void MqttPublishTeleSensor(void) -{ - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - XdrvRulesProcess(); -} - -void MqttPublishPowerState(uint32_t device) -{ - char stopic[TOPSZ]; - char scommand[33]; - - if ((device < 1) || (device > devices_present)) { device = 1; } - -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan() && (device > 1)) { - if (GetFanspeed() < MaxFanspeed()) { -#ifdef USE_DOMOTICZ - DomoticzUpdateFanState(); -#endif - snprintf_P(scommand, sizeof(scommand), PSTR(D_CMND_FANSPEED)); - GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT); - Response_P(S_JSON_COMMAND_NVALUE, scommand, GetFanspeed()); - MqttPublish(stopic); - } - } else { -#endif - GetPowerDevice(scommand, device, sizeof(scommand), Settings.flag.device_index_enable); - GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT); - Response_P(S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1))); - MqttPublish(stopic); - - if (!Settings.flag4.only_json_message) { - GetTopic_P(stopic, STAT, mqtt_topic, scommand); - Response_P(GetStateText(bitRead(power, device -1))); - MqttPublish(stopic, Settings.flag.mqtt_power_retain); - } -#ifdef USE_SONOFF_IFAN - } -#endif -} - -void MqttPublishAllPowerState(void) -{ - for (uint32_t i = 1; i <= devices_present; i++) { - MqttPublishPowerState(i); -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan()) { break; } -#endif - } -} - -void MqttPublishPowerBlinkState(uint32_t device) -{ - char scommand[33]; - - if ((device < 1) || (device > devices_present)) { - device = 1; - } - Response_P(PSTR("{\"%s\":\"" D_JSON_BLINK " %s\"}"), - GetPowerDevice(scommand, device, sizeof(scommand), Settings.flag.device_index_enable), GetStateText(bitRead(blink_mask, device -1))); - - MqttPublishPrefixTopic_P(RESULT_OR_STAT, S_RSLT_POWER); -} - - - -uint16_t MqttConnectCount(void) -{ - return Mqtt.connect_count; -} - -void MqttDisconnected(int state) -{ - Mqtt.connected = false; - Mqtt.retry_counter = Settings.mqtt_retry; - - MqttClient.disconnect(); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND), SettingsText(SET_MQTT_HOST), Settings.mqtt_port, state, Mqtt.retry_counter); - rules_flag.mqtt_disconnected = 1; -} - -void MqttConnected(void) -{ - char stopic[TOPSZ]; - - if (Mqtt.allowed) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED)); - Mqtt.connected = true; - Mqtt.retry_counter = 0; - Mqtt.connect_count++; - - GetTopic_P(stopic, TELE, mqtt_topic, S_LWT); - Response_P(PSTR(D_ONLINE)); - MqttPublish(stopic, true); - - if (!Settings.flag4.only_json_message) { - - mqtt_data[0] = '\0'; - MqttPublishPrefixTopic_P(CMND, S_RSLT_POWER); - } - - GetTopic_P(stopic, CMND, mqtt_topic, PSTR("#")); - MqttSubscribe(stopic); - if (strstr_P(SettingsText(SET_MQTT_FULLTOPIC), MQTT_TOKEN_TOPIC) != nullptr) { - uint32_t real_index = SET_MQTT_GRP_TOPIC; - for (uint32_t i = 0; i < MAX_GROUP_TOPICS; i++) { - if (1 == i) { real_index = SET_MQTT_GRP_TOPIC2 -1; } - if (strlen(SettingsText(real_index +i))) { - GetGroupTopic_P(stopic, PSTR("#"), real_index +i); - MqttSubscribe(stopic); - } - } - GetFallbackTopic_P(stopic, PSTR("#")); - MqttSubscribe(stopic); - } - - XdrvCall(FUNC_MQTT_SUBSCRIBE); - } - - if (Mqtt.initial_connection_state) { - if (ResetReason() != REASON_DEEP_SLEEP_AWAKE) { - char stopic2[TOPSZ]; - Response_P(PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"), - ModuleName().c_str(), my_version, my_image, GetFallbackTopic_P(stopic, ""), GetGroupTopic_P(stopic2, "", SET_MQTT_GRP_TOPIC)); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "1")); -#ifdef USE_WEBSERVER - if (Settings.webserver) { -#if LWIP_IPV6 - Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}"), - (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str(),WifiGetIPv6().c_str()); -#else - Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"), - (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str()); -#endif - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2")); - } -#endif - Response_P(PSTR("{\"" D_JSON_RESTARTREASON "\":")); - if (CrashFlag()) { - CrashDump(); - } else { - ResponseAppend_P(PSTR("\"%s\""), GetResetReason().c_str()); - } - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "3")); - } - - MqttPublishAllPowerState(); - if (Settings.tele_period) { - tele_period = Settings.tele_period -5; - } - rules_flag.system_boot = 1; - XdrvCall(FUNC_MQTT_INIT); - } - Mqtt.initial_connection_state = 0; - - global_state.mqtt_down = 0; - if (Settings.flag.mqtt_enabled) { - rules_flag.mqtt_connected = 1; - } -} - -void MqttReconnect(void) -{ - char stopic[TOPSZ]; - - Mqtt.allowed = Settings.flag.mqtt_enabled; - if (Mqtt.allowed) { -#ifdef USE_DISCOVERY -#ifdef MQTT_HOST_DISCOVERY - MqttDiscoverServer(); -#endif -#endif - if (!strlen(SettingsText(SET_MQTT_HOST)) || !Settings.mqtt_port) { - Mqtt.allowed = false; - } -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - - if (!AWS_IoT_Private_Key || !AWS_IoT_Client_Certificate) { - Mqtt.allowed = false; - } -#endif - } - if (!Mqtt.allowed) { - MqttConnected(); - return; - } - -#ifdef USE_EMULATION - UdpDisconnect(); -#endif - - AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_ATTEMPTING_CONNECTION)); - - Mqtt.connected = false; - Mqtt.retry_counter = Settings.mqtt_retry; - global_state.mqtt_down = 1; - - char *mqtt_user = nullptr; - char *mqtt_pwd = nullptr; - if (strlen(SettingsText(SET_MQTT_USER))) { - mqtt_user = SettingsText(SET_MQTT_USER); - } - if (strlen(SettingsText(SET_MQTT_PWD))) { - mqtt_pwd = SettingsText(SET_MQTT_PWD); - } - - GetTopic_P(stopic, TELE, mqtt_topic, S_LWT); - Response_P(S_OFFLINE); - - if (MqttClient.connected()) { MqttClient.disconnect(); } -#ifdef USE_MQTT_TLS - tlsClient->stop(); -#else - EspClient = WiFiClient(); - MqttClient.setClient(EspClient); -#endif - - if (2 == Mqtt.initial_connection_state) { - Mqtt.initial_connection_state = 1; - } - - MqttClient.setCallback(MqttDataHandler); -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - - tlsClient->setClientECCert(AWS_IoT_Client_Certificate, - AWS_IoT_Private_Key, - 0xFFFF , 0); -#endif - MqttClient.setServer(SettingsText(SET_MQTT_HOST), Settings.mqtt_port); - - uint32_t mqtt_connect_time = millis(); -#if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT) - bool allow_all_fingerprints = false; - bool learn_fingerprint1 = is_fingerprint_mono_value(Settings.mqtt_fingerprint[0], 0x00); - bool learn_fingerprint2 = is_fingerprint_mono_value(Settings.mqtt_fingerprint[1], 0x00); - allow_all_fingerprints |= is_fingerprint_mono_value(Settings.mqtt_fingerprint[0], 0xff); - allow_all_fingerprints |= is_fingerprint_mono_value(Settings.mqtt_fingerprint[1], 0xff); - allow_all_fingerprints |= learn_fingerprint1; - allow_all_fingerprints |= learn_fingerprint2; - tlsClient->setPubKeyFingerprint(Settings.mqtt_fingerprint[0], Settings.mqtt_fingerprint[1], allow_all_fingerprints); -#endif -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "AWS IoT endpoint: %s"), SettingsText(SET_MQTT_HOST)); - if (MqttClient.connect(mqtt_client, nullptr, nullptr, stopic, 1, false, mqtt_data, MQTT_CLEAN_SESSION)) { -#else - if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, true, mqtt_data, MQTT_CLEAN_SESSION)) { -#endif -#ifdef USE_MQTT_TLS - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connected in %d ms, max ThunkStack used %d"), - millis() - mqtt_connect_time, tlsClient->getMaxThunkStackUse()); - if (!tlsClient->getMFLNStatus()) { - AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR("MFLN not supported by TLS server")); - } -#ifndef USE_MQTT_TLS_CA_CERT - - char buf_fingerprint[64]; - ToHex_P((unsigned char *)tlsClient->getRecvPubKeyFingerprint(), 20, buf_fingerprint, sizeof(buf_fingerprint), ' '); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "Server fingerprint: %s"), buf_fingerprint); - - if (learn_fingerprint1 || learn_fingerprint2) { - - bool fingerprint_matched = false; - const uint8_t *recv_fingerprint = tlsClient->getRecvPubKeyFingerprint(); - if (0 == memcmp(recv_fingerprint, Settings.mqtt_fingerprint[0], 20)) { - fingerprint_matched = true; - } - if (0 == memcmp(recv_fingerprint, Settings.mqtt_fingerprint[1], 20)) { - fingerprint_matched = true; - } - if (!fingerprint_matched) { - - if (learn_fingerprint1) { - memcpy(Settings.mqtt_fingerprint[0], recv_fingerprint, 20); - } - if (learn_fingerprint2) { - memcpy(Settings.mqtt_fingerprint[1], recv_fingerprint, 20); - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Fingerprint learned: %s"), buf_fingerprint); - - SettingsSaveAll(); - } - } -#endif -#endif - MqttConnected(); - } else { -#ifdef USE_MQTT_TLS - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "TLS connection error: %d"), tlsClient->getLastError()); -#endif - MqttDisconnected(MqttClient.state()); - } -} - -void MqttCheck(void) -{ - if (Settings.flag.mqtt_enabled) { - if (!MqttIsConnected()) { - global_state.mqtt_down = 1; - if (!Mqtt.retry_counter) { - MqttReconnect(); - } else { - Mqtt.retry_counter--; - } - } else { - global_state.mqtt_down = 0; - } - } else { - global_state.mqtt_down = 0; - if (Mqtt.initial_connection_state) { - MqttReconnect(); - } - } -} - -bool KeyTopicActive(uint32_t key) -{ - - - key &= 1; - char key_topic[TOPSZ]; - Format(key_topic, SettingsText(SET_MQTT_BUTTON_TOPIC + key), sizeof(key_topic)); - return ((strlen(key_topic) != 0) && strcmp(key_topic, "0")); -} - - - - - -#if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT) -void CmndMqttFingerprint(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) { - char fingerprint[60]; - if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(fingerprint))) { - strlcpy(fingerprint, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? MQTT_FINGERPRINT1 : MQTT_FINGERPRINT2 : XdrvMailbox.data, sizeof(fingerprint)); - char *p = fingerprint; - for (uint32_t i = 0; i < 20; i++) { - Settings.mqtt_fingerprint[XdrvMailbox.index -1][i] = strtol(p, &p, 16); - } - restart_flag = 2; - } - ResponseCmndIdxChar(ToHex_P((unsigned char *)Settings.mqtt_fingerprint[XdrvMailbox.index -1], 20, fingerprint, sizeof(fingerprint), ' ')); - } -} -#endif - -void CmndMqttUser(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_MQTT_USER, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? MQTT_USER : XdrvMailbox.data); - restart_flag = 2; - } - ResponseCmndChar(SettingsText(SET_MQTT_USER)); -} - -void CmndMqttPassword(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_MQTT_PWD, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? MQTT_PASS : XdrvMailbox.data); - ResponseCmndChar(SettingsText(SET_MQTT_PWD)); - restart_flag = 2; - } else { - Response_P(S_JSON_COMMAND_ASTERISK, XdrvMailbox.command); - } -} - -void CmndMqttlog(void) -{ - if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { - Settings.mqttlog_level = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.mqttlog_level); -} - -void CmndMqttHost(void) -{ - if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_MQTT_HOST, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? MQTT_HOST : XdrvMailbox.data); - restart_flag = 2; - } - ResponseCmndChar(SettingsText(SET_MQTT_HOST)); -} - -void CmndMqttPort(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 65536)) { - Settings.mqtt_port = (1 == XdrvMailbox.payload) ? MQTT_PORT : XdrvMailbox.payload; - restart_flag = 2; - } - ResponseCmndNumber(Settings.mqtt_port); -} - -void CmndMqttRetry(void) -{ - if ((XdrvMailbox.payload >= MQTT_RETRY_SECS) && (XdrvMailbox.payload < 32001)) { - Settings.mqtt_retry = XdrvMailbox.payload; - Mqtt.retry_counter = Settings.mqtt_retry; - } - ResponseCmndNumber(Settings.mqtt_retry); -} - -void CmndStateText(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_STATE_TEXT)) { - if (!XdrvMailbox.usridx) { - ResponseCmndAll(SET_STATE_TXT1, MAX_STATE_TEXT); - } else { - if (XdrvMailbox.data_len > 0) { - for (uint32_t i = 0; i <= XdrvMailbox.data_len; i++) { - if (XdrvMailbox.data[i] == ' ') XdrvMailbox.data[i] = '_'; - } - SettingsUpdateText(SET_STATE_TXT1 + XdrvMailbox.index -1, XdrvMailbox.data); - } - ResponseCmndIdxChar(GetStateText(XdrvMailbox.index -1)); - } - } -} - -void CmndMqttClient(void) -{ - if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { - SettingsUpdateText(SET_MQTT_CLIENT, (SC_DEFAULT == Shortcut()) ? MQTT_CLIENT_ID : XdrvMailbox.data); - restart_flag = 2; - } - ResponseCmndChar(SettingsText(SET_MQTT_CLIENT)); -} - -void CmndFullTopic(void) -{ - if (XdrvMailbox.data_len > 0) { - MakeValidMqtt(1, XdrvMailbox.data); - if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); } - char stemp1[TOPSZ]; - strlcpy(stemp1, (SC_DEFAULT == Shortcut()) ? MQTT_FULLTOPIC : XdrvMailbox.data, sizeof(stemp1)); - if (strcmp(stemp1, SettingsText(SET_MQTT_FULLTOPIC))) { - Response_P((Settings.flag.mqtt_offline) ? S_OFFLINE : ""); - MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); - SettingsUpdateText(SET_MQTT_FULLTOPIC, stemp1); - restart_flag = 2; - } - } - ResponseCmndChar(SettingsText(SET_MQTT_FULLTOPIC)); -} - -void CmndPrefix(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_MQTT_PREFIXES)) { - if (!XdrvMailbox.usridx) { - ResponseCmndAll(SET_MQTTPREFIX1, MAX_MQTT_PREFIXES); - } else { - if (XdrvMailbox.data_len > 0) { - MakeValidMqtt(0, XdrvMailbox.data); - SettingsUpdateText(SET_MQTTPREFIX1 + XdrvMailbox.index -1, - (SC_DEFAULT == Shortcut()) ? (1==XdrvMailbox.index) ? SUB_PREFIX : (2==XdrvMailbox.index) ? PUB_PREFIX : PUB_PREFIX2 : XdrvMailbox.data); - restart_flag = 2; - } - ResponseCmndIdxChar(SettingsText(SET_MQTTPREFIX1 + XdrvMailbox.index -1)); - } - } -} - -void CmndPublish(void) -{ - if (XdrvMailbox.data_len > 0) { - char *payload_part; - char *mqtt_part = strtok_r(XdrvMailbox.data, " ", &payload_part); - if (mqtt_part) { - char stemp1[TOPSZ]; - strlcpy(stemp1, mqtt_part, sizeof(stemp1)); - if ((payload_part != nullptr) && strlen(payload_part)) { - strlcpy(mqtt_data, payload_part, sizeof(mqtt_data)); - } else { - mqtt_data[0] = '\0'; - } - MqttPublish(stemp1, (XdrvMailbox.index == 2)); - - mqtt_data[0] = '\0'; - } - } -} - -void CmndGroupTopic(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_GROUP_TOPICS)) { - if (XdrvMailbox.data_len > 0) { - uint32_t settings_text_index = (1 == XdrvMailbox.index) ? SET_MQTT_GRP_TOPIC : SET_MQTT_GRP_TOPIC2 + XdrvMailbox.index - 2; - MakeValidMqtt(0, XdrvMailbox.data); - if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); } - SettingsUpdateText(settings_text_index, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? MQTT_GRPTOPIC : XdrvMailbox.data); - - - char stemp[MAX_GROUP_TOPICS][TOPSZ]; - uint32_t read_index = 0; - uint32_t real_index = SET_MQTT_GRP_TOPIC; - for (uint32_t i = 0; i < MAX_GROUP_TOPICS; i++) { - if (1 == i) { real_index = SET_MQTT_GRP_TOPIC2 -1; } - if (strlen(SettingsText(real_index +i))) { - bool not_equal = true; - for (uint32_t j = 0; j < read_index; j++) { - if (!strcmp(SettingsText(real_index +i), stemp[j])) { - not_equal = false; - } - } - if (not_equal) { - strncpy(stemp[read_index], SettingsText(real_index +i), sizeof(stemp[read_index])); - read_index++; - } - } - } - if (0 == read_index) { - SettingsUpdateText(SET_MQTT_GRP_TOPIC, MQTT_GRPTOPIC); - } else { - uint32_t write_index = 0; - uint32_t real_index = SET_MQTT_GRP_TOPIC; - for (uint32_t i = 0; i < MAX_GROUP_TOPICS; i++) { - if (1 == i) { real_index = SET_MQTT_GRP_TOPIC2 -1; } - if (write_index < read_index) { - SettingsUpdateText(real_index +i, stemp[write_index]); - write_index++; - } else { - SettingsUpdateText(real_index +i, ""); - } - } - } - - restart_flag = 2; - } - ResponseCmndAll(SET_MQTT_GRP_TOPIC, MAX_GROUP_TOPICS); - } -} - -void CmndTopic(void) -{ - if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { - MakeValidMqtt(0, XdrvMailbox.data); - if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); } - char stemp1[TOPSZ]; - strlcpy(stemp1, (SC_DEFAULT == Shortcut()) ? MQTT_TOPIC : XdrvMailbox.data, sizeof(stemp1)); - if (strcmp(stemp1, SettingsText(SET_MQTT_TOPIC))) { - Response_P((Settings.flag.mqtt_offline) ? S_OFFLINE : ""); - MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); - SettingsUpdateText(SET_MQTT_TOPIC, stemp1); - restart_flag = 2; - } - } - ResponseCmndChar(SettingsText(SET_MQTT_TOPIC)); -} - -void CmndButtonTopic(void) -{ - if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { - MakeValidMqtt(0, XdrvMailbox.data); - if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); } - switch (Shortcut()) { - case SC_CLEAR: SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, ""); break; - case SC_DEFAULT: SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, mqtt_topic); break; - case SC_USER: SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, MQTT_BUTTON_TOPIC); break; - default: SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, XdrvMailbox.data); - } - } - ResponseCmndChar(SettingsText(SET_MQTT_BUTTON_TOPIC)); -} - -void CmndSwitchTopic(void) -{ - if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { - MakeValidMqtt(0, XdrvMailbox.data); - if (!strcmp(XdrvMailbox.data, mqtt_client)) { SetShortcutDefault(); } - switch (Shortcut()) { - case SC_CLEAR: SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, ""); break; - case SC_DEFAULT: SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, mqtt_topic); break; - case SC_USER: SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, MQTT_SWITCH_TOPIC); break; - default: SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, XdrvMailbox.data); - } - } - ResponseCmndChar(SettingsText(SET_MQTT_SWITCH_TOPIC)); -} - -void CmndButtonRetain(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - if (!XdrvMailbox.payload) { - for (uint32_t i = 1; i <= MAX_KEYS; i++) { - SendKey(KEY_BUTTON, i, CLEAR_RETAIN); - } - } - Settings.flag.mqtt_button_retain = XdrvMailbox.payload; - } - ResponseCmndStateText(Settings.flag.mqtt_button_retain); -} - -void CmndSwitchRetain(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - if (!XdrvMailbox.payload) { - for (uint32_t i = 1; i <= MAX_SWITCHES; i++) { - SendKey(KEY_SWITCH, i, CLEAR_RETAIN); - } - } - Settings.flag.mqtt_switch_retain = XdrvMailbox.payload; - } - ResponseCmndStateText(Settings.flag.mqtt_switch_retain); -} - -void CmndPowerRetain(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - if (!XdrvMailbox.payload) { - char stemp1[TOPSZ]; - char scommand[CMDSZ]; - for (uint32_t i = 1; i <= devices_present; i++) { - GetTopic_P(stemp1, STAT, mqtt_topic, GetPowerDevice(scommand, i, sizeof(scommand), Settings.flag.device_index_enable)); - mqtt_data[0] = '\0'; - MqttPublish(stemp1, Settings.flag.mqtt_power_retain); - } - } - Settings.flag.mqtt_power_retain = XdrvMailbox.payload; - } - ResponseCmndStateText(Settings.flag.mqtt_power_retain); -} - -void CmndSensorRetain(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - if (!XdrvMailbox.payload) { - mqtt_data[0] = '\0'; - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_ENERGY), Settings.flag.mqtt_sensor_retain); - } - Settings.flag.mqtt_sensor_retain = XdrvMailbox.payload; - } - ResponseCmndStateText(Settings.flag.mqtt_sensor_retain); -} - - - - -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - - - -const static uint16_t tls_spi_start_sector = 0xFF; -const static uint8_t* tls_spi_start = (uint8_t*) 0x402FF000; -const static size_t tls_spi_len = 0x1000; -const static size_t tls_block_offset = 0x0400; -const static size_t tls_block_len = 0x0400; -const static size_t tls_obj_store_offset = tls_block_offset + sizeof(tls_dir_t); - - -inline void TlsEraseBuffer(uint8_t *buffer) { - memset(buffer + tls_block_offset, 0xFF, tls_block_len); -} - - - -static br_ec_private_key EC = { - 23, - nullptr, 0 -}; - -static br_x509_certificate CHAIN[] = { - { nullptr, 0 } -}; - - - -void loadTlsDir(void) { - memcpy_P(&tls_dir, tls_spi_start + tls_block_offset, sizeof(tls_dir)); - - - if ((TLS_NAME_SKEY == tls_dir.entry[0].name) && (tls_dir.entry[0].len > 0)) { - EC.x = (unsigned char *)(tls_spi_start + tls_obj_store_offset + tls_dir.entry[0].start); - EC.xlen = tls_dir.entry[0].len; - AWS_IoT_Private_Key = &EC; - } else { - AWS_IoT_Private_Key = nullptr; - } - if ((TLS_NAME_CRT == tls_dir.entry[1].name) && (tls_dir.entry[1].len > 0)) { - CHAIN[0].data = (unsigned char *) (tls_spi_start + tls_obj_store_offset + tls_dir.entry[1].start); - CHAIN[0].data_len = tls_dir.entry[1].len; - AWS_IoT_Client_Certificate = CHAIN; - } else { - AWS_IoT_Client_Certificate = nullptr; - } - -} - -const char ALLOCATE_ERROR[] PROGMEM = "TLSKey " D_JSON_ERROR ": cannot allocate buffer."; - -void CmndTlsKey(void) { -#ifdef DEBUG_DUMP_TLS - if (0 == XdrvMailbox.index){ - CmndTlsDump(); - } -#endif - if ((XdrvMailbox.index >= 1) && (XdrvMailbox.index <= 2)) { - tls_dir_t *tls_dir_write; - - if (XdrvMailbox.data_len > 0) { - - uint8_t *spi_buffer = (uint8_t*) malloc(tls_spi_len); - if (!spi_buffer) { - AddLog_P(LOG_LEVEL_ERROR, ALLOCATE_ERROR); - return; - } - memcpy_P(spi_buffer, tls_spi_start, tls_spi_len); - - - RemoveAllSpaces(XdrvMailbox.data); - - - uint32_t bin_len = decode_base64_length((unsigned char*)XdrvMailbox.data); - uint8_t *bin_buf = nullptr; - if (bin_len > 0) { - bin_buf = (uint8_t*) malloc(bin_len + 4); - if (!bin_buf) { - AddLog_P(LOG_LEVEL_ERROR, ALLOCATE_ERROR); - free(spi_buffer); - return; - } - } - - - if (bin_len > 0) { - decode_base64((unsigned char*)XdrvMailbox.data, bin_buf); - } - - - tls_dir_write = (tls_dir_t*) (spi_buffer + tls_block_offset); - - if (1 == XdrvMailbox.index) { - - - TlsEraseBuffer(spi_buffer); - if (bin_len > 0) { - if (bin_len != 32) { - - AddLog_P2(LOG_LEVEL_INFO, PSTR("TLSKey: Certificate must be 32 bytes: %d."), bin_len); - free(spi_buffer); - free(bin_buf); - return; - } - tls_entry_t *entry = &tls_dir_write->entry[0]; - entry->name = TLS_NAME_SKEY; - entry->start = 0; - entry->len = bin_len; - memcpy(spi_buffer + tls_obj_store_offset + entry->start, bin_buf, entry->len); - } else { - - } - } else if (2 == XdrvMailbox.index) { - - if (TLS_NAME_SKEY != tls_dir.entry[0].name) { - - AddLog_P(LOG_LEVEL_INFO, PSTR("TLSKey: cannot store Cert if no Key previously stored.")); - free(spi_buffer); - free(bin_buf); - return; - } - if (bin_len <= 256) { - - AddLog_P2(LOG_LEVEL_INFO, PSTR("TLSKey: Certificate length too short: %d."), bin_len); - free(spi_buffer); - free(bin_buf); - return; - } - tls_entry_t *entry = &tls_dir_write->entry[1]; - entry->name = TLS_NAME_CRT; - entry->start = (tls_dir_write->entry[0].start + tls_dir_write->entry[0].len + 3) & ~0x03; - entry->len = bin_len; - memcpy(spi_buffer + tls_obj_store_offset + entry->start, bin_buf, entry->len); - } - - if (ESP.flashEraseSector(tls_spi_start_sector)) { - ESP.flashWrite(tls_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); - } - free(spi_buffer); - free(bin_buf); - } - - loadTlsDir(); - Response_P(PSTR("{\"%s1\":%d,\"%s2\":%d}"), - XdrvMailbox.command, AWS_IoT_Private_Key ? tls_dir.entry[0].len : -1, - XdrvMailbox.command, AWS_IoT_Client_Certificate ? tls_dir.entry[1].len : -1); - } -} - -#ifdef DEBUG_DUMP_TLS - -uint32_t bswap32(uint32_t x) { - return ((x << 24) & 0xff000000 ) | - ((x << 8) & 0x00ff0000 ) | - ((x >> 8) & 0x0000ff00 ) | - ((x >> 24) & 0x000000ff ); -} -void CmndTlsDump(void) { - uint32_t start = (uint32_t)tls_spi_start + tls_block_offset; - uint32_t end = start + tls_block_len -1; - for (uint32_t pos = start; pos < end; pos += 0x10) { - uint32_t* values = (uint32_t*)(pos); -#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - Serial.printf("%08x: %08x %08x %08x %08x\n", pos, bswap32(values[0]), bswap32(values[1]), bswap32(values[2]), bswap32(values[3])); -#else - Serial.printf_P(PSTR("%08x: %08x %08x %08x %08x\n"), pos, bswap32(values[0]), bswap32(values[1]), bswap32(values[2]), bswap32(values[3])); -#endif - } -} -#endif -#endif - - - - - -#ifdef USE_WEBSERVER - -#define WEB_HANDLE_MQTT "mq" - -const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; - -const char HTTP_BTN_MENU_MQTT[] PROGMEM = - "

"; - -const char HTTP_FORM_MQTT1[] PROGMEM = - "
 " D_MQTT_PARAMETERS " " - "
" - "

" D_HOST " (" MQTT_HOST ")

" - "

" D_PORT " (" STR(MQTT_PORT) ")

" - "

" D_CLIENT " (%s)

"; -const char HTTP_FORM_MQTT2[] PROGMEM = - "

" D_USER " (" MQTT_USER ")

" - "


" - "

" D_TOPIC " = %%topic%% (%s)

" - "

" D_FULL_TOPIC " (%s)

"; - -void HandleMqttConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); - - if (Webserver->hasArg("save")) { - MqttSaveSettings(); - WebRestart(1); - return; - } - - char str[TOPSZ]; - - WSContentStart_P(S_CONFIGURE_MQTT); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_MQTT1, - SettingsText(SET_MQTT_HOST), - Settings.mqtt_port, - Format(str, MQTT_CLIENT_ID, sizeof(str)), MQTT_CLIENT_ID, SettingsText(SET_MQTT_CLIENT)); - WSContentSend_P(HTTP_FORM_MQTT2, - (!strlen(SettingsText(SET_MQTT_USER))) ? "0" : SettingsText(SET_MQTT_USER), - Format(str, MQTT_TOPIC, sizeof(str)), MQTT_TOPIC, SettingsText(SET_MQTT_TOPIC), - MQTT_FULLTOPIC, MQTT_FULLTOPIC, SettingsText(SET_MQTT_FULLTOPIC)); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void MqttSaveSettings(void) -{ - char tmp[TOPSZ]; - char stemp[TOPSZ]; - char stemp2[TOPSZ]; - - WebGetArg("mt", tmp, sizeof(tmp)); - strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp)); - MakeValidMqtt(0, stemp); - WebGetArg("mf", tmp, sizeof(tmp)); - strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2)); - MakeValidMqtt(1, stemp2); - if ((strcmp(stemp, SettingsText(SET_MQTT_TOPIC))) || (strcmp(stemp2, SettingsText(SET_MQTT_FULLTOPIC)))) { - Response_P((Settings.flag.mqtt_offline) ? S_OFFLINE : ""); - MqttPublishPrefixTopic_P(TELE, S_LWT, true); - } - SettingsUpdateText(SET_MQTT_TOPIC, stemp); - SettingsUpdateText(SET_MQTT_FULLTOPIC, stemp2); - WebGetArg("mh", tmp, sizeof(tmp)); - SettingsUpdateText(SET_MQTT_HOST, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp); - WebGetArg("ml", tmp, sizeof(tmp)); - Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp); - WebGetArg("mc", tmp, sizeof(tmp)); - SettingsUpdateText(SET_MQTT_CLIENT, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp); -#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), - SettingsText(SET_MQTT_HOST), Settings.mqtt_port, SettingsText(SET_MQTT_CLIENT), SettingsText(SET_MQTT_TOPIC), SettingsText(SET_MQTT_FULLTOPIC)); -#else - WebGetArg("mu", tmp, sizeof(tmp)); - SettingsUpdateText(SET_MQTT_USER, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp); - WebGetArg("mp", tmp, sizeof(tmp)); - SettingsUpdateText(SET_MQTT_PWD, (!strlen(tmp)) ? "" : (!strcmp(tmp, D_ASTERISK_PWD)) ? SettingsText(SET_MQTT_PWD) : tmp); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), - SettingsText(SET_MQTT_HOST), Settings.mqtt_port, SettingsText(SET_MQTT_CLIENT), SettingsText(SET_MQTT_USER), SettingsText(SET_MQTT_TOPIC), SettingsText(SET_MQTT_FULLTOPIC)); -#endif -} -#endif - - - - - -bool Xdrv02(uint8_t function) -{ - bool result = false; - - if (Settings.flag.mqtt_enabled) { - switch (function) { - case FUNC_PRE_INIT: - MqttInit(); - break; - case FUNC_EVERY_50_MSECOND: - MqttClient.loop(); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_MQTT); - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); - break; -#endif - case FUNC_COMMAND: - result = DecodeCommand(kMqttCommands, MqttCommand); - break; - } - } - return result; -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_03_energy.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_03_energy.ino" -#ifdef USE_ENERGY_SENSOR - - - - -#define XDRV_03 3 -#define XSNS_03 3 - - - - -#define ENERGY_NONE 0 -#define ENERGY_WATCHDOG 4 - -#include - -#define D_CMND_POWERCAL "PowerCal" -#define D_CMND_VOLTAGECAL "VoltageCal" -#define D_CMND_CURRENTCAL "CurrentCal" -#define D_CMND_TARIFF "Tariff" -#define D_CMND_MODULEADDRESS "ModuleAddress" - -enum EnergyCommands { - CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, - CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS }; - -const char kEnergyCommands[] PROGMEM = "|" - D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|" - D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_MODULEADDRESS "|" -#ifdef USE_ENERGY_MARGIN_DETECTION - D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|" -#ifdef USE_ENERGY_POWER_LIMIT - D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" - D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" - D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW "|" -#endif -#endif - D_CMND_ENERGYRESET "|" D_CMND_TARIFF ; - -void (* const EnergyCommand[])(void) PROGMEM = { - &CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal, - &CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet, &CmndModuleAddress, -#ifdef USE_ENERGY_MARGIN_DETECTION - &CmndPowerDelta, &CmndPowerLow, &CmndPowerHigh, &CmndVoltageLow, &CmndVoltageHigh, &CmndCurrentLow, &CmndCurrentHigh, -#ifdef USE_ENERGY_POWER_LIMIT - &CmndMaxEnergy, &CmndMaxEnergyStart, - &CmndMaxPower, &CmndMaxPowerHold, &CmndMaxPowerWindow, - &CmndSafePower, &CmndSafePowerHold, &CmndSafePowerWindow, -#endif -#endif - &CmndEnergyReset, &CmndTariff }; - -const char kEnergyPhases[] PROGMEM = "|%s / %s|%s / %s / %s||[%s,%s]|[%s,%s,%s]"; - -struct ENERGY { - float voltage[3] = { 0, 0, 0 }; - float current[3] = { 0, 0, 0 }; - float active_power[3] = { 0, 0, 0 }; - float apparent_power[3] = { NAN, NAN, NAN }; - float reactive_power[3] = { NAN, NAN, NAN }; - float power_factor[3] = { NAN, NAN, NAN }; - float frequency[3] = { NAN, NAN, NAN }; - - float start_energy = 0; - float daily = 0; - float total = 0; - float export_active = NAN; - - unsigned long kWhtoday_delta = 0; - unsigned long kWhtoday_offset = 0; - unsigned long kWhtoday; - unsigned long period = 0; - - uint8_t fifth_second = 0; - uint8_t command_code = 0; - uint8_t data_valid[3] = { 0, 0, 0 }; - - uint8_t phase_count = 1; - bool voltage_common = false; - - bool voltage_available = true; - bool current_available = true; - - bool type_dc = false; - bool power_on = true; - -#ifdef USE_ENERGY_MARGIN_DETECTION - uint16_t power_history[3] = { 0 }; - uint8_t power_steady_counter = 8; - bool power_delta = false; - bool min_power_flag = false; - bool max_power_flag = false; - bool min_voltage_flag = false; - bool max_voltage_flag = false; - bool min_current_flag = false; - bool max_current_flag = false; - -#ifdef USE_ENERGY_POWER_LIMIT - uint16_t mplh_counter = 0; - uint16_t mplw_counter = 0; - uint8_t mplr_counter = 0; - uint8_t max_energy_state = 0; -#endif -#endif -} Energy; - -Ticker ticker_energy; - - - -bool EnergyTariff1Active() -{ - uint8_t dst = 0; - if (IsDst() && (Settings.tariff[0][1] != Settings.tariff[1][1])) { - dst = 1; - } - if (Settings.tariff[0][dst] != Settings.tariff[1][dst]) { - if (Settings.flag3.energy_weekend && ((RtcTime.day_of_week == 1) || - (RtcTime.day_of_week == 7))) { - return true; - } - uint32_t minutes = MinutesPastMidnight(); - if (Settings.tariff[0][dst] > Settings.tariff[1][dst]) { - - return ((minutes >= Settings.tariff[0][dst]) || (minutes < Settings.tariff[1][dst])); - } else { - - return ((minutes >= Settings.tariff[0][dst]) && (minutes < Settings.tariff[1][dst])); - } - } else { - return false; - } -} - -void EnergyUpdateToday(void) -{ - if (Energy.kWhtoday_delta > 1000) { - unsigned long delta = Energy.kWhtoday_delta / 1000; - Energy.kWhtoday_delta -= (delta * 1000); - Energy.kWhtoday += delta; - } - - RtcSettings.energy_kWhtoday = Energy.kWhtoday_offset + Energy.kWhtoday; - Energy.daily = (float)(RtcSettings.energy_kWhtoday) / 100000; - Energy.total = (float)(RtcSettings.energy_kWhtotal + RtcSettings.energy_kWhtoday) / 100000; - - if (RtcTime.valid){ - - uint32_t energy_diff = (uint32_t)(Energy.total * 100000) - RtcSettings.energy_usage.last_usage_kWhtotal; - RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total * 100000); - - uint32_t return_diff = 0; - if (!isnan(Energy.export_active)) { - return_diff = (uint32_t)(Energy.export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal; - RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 100000); - } - - if (EnergyTariff1Active()) { - RtcSettings.energy_usage.usage1_kWhtotal += energy_diff; - RtcSettings.energy_usage.return1_kWhtotal += return_diff; - } else { - RtcSettings.energy_usage.usage2_kWhtotal += energy_diff; - RtcSettings.energy_usage.return2_kWhtotal += return_diff; - } - } -} - -void EnergyUpdateTotal(float value, bool kwh) -{ - - - - - uint32_t multiplier = (kwh) ? 100000 : 100; - - if (0 == Energy.start_energy || (value < Energy.start_energy)) { - Energy.start_energy = value; - } - else if (value != Energy.start_energy) { - Energy.kWhtoday = (unsigned long)((value - Energy.start_energy) * multiplier); - } - - if ((Energy.total < (value - 0.01)) && - Settings.flag3.hardware_energy_total) { - RtcSettings.energy_kWhtotal = (unsigned long)((value * multiplier) - Energy.kWhtoday_offset - Energy.kWhtoday); - Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; - Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000; - Settings.energy_kWhtotal_time = (!Energy.kWhtoday_offset) ? LocalTime() : Midnight(); - - } - EnergyUpdateToday(); -} - - - -void Energy200ms(void) -{ - Energy.power_on = (power != 0) | Settings.flag.no_power_on_check; - - Energy.fifth_second++; - if (5 == Energy.fifth_second) { - Energy.fifth_second = 0; - - XnrgCall(FUNC_ENERGY_EVERY_SECOND); - - if (RtcTime.valid) { - if (LocalTime() == Midnight()) { - Settings.energy_kWhyesterday = RtcSettings.energy_kWhtoday; - - RtcSettings.energy_kWhtotal += RtcSettings.energy_kWhtoday; - Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; - Energy.kWhtoday = 0; - Energy.kWhtoday_offset = 0; - RtcSettings.energy_kWhtoday = 0; - Energy.start_energy = 0; - - Energy.kWhtoday_delta = 0; - Energy.period = Energy.kWhtoday; - EnergyUpdateToday(); -#if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - Energy.max_energy_state = 3; -#endif - } -#if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - if ((RtcTime.hour == Settings.energy_max_energy_start) && (3 == Energy.max_energy_state )) { - Energy.max_energy_state = 0; - } -#endif - - } - } - - XnrgCall(FUNC_EVERY_200_MSECOND); -} - -void EnergySaveState(void) -{ - Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; - - Settings.energy_kWhtoday = RtcSettings.energy_kWhtoday; - Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; - - Settings.energy_usage = RtcSettings.energy_usage; -} - -#ifdef USE_ENERGY_MARGIN_DETECTION -bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) -{ - bool change; - - if (!margin) return false; - change = save_flag; - if (type) { - flag = (value > margin); - } else { - flag = (value < margin); - } - save_flag = flag; - return (change != save_flag); -} - -void EnergyMarginCheck(void) -{ - if (Energy.power_steady_counter) { - Energy.power_steady_counter--; - return; - } - - uint16_t energy_power_u = (uint16_t)(Energy.active_power[0]); - - if (Settings.energy_power_delta) { - uint16_t delta = abs(Energy.power_history[0] - energy_power_u); - if (delta > 0) { - if (Settings.energy_power_delta < 101) { - uint16_t min_power = (Energy.power_history[0] > energy_power_u) ? energy_power_u : Energy.power_history[0]; - if (0 == min_power) { min_power++; } - if (((delta * 100) / min_power) > Settings.energy_power_delta) { - Energy.power_delta = true; - } - } else { - if (delta > (Settings.energy_power_delta -100)) { - Energy.power_delta = true; - } - } - if (Energy.power_delta) { - Energy.power_history[1] = Energy.active_power[0]; - Energy.power_history[2] = Energy.active_power[0]; - } - } - } - Energy.power_history[0] = Energy.power_history[1]; - Energy.power_history[1] = Energy.power_history[2]; - Energy.power_history[2] = energy_power_u; - - if (Energy.power_on && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) { - uint16_t energy_voltage_u = (uint16_t)(Energy.voltage[0]); - uint16_t energy_current_u = (uint16_t)(Energy.current[0] * 1000); - - DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); - - Response_P(PSTR("{")); - bool flag; - bool jsonflg = false; - if (EnergyMargin(false, Settings.energy_min_power, energy_power_u, flag, Energy.min_power_flag)) { - ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); - jsonflg = true; - } - if (EnergyMargin(true, Settings.energy_max_power, energy_power_u, flag, Energy.max_power_flag)) { - ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); - jsonflg = true; - } - if (EnergyMargin(false, Settings.energy_min_voltage, energy_voltage_u, flag, Energy.min_voltage_flag)) { - ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); - jsonflg = true; - } - if (EnergyMargin(true, Settings.energy_max_voltage, energy_voltage_u, flag, Energy.max_voltage_flag)) { - ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); - jsonflg = true; - } - if (EnergyMargin(false, Settings.energy_min_current, energy_current_u, flag, Energy.min_current_flag)) { - ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); - jsonflg = true; - } - if (EnergyMargin(true, Settings.energy_max_current, energy_current_u, flag, Energy.max_current_flag)) { - ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); - jsonflg = true; - } - if (jsonflg) { - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); - EnergyMqttShow(); - } - } - -#ifdef USE_ENERGY_POWER_LIMIT - - if (Settings.energy_max_power_limit) { - if (Energy.active_power[0] > Settings.energy_max_power_limit) { - if (!Energy.mplh_counter) { - Energy.mplh_counter = Settings.energy_max_power_limit_hold; - } else { - Energy.mplh_counter--; - if (!Energy.mplh_counter) { - ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHED "\":%d}"), energy_power_u); - MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); - EnergyMqttShow(); - SetAllPower(POWER_ALL_OFF, SRC_MAXPOWER); - if (!Energy.mplr_counter) { - Energy.mplr_counter = Settings.param[P_MAX_POWER_RETRY] +1; - } - Energy.mplw_counter = Settings.energy_max_power_limit_window; - } - } - } - else if (power && (energy_power_u <= Settings.energy_max_power_limit)) { - Energy.mplh_counter = 0; - Energy.mplr_counter = 0; - Energy.mplw_counter = 0; - } - if (!power) { - if (Energy.mplw_counter) { - Energy.mplw_counter--; - } else { - if (Energy.mplr_counter) { - Energy.mplr_counter--; - if (Energy.mplr_counter) { - ResponseTime_P(PSTR(",\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1)); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR)); - RestorePower(true, SRC_MAXPOWER); - } else { - ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0)); - MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); - EnergyMqttShow(); - SetAllPower(POWER_ALL_OFF, SRC_MAXPOWER); - } - } - } - } - } - - - if (Settings.energy_max_energy) { - uint16_t energy_daily_u = (uint16_t)(Energy.daily * 1000); - if (!Energy.max_energy_state && (RtcTime.hour == Settings.energy_max_energy_start)) { - Energy.max_energy_state = 1; - ResponseTime_P(PSTR(",\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1)); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR)); - RestorePower(true, SRC_MAXENERGY); - } - else if ((1 == Energy.max_energy_state ) && (energy_daily_u >= Settings.energy_max_energy)) { - Energy.max_energy_state = 2; - char stemp[FLOATSZ]; - dtostrfd(Energy.daily, 3, stemp); - ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":%s}"), stemp); - MqttPublishPrefixTopic_P(STAT, S_RSLT_WARNING); - EnergyMqttShow(); - SetAllPower(POWER_ALL_OFF, SRC_MAXENERGY); - } - } -#endif - - if (Energy.power_delta) { EnergyMqttShow(); } -} - -void EnergyMqttShow(void) -{ - - int tele_period_save = tele_period; - tele_period = 2; - mqtt_data[0] = '\0'; - ResponseAppendTime(); - EnergyShow(true); - tele_period = tele_period_save; - ResponseJsonEnd(); - MqttPublishTeleSensor(); - Energy.power_delta = false; -} -#endif - -void EnergyEverySecond(void) -{ - - if (global_update) { - if (power && (global_temperature != 9999) && (global_temperature > Settings.param[P_OVER_TEMP])) { - SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP); - } - } - - - uint32_t data_valid = Energy.phase_count; - for (uint32_t i = 0; i < Energy.phase_count; i++) { - if (Energy.data_valid[i] <= ENERGY_WATCHDOG) { - Energy.data_valid[i]++; - if (Energy.data_valid[i] > ENERGY_WATCHDOG) { - - Energy.voltage[i] = 0; - Energy.current[i] = 0; - Energy.active_power[i] = 0; - if (!isnan(Energy.apparent_power[i])) { Energy.apparent_power[i] = 0; } - if (!isnan(Energy.reactive_power[i])) { Energy.reactive_power[i] = 0; } - if (!isnan(Energy.frequency[i])) { Energy.frequency[i] = 0; } - if (!isnan(Energy.power_factor[i])) { Energy.power_factor[i] = 0; } - - data_valid--; - } - } - } - if (!data_valid) { - if (!isnan(Energy.export_active)) { Energy.export_active = 0; } - Energy.start_energy = 0; - - XnrgCall(FUNC_ENERGY_RESET); - } - -#ifdef USE_ENERGY_MARGIN_DETECTION - EnergyMarginCheck(); -#endif -} - - - - - -void EnergyCommandCalResponse(uint32_t nvalue) -{ - snprintf_P(XdrvMailbox.command, CMDSZ, PSTR("%sCal"), XdrvMailbox.command); - ResponseCmndNumber(nvalue); -} - -void CmndEnergyReset(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 3)) { - char *p; - unsigned long lnum = strtoul(XdrvMailbox.data, &p, 10); - if (p != XdrvMailbox.data) { - switch (XdrvMailbox.index) { - case 1: - - Energy.kWhtoday_offset = lnum *100; - Energy.kWhtoday = 0; - Energy.kWhtoday_delta = 0; - Energy.start_energy = 0; - Energy.period = Energy.kWhtoday_offset; - Settings.energy_kWhtoday = Energy.kWhtoday_offset; - RtcSettings.energy_kWhtoday = Energy.kWhtoday_offset; - Energy.daily = (float)Energy.kWhtoday_offset / 100000; - if (!RtcSettings.energy_kWhtotal && !Energy.kWhtoday_offset) { - Settings.energy_kWhtotal_time = LocalTime(); - } - break; - case 2: - - Settings.energy_kWhyesterday = lnum *100; - break; - case 3: - - RtcSettings.energy_kWhtotal = lnum *100; - Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; - - Settings.energy_kWhtotal_time = (!Energy.kWhtoday_offset) ? LocalTime() : Midnight(); - RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total * 1000); - break; - } - } - } - else if ((XdrvMailbox.index > 3) && (XdrvMailbox.index <= 5)) { - uint32_t values[2] = { 0 }; - uint32_t position = ParseParameters(2, values); - values[0] *= 100; - values[1] *= 100; - - switch (XdrvMailbox.index) - { - case 4: - - if (position > 0) { - RtcSettings.energy_usage.usage1_kWhtotal = values[0]; - } - if (position > 1) { - RtcSettings.energy_usage.usage2_kWhtotal = values[1]; - } - Settings.energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal; - Settings.energy_usage.usage2_kWhtotal = RtcSettings.energy_usage.usage2_kWhtotal; - break; - case 5: - - if (position > 0) { - RtcSettings.energy_usage.return1_kWhtotal = values[0]; - } - if (position > 1) { - RtcSettings.energy_usage.return2_kWhtotal = values[1]; - } - Settings.energy_usage.return1_kWhtotal = RtcSettings.energy_usage.return1_kWhtotal; - Settings.energy_usage.return2_kWhtotal = RtcSettings.energy_usage.return2_kWhtotal; - break; - } - } - - Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000; - - char energy_total_chr[FLOATSZ]; - dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr); - char energy_daily_chr[FLOATSZ]; - dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr); - char energy_yesterday_chr[FLOATSZ]; - dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); - - char energy_usage1_chr[FLOATSZ]; - dtostrfd((float)Settings.energy_usage.usage1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_usage1_chr); - char energy_usage2_chr[FLOATSZ]; - dtostrfd((float)Settings.energy_usage.usage2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_usage2_chr); - char energy_return1_chr[FLOATSZ]; - dtostrfd((float)Settings.energy_usage.return1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_return1_chr); - char energy_return2_chr[FLOATSZ]; - dtostrfd((float)Settings.energy_usage.return2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_return2_chr); - - Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s,\"" D_JSON_USAGE "\":[%s,%s],\"" D_JSON_EXPORT "\":[%s,%s]}}"), - XdrvMailbox.command, energy_total_chr, energy_yesterday_chr, energy_daily_chr, energy_usage1_chr, energy_usage2_chr, energy_return1_chr, energy_return2_chr); -} - -void CmndTariff(void) -{ - - - - - - - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) { - uint32_t tariff = XdrvMailbox.index -1; - uint32_t time_type = 0; - char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); - while ((str != nullptr) && (time_type < 2)) { - char *q; - uint32_t value = strtol(str, &q, 10); - Settings.tariff[tariff][time_type] = value; - if (value < 24) { - Settings.tariff[tariff][time_type] *= 60; - char *minute = strtok_r(nullptr, ":", &q); - if (minute) { - value = strtol(minute, nullptr, 10); - if (value > 59) { - value = 59; - } - Settings.tariff[tariff][time_type] += value; - } - } - if (Settings.tariff[tariff][time_type] > 1439) { - Settings.tariff[tariff][time_type] = 1439; - } - str = strtok_r(nullptr, ", ", &p); - time_type++; - } - } - else if (XdrvMailbox.index == 9) { - Settings.flag3.energy_weekend = XdrvMailbox.payload & 1; - } - Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\"}}"), - XdrvMailbox.command, - GetMinuteTime(Settings.tariff[0][0]).c_str(),GetMinuteTime(Settings.tariff[0][1]).c_str(), - GetMinuteTime(Settings.tariff[1][0]).c_str(),GetMinuteTime(Settings.tariff[1][1]).c_str(), - GetStateText(Settings.flag3.energy_weekend)); -} - -void CmndPowerCal(void) -{ - Energy.command_code = CMND_POWERCAL; - if (XnrgCall(FUNC_COMMAND)) { - if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { - Settings.energy_power_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_power_calibration); - } -} - -void CmndVoltageCal(void) -{ - Energy.command_code = CMND_VOLTAGECAL; - if (XnrgCall(FUNC_COMMAND)) { - if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { - Settings.energy_voltage_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_voltage_calibration); - } -} - -void CmndCurrentCal(void) -{ - Energy.command_code = CMND_CURRENTCAL; - if (XnrgCall(FUNC_COMMAND)) { - if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload < 32001)) { - Settings.energy_current_calibration = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_current_calibration); - } -} - -void CmndPowerSet(void) -{ - Energy.command_code = CMND_POWERSET; - if (XnrgCall(FUNC_COMMAND)) { - EnergyCommandCalResponse(Settings.energy_power_calibration); - } -} - -void CmndVoltageSet(void) -{ - Energy.command_code = CMND_VOLTAGESET; - if (XnrgCall(FUNC_COMMAND)) { - EnergyCommandCalResponse(Settings.energy_voltage_calibration); - } -} - -void CmndCurrentSet(void) -{ - Energy.command_code = CMND_CURRENTSET; - if (XnrgCall(FUNC_COMMAND)) { - EnergyCommandCalResponse(Settings.energy_current_calibration); - } -} - -void CmndFrequencySet(void) -{ - Energy.command_code = CMND_FREQUENCYSET; - if (XnrgCall(FUNC_COMMAND)) { - EnergyCommandCalResponse(Settings.energy_frequency_calibration); - } -} - -void CmndModuleAddress(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy.phase_count)) { - Energy.command_code = CMND_MODULEADDRESS; - if (XnrgCall(FUNC_COMMAND)) { - ResponseCmndDone(); - } - } -} - -#ifdef USE_ENERGY_MARGIN_DETECTION -void CmndPowerDelta(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32000)) { - Settings.energy_power_delta = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_power_delta); -} - -void CmndPowerLow(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_min_power = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_min_power); -} - -void CmndPowerHigh(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_power = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power); -} - -void CmndVoltageLow(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 501)) { - Settings.energy_min_voltage = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_min_voltage); -} - -void CmndVoltageHigh(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 501)) { - Settings.energy_max_voltage = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_voltage); -} - -void CmndCurrentLow(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 16001)) { - Settings.energy_min_current = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_min_current); -} - -void CmndCurrentHigh(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 16001)) { - Settings.energy_max_current = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_current); -} - -#ifdef USE_ENERGY_POWER_LIMIT -void CmndMaxPower(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_power_limit = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power_limit); -} - -void CmndMaxPowerHold(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power_limit_hold); -} - -void CmndMaxPowerWindow(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power_limit_window); -} - -void CmndSafePower(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_power_safe_limit = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power_safe_limit); -} - -void CmndSafePowerHold(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_power_safe_limit_hold = (1 == XdrvMailbox.payload) ? SAFE_POWER_HOLD : XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power_safe_limit_hold); -} - -void CmndSafePowerWindow(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 1440)) { - Settings.energy_max_power_safe_limit_window = (1 == XdrvMailbox.payload) ? SAFE_POWER_WINDOW : XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_power_safe_limit_window); -} - -void CmndMaxEnergy(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.energy_max_energy = XdrvMailbox.payload; - Energy.max_energy_state = 3; - } - ResponseCmndNumber(Settings.energy_max_energy); -} - -void CmndMaxEnergyStart(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 24)) { - Settings.energy_max_energy_start = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.energy_max_energy_start); -} -#endif -#endif - -void EnergySnsInit(void) -{ - XnrgCall(FUNC_INIT); - - if (energy_flg) { - if (RtcSettingsValid()) { - Energy.kWhtoday_offset = RtcSettings.energy_kWhtoday; - } - else if (RtcTime.day_of_year == Settings.energy_kWhdoy) { - Energy.kWhtoday_offset = Settings.energy_kWhtoday; - } - else { - Energy.kWhtoday_offset = 0; - } - Energy.kWhtoday = 0; - Energy.kWhtoday_delta = 0; - Energy.period = Energy.kWhtoday_offset; - EnergyUpdateToday(); - ticker_energy.attach_ms(200, Energy200ms); - } -} - -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SNS1[] PROGMEM = - "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" - "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" - "{s}" D_POWER_FACTOR "{m}%s{e}"; - -const char HTTP_ENERGY_SNS2[] PROGMEM = - "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; - -const char HTTP_ENERGY_SNS3[] PROGMEM = - "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; -#endif - -char* EnergyFormatIndex(char* result, char* input, bool json, uint32_t index, bool single = false) -{ - char layout[16]; - GetTextIndexed(layout, sizeof(layout), (index -1) + (3 * json), kEnergyPhases); - switch (index) { - case 2: - snprintf_P(result, FLOATSZ *3, layout, input, input + FLOATSZ); - break; - case 3: - snprintf_P(result, FLOATSZ *3, layout, input, input + FLOATSZ, input + FLOATSZ + FLOATSZ); - break; - default: - snprintf_P(result, FLOATSZ *3, input); - } - return result; -} - -char* EnergyFormat(char* result, char* input, bool json, bool single = false) -{ - uint8_t index = (single) ? 1 : Energy.phase_count; - return EnergyFormatIndex(result, input, json, index, single); -} - -void EnergyShow(bool json) -{ - for (uint32_t i = 0; i < Energy.phase_count; i++) { - if (Energy.voltage_common) { - Energy.voltage[i] = Energy.voltage[0]; - } - } - - float power_factor_knx = Energy.power_factor[0]; - - char apparent_power_chr[Energy.phase_count][FLOATSZ]; - char reactive_power_chr[Energy.phase_count][FLOATSZ]; - char power_factor_chr[Energy.phase_count][FLOATSZ]; - char frequency_chr[Energy.phase_count][FLOATSZ]; - if (!Energy.type_dc) { - if (Energy.current_available && Energy.voltage_available) { - for (uint32_t i = 0; i < Energy.phase_count; i++) { - float apparent_power = Energy.apparent_power[i]; - if (isnan(apparent_power)) { - apparent_power = Energy.voltage[i] * Energy.current[i]; - } - if (apparent_power < Energy.active_power[i]) { - Energy.active_power[i] = apparent_power; - } - - float power_factor = Energy.power_factor[i]; - if (isnan(power_factor)) { - power_factor = (Energy.active_power[i] && apparent_power) ? Energy.active_power[i] / apparent_power : 0; - if (power_factor > 1) { - power_factor = 1; - } - } - if (0 == i) { power_factor_knx = power_factor; } - - float reactive_power = Energy.reactive_power[i]; - if (isnan(reactive_power)) { - reactive_power = 0; - uint32_t difference = ((uint32_t)(apparent_power * 100) - (uint32_t)(Energy.active_power[i] * 100)) / 10; - if ((Energy.current[i] > 0.005) && ((difference > 15) || (difference > (uint32_t)(apparent_power * 100 / 1000)))) { - - - reactive_power = (float)(RoundSqrtInt((uint32_t)(apparent_power * apparent_power * 100) - (uint32_t)(Energy.active_power[i] * Energy.active_power[i] * 100))) / 10; - } - } - - dtostrfd(apparent_power, Settings.flag2.wattage_resolution, apparent_power_chr[i]); - dtostrfd(reactive_power, Settings.flag2.wattage_resolution, reactive_power_chr[i]); - dtostrfd(power_factor, 2, power_factor_chr[i]); - } - } - for (uint32_t i = 0; i < Energy.phase_count; i++) { - float frequency = Energy.frequency[i]; - if (isnan(Energy.frequency[i])) { - frequency = 0; - } - dtostrfd(frequency, Settings.flag2.frequency_resolution, frequency_chr[i]); - } - } - - char voltage_chr[Energy.phase_count][FLOATSZ]; - char current_chr[Energy.phase_count][FLOATSZ]; - char active_power_chr[Energy.phase_count][FLOATSZ]; - for (uint32_t i = 0; i < Energy.phase_count; i++) { - dtostrfd(Energy.voltage[i], Settings.flag2.voltage_resolution, voltage_chr[i]); - dtostrfd(Energy.current[i], Settings.flag2.current_resolution, current_chr[i]); - dtostrfd(Energy.active_power[i], Settings.flag2.wattage_resolution, active_power_chr[i]); - } - - char energy_daily_chr[FLOATSZ]; - dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr); - char energy_yesterday_chr[FLOATSZ]; - dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); - - char energy_total_chr[3][FLOATSZ]; - dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr[0]); - char export_active_chr[3][FLOATSZ]; - dtostrfd(Energy.export_active, Settings.flag2.energy_resolution, export_active_chr[0]); - uint8_t energy_total_fields = 1; - - if (Settings.tariff[0][0] != Settings.tariff[1][0]) { - dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_total_chr[1]); - dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_total_chr[2]); - dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100000, Settings.flag2.energy_resolution, export_active_chr[1]); - dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100000, Settings.flag2.energy_resolution, export_active_chr[2]); - energy_total_fields = 3; - } - - char value_chr[FLOATSZ *3]; - char value2_chr[FLOATSZ *3]; - char value3_chr[FLOATSZ *3]; - - if (json) { - bool show_energy_period = (0 == tele_period); - - ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), - GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormatIndex(value_chr, energy_total_chr[0], json, energy_total_fields), - energy_yesterday_chr, - energy_daily_chr); - - if (!isnan(Energy.export_active)) { - ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormatIndex(value_chr, export_active_chr[0], json, energy_total_fields)); - } - - if (show_energy_period) { - float energy = 0; - if (Energy.period) { - energy = (float)(RtcSettings.energy_kWhtoday - Energy.period) / 100; - } - Energy.period = RtcSettings.energy_kWhtoday; - char energy_period_chr[FLOATSZ]; - dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr); - ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), energy_period_chr); - } - ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), - EnergyFormat(value_chr, active_power_chr[0], json)); - if (!Energy.type_dc) { - if (Energy.current_available && Energy.voltage_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), - EnergyFormat(value_chr, apparent_power_chr[0], json), - EnergyFormat(value2_chr, reactive_power_chr[0], json), - EnergyFormat(value3_chr, power_factor_chr[0], json)); - } - if (!isnan(Energy.frequency[0])) { - ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, frequency_chr[0], json, Energy.voltage_common)); - } - } - if (Energy.voltage_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, voltage_chr[0], json, Energy.voltage_common)); - } - if (Energy.current_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), - EnergyFormat(value_chr, current_chr[0], json)); - } - XnrgCall(FUNC_JSON_APPEND); - ResponseJsonEnd(); - -#ifdef USE_DOMOTICZ - if (show_energy_period) { - dtostrfd(Energy.total * 1000, 1, energy_total_chr[0]); - DomoticzSensorPowerEnergy((int)Energy.active_power[0], energy_total_chr[0]); - - dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100, 1, energy_total_chr[1]); - dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100, 1, energy_total_chr[2]); - dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100, 1, export_active_chr[1]); - dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100, 1, export_active_chr[2]); - DomoticzSensorP1SmartMeter(energy_total_chr[1], energy_total_chr[2], export_active_chr[1], export_active_chr[2], (int)Energy.active_power[0]); - - if (Energy.voltage_available) { - DomoticzSensor(DZ_VOLTAGE, voltage_chr[0]); - } - if (Energy.current_available) { - DomoticzSensor(DZ_CURRENT, current_chr[0]); - } - } -#endif -#ifdef USE_KNX - if (show_energy_period) { - if (Energy.voltage_available) { - KnxSensor(KNX_ENERGY_VOLTAGE, Energy.voltage[0]); - } - if (Energy.current_available) { - KnxSensor(KNX_ENERGY_CURRENT, Energy.current[0]); - } - KnxSensor(KNX_ENERGY_POWER, Energy.active_power[0]); - if (!Energy.type_dc) { - KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor_knx); - } - KnxSensor(KNX_ENERGY_DAILY, Energy.daily); - KnxSensor(KNX_ENERGY_TOTAL, Energy.total); - KnxSensor(KNX_ENERGY_START, Energy.start_energy); - } -#endif -#ifdef USE_WEBSERVER - } else { - if (Energy.voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, EnergyFormat(value_chr, voltage_chr[0], json, Energy.voltage_common)); - } - if (Energy.current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, EnergyFormat(value_chr, current_chr[0], json)); - } - WSContentSend_PD(HTTP_SNS_POWER, EnergyFormat(value_chr, active_power_chr[0], json)); - if (!Energy.type_dc) { - if (Energy.current_available && Energy.voltage_available) { - WSContentSend_PD(HTTP_ENERGY_SNS1, EnergyFormat(value_chr, apparent_power_chr[0], json), - EnergyFormat(value2_chr, reactive_power_chr[0], json), - EnergyFormat(value3_chr, power_factor_chr[0], json)); - } - if (!isnan(Energy.frequency[0])) { - WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - EnergyFormat(value_chr, frequency_chr[0], json, Energy.voltage_common)); - } - } - WSContentSend_PD(HTTP_ENERGY_SNS2, energy_daily_chr, energy_yesterday_chr, energy_total_chr[0]); - if (!isnan(Energy.export_active)) { - WSContentSend_PD(HTTP_ENERGY_SNS3, export_active_chr[0]); - } - - XnrgCall(FUNC_WEB_SENSOR); -#endif - } -} - - - - - -bool Xdrv03(uint8_t function) -{ - bool result = false; - - if (FUNC_PRE_INIT == function) { - energy_flg = ENERGY_NONE; - XnrgCall(FUNC_PRE_INIT); - } - else if (energy_flg) { - switch (function) { - case FUNC_LOOP: - XnrgCall(FUNC_LOOP); - break; - case FUNC_EVERY_250_MSECOND: - XnrgCall(FUNC_EVERY_250_MSECOND); - break; - case FUNC_SERIAL: - result = XnrgCall(FUNC_SERIAL); - break; -#ifdef USE_ENERGY_MARGIN_DETECTION - case FUNC_SET_POWER: - Energy.power_steady_counter = 2; - break; -#endif - case FUNC_COMMAND: - result = DecodeCommand(kEnergyCommands, EnergyCommand); - break; - } - } - return result; -} - -bool Xsns03(uint8_t function) -{ - bool result = false; - - if (energy_flg) { - switch (function) { - case FUNC_EVERY_SECOND: - EnergyEverySecond(); - break; - case FUNC_JSON_APPEND: - EnergyShow(true); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - EnergyShow(false); - break; -#endif - case FUNC_SAVE_BEFORE_RESTART: - EnergySaveState(); - break; - case FUNC_INIT: - EnergySnsInit(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" -#ifdef USE_LIGHT -# 124 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" -#define XDRV_04 4 - - -enum LightSchemes { LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX }; - -const uint8_t LIGHT_COLOR_SIZE = 25; - -const char kLightCommands[] PROGMEM = "|" - D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_DIMMER_RANGE "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|" - D_CMND_RGBWWTABLE "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|" - D_CMND_WHITE "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR -#ifdef USE_LIGHT_PALETTE - "|" D_CMND_PALETTE -#endif - "|UNDOCA" ; - -void (* const LightCommand[])(void) PROGMEM = { - &CmndColor, &CmndColorTemperature, &CmndDimmer, &CmndDimmerRange, &CmndLedTable, &CmndFade, - &CmndRgbwwTable, &CmndScheme, &CmndSpeed, &CmndWakeup, &CmndWakeupDuration, - &CmndWhite, &CmndChannel, &CmndHsbColor, -#ifdef USE_LIGHT_PALETTE - &CmndPalette, -#endif - &CmndUndocA }; - - -enum LightColorModes { - LCM_RGB = 1, LCM_CT = 2, LCM_BOTH = 3 }; - -struct LRgbColor { - uint8_t R, G, B; -}; -const uint8_t MAX_FIXED_COLOR = 12; -const LRgbColor kFixedColor[MAX_FIXED_COLOR] PROGMEM = - { 255,0,0, 0,255,0, 0,0,255, 228,32,0, 0,228,32, 0,32,228, 188,64,0, 0,160,96, 160,32,240, 255,255,0, 255,0,170, 255,255,255 }; - -struct LWColor { - uint8_t W; -}; -const uint8_t MAX_FIXED_WHITE = 4; -const LWColor kFixedWhite[MAX_FIXED_WHITE] PROGMEM = { 0, 255, 128, 32 }; - -struct LCwColor { - uint8_t C, W; -}; -const uint8_t MAX_FIXED_COLD_WARM = 4; -const LCwColor kFixedColdWarm[MAX_FIXED_COLD_WARM] PROGMEM = { 0,0, 255,0, 0,255, 128,128 }; - - -const uint16_t CT_MIN = 153; -const uint16_t CT_MAX = 500; - -const uint16_t CT_MIN_ALEXA = 200; -const uint16_t CT_MAX_ALEXA = 380; - - - - - - -typedef struct gamma_table_t { - uint16_t to_src; - uint16_t to_gamma; -} gamma_table_t; - -const gamma_table_t gamma_table[] = { - { 1, 1 }, - { 4, 1 }, - { 209, 13 }, - { 312, 41 }, - { 457, 106 }, - { 626, 261 }, - { 762, 450 }, - { 895, 703 }, - { 1023, 1023 }, - { 0xFFFF, 0xFFFF } -}; - - -const gamma_table_t gamma_table_fast[] = { - { 384, 192 }, - { 768, 576 }, - { 1023, 1023 }, - { 0xFFFF, 0xFFFF } -}; -# 256 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" -struct LIGHT { - uint32_t strip_timer_counter = 0; - power_t power = 0; - - uint16_t wakeup_counter = 0; - - uint8_t entry_color[LST_MAX]; - uint8_t current_color[LST_MAX]; - uint8_t new_color[LST_MAX]; - uint8_t last_color[LST_MAX]; - uint8_t color_remap[LST_MAX]; - - uint8_t wheel = 0; - uint8_t random = 0; - uint8_t subtype = 0; - uint8_t device = 0; - uint8_t old_power = 1; - uint8_t wakeup_active = 0; - uint8_t wakeup_dimmer = 0; - uint8_t fixed_color_index = 1; - uint8_t pwm_offset = 0; - uint8_t max_scheme = LS_MAX -1; - - bool update = true; - bool pwm_multi_channels = false; - - bool fade_initialized = false; - bool fade_running = false; -#ifdef USE_DEVICE_GROUPS - bool devgrp_no_channels_out = false; -#endif -#ifdef USE_LIGHT_PALETTE - uint8_t palette_count = 0; - uint8_t * palette; -#endif - uint16_t fade_start_10[LST_MAX] = {0,0,0,0,0}; - uint16_t fade_cur_10[LST_MAX]; - uint16_t fade_end_10[LST_MAX]; - uint16_t fade_duration = 0; - uint32_t fade_start = 0; - - uint16_t pwm_min = 0; - uint16_t pwm_max = 1023; -} Light; - -power_t LightPower(void) -{ - return Light.power; -} - - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 -power_t LightPowerIRAM(void) ICACHE_RAM_ATTR; -#endif - -power_t LightPowerIRAM(void) -{ - return Light.power; -} - -uint8_t LightDevice(void) -{ - return Light.device; -} - -static uint32_t min3(uint32_t a, uint32_t b, uint32_t c) { - return (a < b && a < c) ? a : (b < c) ? b : c; -} -# 362 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" -class LightStateClass { - private: - uint16_t _hue = 0; - uint8_t _sat = 255; - uint8_t _briRGB = 255; - - uint8_t _r = 255; - uint8_t _g = 255; - uint8_t _b = 255; - - uint8_t _subtype = 0; - uint16_t _ct = CT_MIN; - uint8_t _wc = 255; - uint8_t _ww = 0; - uint8_t _briCT = 255; - - uint8_t _color_mode = LCM_RGB; - - - - - - uint16_t _ct_min_range = CT_MIN; - uint16_t _ct_max_range = CT_MAX; - - public: - LightStateClass() { - - } - - void setSubType(uint8_t sub_type) { - _subtype = sub_type; - } -# 404 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" - uint8_t setColorMode(uint8_t cm) { - uint8_t prev_cm = _color_mode; - if (cm < LCM_RGB) { cm = LCM_RGB; } - if (cm > LCM_BOTH) { cm = LCM_BOTH; } - uint8_t maxbri = (_briRGB >= _briCT) ? _briRGB : _briCT; - - switch (_subtype) { - case LST_COLDWARM: - _color_mode = LCM_CT; - break; - - case LST_NONE: - case LST_SINGLE: - case LST_RGB: - default: - _color_mode = LCM_RGB; - break; - - case LST_RGBW: - case LST_RGBCW: - _color_mode = cm; - break; - } - if (LCM_RGB == _color_mode) { - _briCT = 0; - if (0 == _briRGB) { _briRGB = maxbri; } - } - if (LCM_CT == _color_mode) { - _briRGB = 0; - if (0 == _briCT) { _briCT = maxbri; } - } -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setColorMode prev_cm (%d) req_cm (%d) new_cm (%d)", prev_cm, cm, _color_mode); -#endif - return prev_cm; - } - - inline uint8_t getColorMode() { - return _color_mode; - } - - void addRGBMode() { - setColorMode(_color_mode | LCM_RGB); - } - void addCTMode() { - setColorMode(_color_mode | LCM_CT); - } - - - void getRGB(uint8_t *r, uint8_t *g, uint8_t *b) { - if (r) { *r = _r; } - if (g) { *g = _g; } - if (b) { *b = _b; } - } - - - - void getCW(uint8_t *rc, uint8_t *rw) { - if (rc) { *rc = _wc; } - if (rw) { *rw = _ww; } - } - - - void getActualRGBCW(uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *c, uint8_t *w) { - bool rgb_channels_on = _color_mode & LCM_RGB; - bool ct_channels_on = _color_mode & LCM_CT; - - if (r) { *r = rgb_channels_on ? changeUIntScale(_r, 0, 255, 0, _briRGB) : 0; } - if (g) { *g = rgb_channels_on ? changeUIntScale(_g, 0, 255, 0, _briRGB) : 0; } - if (b) { *b = rgb_channels_on ? changeUIntScale(_b, 0, 255, 0, _briRGB) : 0; } - - if (c) { *c = ct_channels_on ? changeUIntScale(_wc, 0, 255, 0, _briCT) : 0; } - if (w) { *w = ct_channels_on ? changeUIntScale(_ww, 0, 255, 0, _briCT) : 0; } - } - - uint8_t getChannels(uint8_t *channels) { - getActualRGBCW(&channels[0], &channels[1], &channels[2], &channels[3], &channels[4]); - } - - void getChannelsRaw(uint8_t *channels) { - channels[0] = _r; - channels[1] = _g; - channels[2] = _b; - channels[3] = _wc; - channels[4] = _ww; - } - - void getHSB(uint16_t *hue, uint8_t *sat, uint8_t *bri) { - if (hue) { *hue = _hue; } - if (sat) { *sat = _sat; } - if (bri) { *bri = _briRGB; } - } - - - uint8_t getBri(void) { - - return (_briRGB >= _briCT) ? _briRGB : _briCT; - } - - - inline uint8_t getBriCT() { - return _briCT; - } - - static inline uint8_t DimmerToBri(uint8_t dimmer) { - return changeUIntScale(dimmer, 0, 100, 0, 255); - } - static uint8_t BriToDimmer(uint8_t bri) { - uint8_t dimmer = changeUIntScale(bri, 0, 255, 0, 100); - - if ((dimmer == 0) && (bri > 0)) { dimmer = 1; } - return dimmer; - } - - uint8_t getDimmer(uint32_t mode = 0) { - uint8_t bri; - switch (mode) { - case 1: - bri = getBriRGB(); - break; - case 2: - bri = getBriCT(); - break; - default: - bri = getBri(); - break; - } - return BriToDimmer(bri); - } - - inline uint16_t getCT() const { - return _ct; - } - - - uint16_t getCT10bits() const { - return changeUIntScale(_ct, _ct_min_range, _ct_max_range, 0, 1023); - } - - inline void setCTRange(uint16_t ct_min_range, uint16_t ct_max_range) { - _ct_min_range = ct_min_range; - _ct_max_range = ct_max_range; - } - - inline void getCTRange(uint16_t *ct_min_range, uint16_t *ct_max_range) const { - if (ct_min_range) { *ct_min_range = _ct_min_range; } - if (ct_max_range) { *ct_max_range = _ct_max_range; } - } - - - void getXY(float *x, float *y) { - RgbToXy(_r, _g, _b, x, y); - } - - - - void setBri(uint8_t bri) { - setBriRGB(_color_mode & LCM_RGB ? bri : 0); - setBriCT(_color_mode & LCM_CT ? bri : 0); -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setBri RGB raw (%d %d %d) HS (%d %d) bri (%d)", _r, _g, _b, _hue, _sat, _briRGB); -#endif -#ifdef USE_PWM_DIMMER - if (PWM_DIMMER == my_module_type) PWMDimmerSetBrightnessLeds(0); -#endif - } - - - uint8_t setBriRGB(uint8_t bri_rgb) { - uint8_t prev_bri = _briRGB; - _briRGB = bri_rgb; - if (bri_rgb > 0) { addRGBMode(); } - return prev_bri; - } - - - uint8_t setBriCT(uint8_t bri_ct) { - uint8_t prev_bri = _briCT; - _briCT = bri_ct; - if (bri_ct > 0) { addCTMode(); } - return prev_bri; - } - - inline uint8_t getBriRGB() { - return _briRGB; - } - - void setDimmer(uint8_t dimmer) { - setBri(DimmerToBri(dimmer)); - } - - void setCT(uint16_t ct) { - if (0 == ct) { - - setColorMode(LCM_RGB); - } else { - ct = (ct < CT_MIN ? CT_MIN : (ct > CT_MAX ? CT_MAX : ct)); - _ww = changeUIntScale(ct, _ct_min_range, _ct_max_range, 0, 255); - _wc = 255 - _ww; - _ct = ct; - addCTMode(); - } -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setCT RGB raw (%d %d %d) HS (%d %d) briRGB (%d) briCT (%d) CT (%d)", _r, _g, _b, _hue, _sat, _briRGB, _briCT, _ct); -#endif - } -# 625 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" - void setCW(uint8_t c, uint8_t w, bool free_range = false) { - uint16_t max = (w > c) ? w : c; - uint16_t sum = c + w; - - if (0 == max) { - _briCT = 0; - setColorMode(LCM_RGB); - } else { - if (!free_range) { - - _ww = changeUIntScale(w, 0, sum, 0, 255); - _wc = 255 - _ww; - } else { - _ww = changeUIntScale(w, 0, max, 0, 255); - _wc = changeUIntScale(c, 0, max, 0, 255); - } - _ct = changeUIntScale(w, 0, sum, _ct_min_range, _ct_max_range); - addCTMode(); - if (_color_mode & LCM_CT) { _briCT = free_range ? max : (sum > 255 ? 255 : sum); } - } -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setCW CW (%d %d) CT (%d) briCT (%d)", c, w, _ct, _briCT); -#endif - } - - - uint8_t setRGB(uint8_t r, uint8_t g, uint8_t b, bool keep_bri = false) { - uint16_t hue; - uint8_t sat; -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setRGB RGB input (%d %d %d)", r, g, b); -#endif - - uint32_t max = (r > g && r > b) ? r : (g > b) ? g : b; - - if (0 == max) { - r = g = b = 255; - setColorMode(LCM_CT); - } else { - if (255 > max) { - - r = changeUIntScale(r, 0, max, 0, 255); - g = changeUIntScale(g, 0, max, 0, 255); - b = changeUIntScale(b, 0, max, 0, 255); - } - addRGBMode(); - } - if (!keep_bri) { - _briRGB = (_color_mode & LCM_RGB) ? max : 0; - } - - RgbToHsb(r, g, b, &hue, &sat, nullptr); - _r = r; - _g = g; - _b = b; - _hue = hue; - _sat = sat; -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setRGB RGB raw (%d %d %d) HS (%d %d) bri (%d)", _r, _g, _b, _hue, _sat, _briRGB); -#endif - return max; - } - - void setHS(uint16_t hue, uint8_t sat) { - uint8_t r, g, b; - HsToRgb(hue, sat, &r, &g, &b); - _r = r; - _g = g; - _b = b; - _hue = hue; - _sat = sat; - addRGBMode(); -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setHS HS (%d %d) rgb (%d %d %d)", hue, sat, r, g, b); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setHS RGB raw (%d %d %d) HS (%d %d) bri (%d)", _r, _g, _b, _hue, _sat, _briRGB); -#endif - } - - - - void setChannelsRaw(uint8_t *channels) { - _r = channels[0]; - _g = channels[1]; - _b = channels[2]; - _wc = channels[3]; - _ww = channels[4]; -} - - - - - void setChannels(uint8_t *channels) { - setRGB(channels[0], channels[1], channels[2]); - setCW(channels[3], channels[4], true); -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setChannels (%d %d %d %d %d)", - channels[0], channels[1], channels[2], channels[3], channels[4]); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightStateClass::setChannels CT (%d) briRGB (%d) briCT (%d)", _ct, _briRGB, _briCT); -#endif - } - - - static void RgbToHsb(uint8_t r, uint8_t g, uint8_t b, uint16_t *r_hue, uint8_t *r_sat, uint8_t *r_bri); - static void HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b); - static void RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y); - static void XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_t *rb); - -}; -# 741 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_04_light.ino" -void LightStateClass::RgbToHsb(uint8_t ir, uint8_t ig, uint8_t ib, uint16_t *r_hue, uint8_t *r_sat, uint8_t *r_bri) { - uint32_t r = ir; - uint32_t g = ig; - uint32_t b = ib; - uint32_t max = (r > g && r > b) ? r : (g > b) ? g : b; - uint32_t min = (r < g && r < b) ? r : (g < b) ? g : b; - uint32_t d = max - min; - - uint16_t hue = 0; - uint8_t sat = 0; - uint8_t bri = max; - - if (d != 0) { - sat = changeUIntScale(d, 0, max, 0, 255); - if (r == max) { - hue = (g > b) ? changeUIntScale(g-b,0,d,0,60) : 360 - changeUIntScale(b-g,0,d,0,60); - } else if (g == max) { - hue = (b > r) ? 120 + changeUIntScale(b-r,0,d,0,60) : 120 - changeUIntScale(r-b,0,d,0,60); - } else { - hue = (r > g) ? 240 + changeUIntScale(r-g,0,d,0,60) : 240 - changeUIntScale(g-r,0,d,0,60); - } - hue = hue % 360; - } - - if (r_hue) *r_hue = hue; - if (r_sat) *r_sat = sat; - if (r_bri) *r_bri = bri; - -} - -void LightStateClass::HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b) { - uint32_t r = 255; - uint32_t g = 255; - uint32_t b = 255; - - hue = hue % 360; - - if (sat > 0) { - uint32_t i = hue / 60; - uint32_t f = hue % 60; - uint32_t q = 255 - changeUIntScale(f, 0, 60, 0, sat); - uint32_t p = 255 - sat; - uint32_t t = 255 - changeUIntScale(60 - f, 0, 60, 0, sat); - - switch (i) { - case 0: - - g = t; - b = p; - break; - case 1: - r = q; - - b = p; - break; - case 2: - r = p; - - b = t; - break; - case 3: - r = p; - g = q; - - break; - case 4: - r = t; - g = p; - - break; - default: - - g = p; - b = q; - break; - } - } - if (r_r) *r_r = r; - if (r_g) *r_g = g; - if (r_b) *r_b = b; -} - -#define POW FastPrecisePowf - -void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y) { - float x = 0.31271f; - float y = 0.32902f; - - if (i_r + i_b + i_g > 0) { - float r = (float)i_r / 255.0f; - float g = (float)i_g / 255.0f; - float b = (float)i_b / 255.0f; - - - r = (r > 0.04045f) ? POW((r + 0.055f) / (1.0f + 0.055f), 2.4f) : (r / 12.92f); - g = (g > 0.04045f) ? POW((g + 0.055f) / (1.0f + 0.055f), 2.4f) : (g / 12.92f); - b = (b > 0.04045f) ? POW((b + 0.055f) / (1.0f + 0.055f), 2.4f) : (b / 12.92f); - - - - float X = r * 0.649926f + g * 0.103455f + b * 0.197109f; - float Y = r * 0.234327f + g * 0.743075f + b * 0.022598f; - float Z = r * 0.000000f + g * 0.053077f + b * 1.035763f; - - x = X / (X + Y + Z); - y = Y / (X + Y + Z); - - } - if (r_x) *r_x = x; - if (r_y) *r_y = y; -} - -void LightStateClass::XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_t *rb) -{ - x = (x > 0.99f ? 0.99f : (x < 0.01f ? 0.01f : x)); - y = (y > 0.99f ? 0.99f : (y < 0.01f ? 0.01f : y)); - float z = 1.0f - x - y; - - float X = x / y; - float Z = z / y; - - - - float r = X * 3.2406f - 1.5372f - Z * 0.4986f; - float g = -X * 0.9689f + 1.8758f + Z * 0.0415f; - float b = X * 0.0557f - 0.2040f + Z * 1.0570f; - float max = (r > g && r > b) ? r : (g > b) ? g : b; - r = r / max; - g = g / max; - b = b / max; - r = (r <= 0.0031308f) ? 12.92f * r : 1.055f * POW(r, (1.0f / 2.4f)) - 0.055f; - g = (g <= 0.0031308f) ? 12.92f * g : 1.055f * POW(g, (1.0f / 2.4f)) - 0.055f; - b = (b <= 0.0031308f) ? 12.92f * b : 1.055f * POW(b, (1.0f / 2.4f)) - 0.055f; - - - - - - int32_t ir = r * 255.0f + 0.5f; - int32_t ig = g * 255.0f + 0.5f; - int32_t ib = b * 255.0f + 0.5f; - if (rr) { *rr = (ir > 255 ? 255: (ir < 0 ? 0 : ir)); } - if (rg) { *rg = (ig > 255 ? 255: (ig < 0 ? 0 : ig)); } - if (rb) { *rb = (ib > 255 ? 255: (ib < 0 ? 0 : ib)); } -} - -class LightControllerClass { -private: - LightStateClass *_state; - - - bool _ct_rgb_linked = true; - bool _pwm_multi_channels = false; - -public: - LightControllerClass(LightStateClass& state) { - _state = &state; - } - - void setSubType(uint8_t sub_type) { - _state->setSubType(sub_type); - } - - inline bool setCTRGBLinked(bool ct_rgb_linked) { - bool prev = _ct_rgb_linked; - if (_pwm_multi_channels) { - _ct_rgb_linked = false; - } else { - _ct_rgb_linked = ct_rgb_linked; - } - return prev; - } - - void setAlexaCTRange(bool alexa_ct_range) { - - if (alexa_ct_range) { - _state->setCTRange(CT_MIN_ALEXA, CT_MAX_ALEXA); - } else { - _state->setCTRange(CT_MIN, CT_MAX); - } - } - - inline bool isCTRGBLinked() { - return _ct_rgb_linked; - } - - inline bool setPWMMultiChannel(bool pwm_multi_channels) { - bool prev = _pwm_multi_channels; - _pwm_multi_channels = pwm_multi_channels; - if (pwm_multi_channels) setCTRGBLinked(false); - return prev; - } - - inline bool isPWMMultiChannel(void) { - return _pwm_multi_channels; - } - -#ifdef DEBUG_LIGHT - void debugLogs() { - uint8_t r,g,b,c,w; - _state->getActualRGBCW(&r,&g,&b,&c,&w); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::debugLogs rgb (%d %d %d) cw (%d %d)", - r, g, b, c, w); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::debugLogs lightCurrent (%d %d %d %d %d)", - Light.current_color[0], Light.current_color[1], Light.current_color[2], - Light.current_color[3], Light.current_color[4]); - } -#endif - - void loadSettings() { -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::loadSettings Settings.light_color (%d %d %d %d %d - %d)", - Settings.light_color[0], Settings.light_color[1], Settings.light_color[2], - Settings.light_color[3], Settings.light_color[4], Settings.light_dimmer); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::loadSettings light_type/sub (%d %d)", - light_type, Light.subtype); -#endif - if (_pwm_multi_channels) { - _state->setChannelsRaw(Settings.light_color); - } else { - - _state->setCW(Settings.light_color[3], Settings.light_color[4], true); - _state->setRGB(Settings.light_color[0], Settings.light_color[1], Settings.light_color[2]); - - - - uint8_t bri = _state->DimmerToBri(Settings.light_dimmer); - - - - if ((DEFAULT_LIGHT_COMPONENT == Settings.light_color[0]) && - (DEFAULT_LIGHT_COMPONENT == Settings.light_color[1]) && - (DEFAULT_LIGHT_COMPONENT == Settings.light_color[2]) && - (DEFAULT_LIGHT_COMPONENT == Settings.light_color[3]) && - (DEFAULT_LIGHT_COMPONENT == Settings.light_color[4]) && - (DEFAULT_LIGHT_DIMMER == Settings.light_dimmer) ) { - _state->setBriCT(bri); - _state->setBriRGB(bri); - _state->setColorMode(LCM_RGB); - } - - if (Settings.light_color[0] + Settings.light_color[1] + Settings.light_color[2] > 0) { - _state->setBriRGB(bri); - } else { - _state->setBriCT(bri); - } - } - } - - void changeCTB(uint16_t new_ct, uint8_t briCT) { - - - - - - - if ((LST_COLDWARM != Light.subtype) && (LST_RGBW > Light.subtype)) { - return; - } - _state->setCT(new_ct); - _state->setBriCT(briCT); - if (_ct_rgb_linked) { _state->setColorMode(LCM_CT); } - saveSettings(); - calcLevels(); - - } - - void changeDimmer(uint8_t dimmer, uint32_t mode = 0) { - uint8_t bri = changeUIntScale(dimmer, 0, 100, 0, 255); - switch (mode) { - case 1: - changeBriRGB(bri); - if (_ct_rgb_linked) { _state->setColorMode(LCM_RGB); } - break; - case 2: - changeBriCT(bri); - if (_ct_rgb_linked) { _state->setColorMode(LCM_CT); } - break; - default: - changeBri(bri); - break; - } - } - - void changeBri(uint8_t bri) { - _state->setBri(bri); - saveSettings(); - calcLevels(); - } - - void changeBriRGB(uint8_t bri) { - _state->setBriRGB(bri); - saveSettings(); - calcLevels(); - } - - void changeBriCT(uint8_t bri) { - _state->setBriCT(bri); - saveSettings(); - calcLevels(); - } - - void changeRGB(uint8_t r, uint8_t g, uint8_t b, bool keep_bri = false) { - _state->setRGB(r, g, b, keep_bri); - if (_ct_rgb_linked) { _state->setColorMode(LCM_RGB); } - saveSettings(); - calcLevels(); - } - - - - void calcLevels(uint8_t *current_color = nullptr) { - uint8_t r,g,b,c,w,briRGB,briCT; - if (current_color == nullptr) { current_color = Light.current_color; } - - if (_pwm_multi_channels) { - _state->getChannelsRaw(current_color); - return; - } - - _state->getActualRGBCW(&r,&g,&b,&c,&w); - briRGB = _state->getBriRGB(); - briCT = _state->getBriCT(); - - current_color[0] = current_color[1] = current_color[2] = 0; - current_color[3] = current_color[4] = 0; - switch (Light.subtype) { - case LST_NONE: - current_color[0] = 255; - break; - case LST_SINGLE: - current_color[0] = briRGB; - break; - case LST_COLDWARM: - current_color[0] = c; - current_color[1] = w; - break; - case LST_RGBW: - case LST_RGBCW: - if (LST_RGBCW == Light.subtype) { - current_color[3] = c; - current_color[4] = w; - } else { - current_color[3] = briCT; - } - - case LST_RGB: - current_color[0] = r; - current_color[1] = g; - current_color[2] = b; - break; - } - } - - void changeHSB(uint16_t hue, uint8_t sat, uint8_t briRGB) { - _state->setHS(hue, sat); - _state->setBriRGB(briRGB); - if (_ct_rgb_linked) { _state->setColorMode(LCM_RGB); } - saveSettings(); - calcLevels(); - } - - - void saveSettings() { - if (Light.pwm_multi_channels) { - - _state->getChannelsRaw(Settings.light_color); - Settings.light_dimmer = 100; - } else { - uint8_t cm = _state->getColorMode(); - - memset(&Settings.light_color[0], 0, sizeof(Settings.light_color)); - if (LCM_RGB & cm) { - _state->getRGB(&Settings.light_color[0], &Settings.light_color[1], &Settings.light_color[2]); - Settings.light_dimmer = _state->BriToDimmer(_state->getBriRGB()); - - if (LCM_BOTH == cm) { - - _state->getActualRGBCW(nullptr, nullptr, nullptr, &Settings.light_color[3], &Settings.light_color[4]); - } - } else if (LCM_CT == cm) { - _state->getCW(&Settings.light_color[3], &Settings.light_color[4]); - Settings.light_dimmer = _state->BriToDimmer(_state->getBriCT()); - } - } -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::saveSettings Settings.light_color (%d %d %d %d %d - %d)", - Settings.light_color[0], Settings.light_color[1], Settings.light_color[2], - Settings.light_color[3], Settings.light_color[4], Settings.light_dimmer); -#endif - } - - - - - void changeChannels(uint8_t *channels) { - if (Light.pwm_multi_channels) { - _state->setChannelsRaw(channels); - } else if (LST_COLDWARM == Light.subtype) { - - uint8_t remapped_channels[5] = {0,0,0,channels[0],channels[1]}; - _state->setChannels(remapped_channels); - } else { - _state->setChannels(channels); - } - - saveSettings(); - calcLevels(); - } -}; - - - -LightStateClass light_state = LightStateClass(); -LightControllerClass light_controller = LightControllerClass(light_state); - - - - - -uint16_t change8to10(uint8_t v) { - return changeUIntScale(v, 0, 255, 0, 1023); -} - -uint8_t change10to8(uint16_t v) { - return (0 == v) ? 0 : changeUIntScale(v, 4, 1023, 1, 255); -} - - - - - -uint16_t ledGamma_internal(uint16_t v, const struct gamma_table_t *gt_ptr) { - uint16_t from_src = 0; - uint16_t from_gamma = 0; - - for (const gamma_table_t *gt = gt_ptr; ; gt++) { - uint16_t to_src = gt->to_src; - uint16_t to_gamma = gt->to_gamma; - if (v <= to_src) { - return changeUIntScale(v, from_src, to_src, from_gamma, to_gamma); - } - from_src = to_src; - from_gamma = to_gamma; - } -} - -uint16_t ledGammaReverse_internal(uint16_t vg, const struct gamma_table_t *gt_ptr) { - uint16_t from_src = 0; - uint16_t from_gamma = 0; - - for (const gamma_table_t *gt = gt_ptr; ; gt++) { - uint16_t to_src = gt->to_src; - uint16_t to_gamma = gt->to_gamma; - if (vg <= to_gamma) { - return changeUIntScale(vg, from_gamma, to_gamma, from_src, to_src); - } - from_src = to_src; - from_gamma = to_gamma; - } -} - - -uint16_t ledGamma10_10(uint16_t v) { - return ledGamma_internal(v, gamma_table); -} - -uint16_t ledGamma10(uint8_t v) { - return ledGamma10_10(change8to10(v)); -} - - -uint8_t ledGamma(uint8_t v) { - return change10to8(ledGamma10(v)); -} - - - -void LightPwmOffset(uint32_t offset) -{ - Light.pwm_offset = offset; -} - -bool LightModuleInit(void) -{ - light_type = LT_BASIC; - - if (Settings.flag.pwm_control) { - for (uint32_t i = 0; i < MAX_PWMS; i++) { - if (pin[GPIO_PWM1 +i] < 99) { light_type++; } - } - } - - light_flg = 0; - if (XlgtCall(FUNC_MODULE_INIT)) { - - } -#ifdef ESP8266 - else if (SONOFF_BN == my_module_type) { - light_type = LT_PWM1; - } - else if (SONOFF_LED == my_module_type) { - if (!my_module.io[4]) { - pinMode(4, OUTPUT); - digitalWrite(4, LOW); - } - if (!my_module.io[5]) { - pinMode(5, OUTPUT); - digitalWrite(5, LOW); - } - if (!my_module.io[14]) { - pinMode(14, OUTPUT); - digitalWrite(14, LOW); - } - light_type = LT_PWM2; - } -#endif - - if (light_type > LT_BASIC) { - devices_present++; - } - - - if (Settings.flag3.pwm_multi_channels) { - uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7); - if (0 == pwm_channels) { pwm_channels = 1; } - devices_present += pwm_channels - 1; - } else if ((Settings.param[P_RGB_REMAP] & 128) && (LST_RGBW <= (light_type & 7))) { - - devices_present++; - } - - return (light_type > LT_BASIC); -} - - - -void LightCalcPWMRange(void) { - uint16_t pwm_min, pwm_max; - - pwm_min = change8to10(LightStateClass::DimmerToBri(Settings.dimmer_hw_min)); - pwm_max = change8to10(LightStateClass::DimmerToBri(Settings.dimmer_hw_max)); - if (Settings.light_correction) { - pwm_min = ledGamma10_10(pwm_min); - pwm_max = ledGamma10_10(pwm_max); - } - pwm_min = pwm_min > 0 ? changeUIntScale(pwm_min, 1, 1023, 1, Settings.pwm_range) : 0; - pwm_max = changeUIntScale(pwm_max, 1, 1023, 1, Settings.pwm_range); - - Light.pwm_min = pwm_min; - Light.pwm_max = pwm_max; - -} - -void LightInit(void) -{ - Light.device = devices_present; - Light.subtype = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7); - Light.pwm_multi_channels = Settings.flag3.pwm_multi_channels; - - if (LST_RGBW <= Light.subtype) { - - - bool ct_rgb_linked = !(Settings.param[P_RGB_REMAP] & 128); - light_controller.setCTRGBLinked(ct_rgb_linked); - } - - if ((LST_SINGLE <= Light.subtype) && Light.pwm_multi_channels) { - - light_controller.setPWMMultiChannel(true); - Light.device = devices_present - Light.subtype + 1; - } else if (!light_controller.isCTRGBLinked()) { - - Light.device--; - } - LightCalcPWMRange(); -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightInit Light.pwm_multi_channels=%d Light.subtype=%d Light.device=%d devices_present=%d", - Light.pwm_multi_channels, Light.subtype, Light.device, devices_present); -#endif - - light_controller.setSubType(Light.subtype); - light_controller.loadSettings(); - light_controller.setAlexaCTRange(Settings.flag4.alexa_ct_range); - light_controller.calcLevels(); - - if (LST_SINGLE == Light.subtype) { - Settings.light_color[0] = 255; - } - if (light_type < LT_PWM6) { - for (uint32_t i = 0; i < light_type; i++) { - Settings.pwm_value[i] = 0; - if (pin[GPIO_PWM1 +i] < 99) { - pinMode(pin[GPIO_PWM1 +i], OUTPUT); - } - } - if (pin[GPIO_ARIRFRCV] < 99) { - if (pin[GPIO_ARIRFSEL] < 99) { - pinMode(pin[GPIO_ARIRFSEL], OUTPUT); - digitalWrite(pin[GPIO_ARIRFSEL], 1); - } - } - } - - uint32_t max_scheme = Light.max_scheme; - if (Light.subtype < LST_RGB) { - max_scheme = LS_POWER; - } - if ((LS_WAKEUP == Settings.light_scheme) || (Settings.light_scheme > max_scheme)) { - Settings.light_scheme = LS_POWER; - } - Light.power = 0; - Light.update = true; - Light.wakeup_active = 0; - if (Settings.flag4.fade_at_startup) { - Light.fade_initialized = true; - } - - LightUpdateColorMapping(); -} - -void LightUpdateColorMapping(void) -{ - uint8_t param = Settings.param[P_RGB_REMAP] & 127; - if (param > 119){ param = 0; } - - uint8_t tmp[] = {0,1,2,3,4}; - Light.color_remap[0] = tmp[param / 24]; - for (uint32_t i = param / 24; i<4; ++i){ - tmp[i] = tmp[i+1]; - } - param = param % 24; - Light.color_remap[1] = tmp[(param / 6)]; - for (uint32_t i = param / 6; i<3; ++i){ - tmp[i] = tmp[i+1]; - } - param = param % 6; - Light.color_remap[2] = tmp[(param / 2)]; - for (uint32_t i = param / 2; i<2; ++i){ - tmp[i] = tmp[i+1]; - } - param = param % 2; - Light.color_remap[3] = tmp[param]; - Light.color_remap[4] = tmp[1-param]; - - Light.update = true; - -} - -uint8_t LightGetDimmer(uint8_t dimmer) { - return light_state.getDimmer(dimmer); -} - -void LightSetDimmer(uint8_t dimmer) { - light_controller.changeDimmer(dimmer); -} - -void LightGetHSB(uint16_t *hue, uint8_t *sat, uint8_t *bri) { - light_state.getHSB(hue, sat, bri); -} - -void LightHsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b) { - light_state.HsToRgb(hue, sat, r_r, r_g, r_b); -} - - -uint8_t LightGetBri(uint8_t device) { - uint8_t bri = 254; - if (Light.pwm_multi_channels) { - if ((device >= Light.device) && (device < Light.device + LST_MAX) && (device <= devices_present)) { - bri = Light.current_color[device - Light.device]; - } - } else if (light_controller.isCTRGBLinked()) { - if (device == Light.device) { - bri = light_state.getBri(); - } - } else { - if (device == Light.device) { - bri = light_state.getBriRGB(); - } else if (device == Light.device + 1) { - bri = light_state.getBriCT(); - } - } - return bri; -} - - -void LightSetBri(uint8_t device, uint8_t bri) { - if (Light.pwm_multi_channels) { - if ((device >= Light.device) && (device < Light.device + LST_MAX) && (device <= devices_present)) { - Light.current_color[device - Light.device] = bri; - light_controller.changeChannels(Light.current_color); - } - } else if (light_controller.isCTRGBLinked()) { - if (device == Light.device) { - light_controller.changeBri(bri); - } - } else { - if (device == Light.device) { - light_controller.changeBriRGB(bri); - } else if (device == Light.device + 1) { - light_controller.changeBriCT(bri); - } - } -} - -void LightSetColorTemp(uint16_t ct) -{ - - - - - - - if ((LST_COLDWARM != Light.subtype) && (LST_RGBCW != Light.subtype)) { - return; - } - light_controller.changeCTB(ct, light_state.getBriCT()); -} - -uint16_t LightGetColorTemp(void) -{ - - if ((LST_COLDWARM != Light.subtype) && (LST_RGBCW != Light.subtype)) { - return 0; - } - return (light_state.getColorMode() & LCM_CT) ? light_state.getCT() : 0; -} - -void LightSetSignal(uint16_t lo, uint16_t hi, uint16_t value) -{ - - - - if (Settings.flag.light_signal) { - uint16_t signal = changeUIntScale(value, lo, hi, 0, 255); - - light_controller.changeRGB(signal, 255 - signal, 0, true); - Settings.light_scheme = 0; -#ifdef USE_DEVICE_GROUPS - LightUpdateScheme(); -#endif - if (0 == light_state.getBri()) { - light_controller.changeBri(50); - } - } -} - - -char* LightGetColor(char* scolor, boolean force_hex = false) -{ - if ((0 == Settings.light_scheme) || (!Light.pwm_multi_channels)) { - light_controller.calcLevels(); - } - scolor[0] = '\0'; - for (uint32_t i = 0; i < Light.subtype; i++) { - if (!force_hex && Settings.flag.decimal_text) { - snprintf_P(scolor, LIGHT_COLOR_SIZE, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Light.current_color[i]); - } else { - snprintf_P(scolor, LIGHT_COLOR_SIZE, PSTR("%s%02X"), scolor, Light.current_color[i]); - } - } - return scolor; -} - -void LightPowerOn(void) -{ - if (light_state.getBri() && !(Light.power)) { - ExecuteCommandPower(Light.device, POWER_ON, SRC_LIGHT); - } -} - -void LightState(uint8_t append) -{ - char scolor[LIGHT_COLOR_SIZE]; - char scommand[33]; - bool unlinked = !light_controller.isCTRGBLinked() && (Light.subtype >= LST_RGBW); - - if (append) { - ResponseAppend_P(PSTR(",")); - } else { - Response_P(PSTR("{")); - } - if (!Light.pwm_multi_channels) { - if (unlinked) { - - ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d" - ",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"), - Light.device, GetStateText(Light.power & 1), Light.device, light_state.getDimmer(1), - Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), Light.device + 1, light_state.getDimmer(2)); - } else { - GetPowerDevice(scommand, Light.device, sizeof(scommand), Settings.flag.device_index_enable); - ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(Light.power & 1), - light_state.getDimmer()); - } - - - if (Light.subtype > LST_SINGLE) { - ResponseAppend_P(PSTR(",\"" D_CMND_COLOR "\":\"%s\""), LightGetColor(scolor)); - if (LST_RGB <= Light.subtype) { - uint16_t hue; - uint8_t sat, bri; - light_state.getHSB(&hue, &sat, &bri); - sat = changeUIntScale(sat, 0, 255, 0, 100); - bri = changeUIntScale(bri, 0, 255, 0, 100); - - ResponseAppend_P(PSTR(",\"" D_CMND_HSBCOLOR "\":\"%d,%d,%d\""), hue,sat,bri); - } - - if ((LST_COLDWARM == Light.subtype) || (LST_RGBW <= Light.subtype)) { - ResponseAppend_P(PSTR(",\"" D_CMND_WHITE "\":%d"), light_state.getDimmer(2)); - } - - if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) { - ResponseAppend_P(PSTR(",\"" D_CMND_COLORTEMPERATURE "\":%d"), light_state.getCT()); - } - - ResponseAppend_P(PSTR(",\"" D_CMND_CHANNEL "\":[" )); - for (uint32_t i = 0; i < Light.subtype; i++) { - uint8_t channel_raw = Light.current_color[i]; - uint8_t channel = changeUIntScale(channel_raw,0,255,0,100); - - if ((0 == channel) && (channel_raw > 0)) { channel = 1; } - ResponseAppend_P(PSTR("%s%d" ), (i > 0 ? "," : ""), channel); - } - ResponseAppend_P(PSTR("]")); - } - - if (append) { - if (Light.subtype >= LST_RGB) { - ResponseAppend_P(PSTR(",\"" D_CMND_SCHEME "\":%d"), Settings.light_scheme); - } - if (Light.max_scheme > LS_MAX) { - ResponseAppend_P(PSTR(",\"" D_CMND_WIDTH "\":%d"), Settings.light_width); - } - ResponseAppend_P(PSTR(",\"" D_CMND_FADE "\":\"%s\",\"" D_CMND_SPEED "\":%d,\"" D_CMND_LEDTABLE "\":\"%s\""), - GetStateText(Settings.light_fade), Settings.light_speed, GetStateText(Settings.light_correction)); - } - } else { - for (uint32_t i = 0; i < Light.subtype; i++) { - GetPowerDevice(scommand, Light.device + i, sizeof(scommand), 1); - uint32_t light_power_masked = Light.power & (1 << i); - light_power_masked = light_power_masked ? 1 : 0; - ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_CHANNEL "%d\":%d,"), scommand, GetStateText(light_power_masked), Light.device + i, - changeUIntScale(Light.current_color[i], 0, 255, 0, 100)); - } - ResponseAppend_P(PSTR("\"" D_CMND_COLOR "\":\"%s\""), LightGetColor(scolor)); - } - - if (!append) { - ResponseJsonEnd(); - } -} - -void LightPreparePower(power_t channels = 0xFFFFFFFF) { -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG, "LightPreparePower power=%d Light.power=%d", power, Light.power); -#endif - - if (Light.pwm_multi_channels) { - for (uint32_t i = 0; i < Light.subtype; i++) { - if (bitRead(channels, i)) { - - if ((Light.current_color[i]) && (!bitRead(Light.power, i))) { - if (!Settings.flag.not_power_linked) { - ExecuteCommandPower(Light.device + i, POWER_ON_NO_STATE, SRC_LIGHT); - } - } else { - - if ((0 == Light.current_color[i]) && bitRead(Light.power, i)) { - ExecuteCommandPower(Light.device + i, POWER_OFF_NO_STATE, SRC_LIGHT); - } - } - #ifdef USE_DOMOTICZ - DomoticzUpdatePowerState(Light.device + i); - #endif - } - } - } else { - if (light_controller.isCTRGBLinked()) { - if (light_state.getBri() && !(Light.power)) { - if (!Settings.flag.not_power_linked) { - ExecuteCommandPower(Light.device, POWER_ON_NO_STATE, SRC_LIGHT); - } - } else if (!light_state.getBri() && Light.power) { - ExecuteCommandPower(Light.device, POWER_OFF_NO_STATE, SRC_LIGHT); - } - } else { - - if (channels & 1) { - if (light_state.getBriRGB() && !(Light.power & 1)) { - if (!Settings.flag.not_power_linked) { - ExecuteCommandPower(Light.device, POWER_ON_NO_STATE, SRC_LIGHT); - } - } else if (!light_state.getBriRGB() && (Light.power & 1)) { - ExecuteCommandPower(Light.device, POWER_OFF_NO_STATE, SRC_LIGHT); - } - } - - if (channels & 2) { - if (light_state.getBriCT() && !(Light.power & 2)) { - if (!Settings.flag.not_power_linked) { - ExecuteCommandPower(Light.device + 1, POWER_ON_NO_STATE, SRC_LIGHT); - } - } else if (!light_state.getBriCT() && (Light.power & 2)) { - ExecuteCommandPower(Light.device + 1, POWER_OFF_NO_STATE, SRC_LIGHT); - } - } - } -#ifdef USE_DOMOTICZ - DomoticzUpdatePowerState(Light.device); -#endif - } - - if (Settings.flag3.hass_tele_on_power) { - MqttPublishTeleState(); - } - -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG, "LightPreparePower End power=%d Light.power=%d", power, Light.power); -#endif - Light.power = power >> (Light.device - 1); - LightState(0); -} - -#ifdef USE_LIGHT_PALETTE -void LightSetPaletteEntry(void) -{ - uint8_t bri = light_state.getBri(); - uint8_t * palette_entry = &Light.palette[Light.wheel * LST_MAX]; - for (int i = 0; i < LST_MAX; i++) { - Light.new_color[i] = changeUIntScale(palette_entry[i], 0, 255, 0, bri); - } - light_state.setChannelsRaw(Light.new_color); - if (!Light.pwm_multi_channels) { - light_state.setCW(Light.new_color[3], Light.new_color[4], true); - if (Light.new_color[0] || Light.new_color[1] || Light.new_color[2]) light_state.addRGBMode(); - } -} -#endif - -void LightCycleColor(int8_t direction) -{ - - if (Settings.light_speed > 3) { - if (Light.strip_timer_counter % (Settings.light_speed - 2)) { return; } - } - -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count) { - if (0 == direction) { - Light.wheel = random(Light.palette_count); - } - else { - Light.wheel += direction; - if (Light.wheel >= Light.palette_count) { - Light.wheel = 0; - if (direction < 0) Light.wheel = Light.palette_count - 1; - } - } - LightSetPaletteEntry(); - return; - } -#endif - - if (0 == direction) { - if (Light.random == Light.wheel) { - Light.random = random(255); - - uint8_t my_dir = (Light.random < Light.wheel -128) ? 1 : - (Light.random < Light.wheel ) ? 0 : - (Light.random > Light.wheel +128) ? 0 : 1; - Light.random = (Light.random & 0xFE) | my_dir; - - - } - - direction = (Light.random &0x01) ? 1 : -1; - } - - - if (Settings.light_speed < 3) { direction *= (4 - Settings.light_speed); } - Light.wheel += direction; - uint16_t hue = changeUIntScale(Light.wheel, 0, 255, 0, 359); - - - - if (!Light.pwm_multi_channels) { - uint8_t sat; - light_state.getHSB(nullptr, &sat, nullptr); - light_state.setHS(hue, sat); - } else { - light_state.setHS(hue, 255); - light_state.setBri(255); - } - light_controller.calcLevels(Light.new_color); -} - -void LightSetPower(void) -{ - - Light.old_power = Light.power; - - uint32_t mask = 1; - if (Light.pwm_multi_channels) { - mask = (1 << Light.subtype) - 1; - } else if (!light_controller.isCTRGBLinked()) { - mask = 3; - } - uint32_t shift = Light.device - 1; - - - - - - Light.power = (XdrvMailbox.index & (mask << shift)) >> shift; - if (Light.wakeup_active) { - Light.wakeup_active--; - } -#ifdef DEBUG_LIGHT - AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightSetPower XdrvMailbox.index=%d Light.old_power=%d Light.power=%d mask=%d shift=%d", - XdrvMailbox.index, Light.old_power, Light.power, mask, shift); -#endif - if (Light.power != Light.old_power) { - Light.update = true; - } - LightAnimate(); -} - - - - -void LightAnimate(void) -{ - uint16_t light_still_on = 0; - bool power_off = false; - - - light_controller.setAlexaCTRange(Settings.flag4.alexa_ct_range); - Light.strip_timer_counter++; - - - - if (Light.power || Light.fade_running) { - if (Settings.sleep > PWM_MAX_SLEEP) { - ssleep = PWM_MAX_SLEEP; - } else { - ssleep = Settings.sleep; - } - } else { - ssleep = Settings.sleep; - } - - if (!Light.power) { - Light.strip_timer_counter = 0; - if (Settings.light_scheme >= LS_MAX) { - power_off = true; - } - } else { - switch (Settings.light_scheme) { - case LS_POWER: - light_controller.calcLevels(Light.new_color); - break; - case LS_WAKEUP: - if (2 == Light.wakeup_active) { - Light.wakeup_active = 1; - for (uint32_t i = 0; i < Light.subtype; i++) { - Light.new_color[i] = 0; - } - Light.wakeup_counter = 0; - Light.wakeup_dimmer = 0; - } - Light.wakeup_counter++; - if (Light.wakeup_counter > ((Settings.light_wakeup * STATES) / Settings.light_dimmer)) { - Light.wakeup_counter = 0; - Light.wakeup_dimmer++; - if (Light.wakeup_dimmer <= Settings.light_dimmer) { - light_state.setDimmer(Light.wakeup_dimmer); - light_controller.calcLevels(); - for (uint32_t i = 0; i < Light.subtype; i++) { - Light.new_color[i] = Light.current_color[i]; - } - } else { - - - - - Response_P(PSTR("{\"" D_CMND_WAKEUP "\":\"" D_JSON_DONE "\"")); - LightState(1); - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_WAKEUP)); - XdrvRulesProcess(); - - Light.wakeup_active = 0; - Settings.light_scheme = LS_POWER; -#ifdef USE_DEVICE_GROUPS - LightUpdateScheme(); -#endif - } - } - break; - case LS_CYCLEUP: - case LS_CYCLEDN: - case LS_RANDOM: - if (LS_CYCLEUP == Settings.light_scheme) { - LightCycleColor(1); - } else if (LS_CYCLEDN == Settings.light_scheme) { - LightCycleColor(-1); - } else { - LightCycleColor(0); - } - if (Light.pwm_multi_channels) { - Light.new_color[0] = changeUIntScale(Light.new_color[0], 0, 255, 0, Settings.light_color[0]); - Light.new_color[1] = changeUIntScale(Light.new_color[1], 0, 255, 0, Settings.light_color[1]); - Light.new_color[2] = changeUIntScale(Light.new_color[2], 0, 255, 0, Settings.light_color[2]); - } - break; - default: - XlgtCall(FUNC_SET_SCHEME); - } - } - - if ((Settings.light_scheme < LS_MAX) || power_off) { - - - LightApplyPower(Light.new_color, Light.power); - - - - - - - - if (memcmp(Light.last_color, Light.new_color, Light.subtype)) { - Light.update = true; - } - if (Light.update) { -#ifdef USE_DEVICE_GROUPS - if (Light.power) LightSendDeviceGroupStatus(false); -#endif - - uint16_t cur_col_10[LST_MAX]; - Light.update = false; - - - for (uint32_t i = 0; i < LST_MAX; i++) { - Light.last_color[i] = Light.new_color[i]; - - cur_col_10[i] = change8to10(Light.new_color[i]); - } - - if (Light.pwm_multi_channels) { - calcGammaMultiChannels(cur_col_10); - } else { - calcGammaBulbs(cur_col_10); - - - - if ((LST_RGBW <= Light.subtype) && (0 == Settings.rgbwwTable[4]) && (0 == cur_col_10[3]+cur_col_10[4])) { - uint32_t min_rgb_10 = min3(cur_col_10[0], cur_col_10[1], cur_col_10[2]); - for (uint32_t i=0; i<3; i++) { - - uint32_t adjust10 = change8to10(Settings.rgbwwTable[i]); - cur_col_10[i] = changeUIntScale(cur_col_10[i] - min_rgb_10, 0, 1023, 0, adjust10); - } - - - uint32_t adjust_w_10 = changeUIntScale(Settings.rgbwwTable[3], 0, 255, 0, 1023); - uint32_t white_10 = changeUIntScale(min_rgb_10, 0, 1023, 0, adjust_w_10); - if (LST_RGBW == Light.subtype) { - - cur_col_10[3] = white_10; - } else { - - uint32_t ct = light_state.getCT10bits(); - cur_col_10[4] = changeUIntScale(ct, 0, 1023, 0, white_10); - cur_col_10[3] = white_10 - cur_col_10[4]; - } - } - } - - - if (0 != Settings.rgbwwTable[4]) { - for (uint32_t i = 0; i 0) ? changeUIntScale(cur_col_10[i], 1, 1023, 1, Settings.pwm_range) : 0; - } - - - uint16_t orig_col_10bits[LST_MAX]; - memcpy(orig_col_10bits, cur_col_10, sizeof(orig_col_10bits)); - for (uint32_t i = 0; i < LST_MAX; i++) { - cur_col_10[i] = orig_col_10bits[Light.color_remap[i]]; - } - - if (!Settings.light_fade || skip_light_fade || power_off || (!Light.fade_initialized)) { - - memcpy(Light.fade_start_10, cur_col_10, sizeof(Light.fade_start_10)); - - LightSetOutputs(cur_col_10); - Light.fade_initialized = true; - } else { - if (Light.fade_running) { - - memcpy(Light.fade_start_10, Light.fade_cur_10, sizeof(Light.fade_start_10)); - } - memcpy(Light.fade_end_10, cur_col_10, sizeof(Light.fade_start_10)); - Light.fade_running = true; - Light.fade_duration = 0; - Light.fade_start = 0; - - } - } - if (Light.fade_running) { - if (LightApplyFade()) { - - - - LightSetOutputs(Light.fade_cur_10); - } - } -#ifdef USE_PWM_DIMMER - - if (PWM_DIMMER == my_module_type && !Light.power && !Light.fade_running) PWMDimmerSetPower(); -#endif - } -} - -bool isChannelGammaCorrected(uint32_t channel) { - if (!Settings.light_correction) { return false; } - if (channel >= Light.subtype) { return false; } -#ifdef ESP8266 - if (PHILIPS == my_module_type) { - if ((LST_COLDWARM == Light.subtype) && (1 == channel)) { return false; } - if ((LST_RGBCW == Light.subtype) && (4 == channel)) { return false; } - } -#endif - return true; -} - - -bool isChannelCT(uint32_t channel) { -#ifdef ESP8266 - if (PHILIPS == my_module_type) { - if ((LST_COLDWARM == Light.subtype) && (1 == channel)) { return true; } - if ((LST_RGBCW == Light.subtype) && (4 == channel)) { return true; } - } -#endif - return false; -} - - -uint16_t fadeGamma(uint32_t channel, uint16_t v) { - if (isChannelGammaCorrected(channel)) { - return ledGamma_internal(v, gamma_table_fast); - } else { - return v; - } -} -uint16_t fadeGammaReverse(uint32_t channel, uint16_t vg) { - if (isChannelGammaCorrected(channel)) { - return ledGammaReverse_internal(vg, gamma_table_fast); - } else { - return vg; - } -} - -bool LightApplyFade(void) { - static uint32_t last_millis = 0; - uint32_t now = millis(); - - if ((now - last_millis) <= 5) { - return false; - } - last_millis = now; - - - if (0 == Light.fade_duration) { - Light.fade_start = now; - - uint32_t distance = 0; - for (uint32_t i = 0; i < Light.subtype; i++) { - int32_t channel_distance = fadeGammaReverse(i, Light.fade_end_10[i]) - fadeGammaReverse(i, Light.fade_start_10[i]); - if (channel_distance < 0) { channel_distance = - channel_distance; } - if (channel_distance > distance) { distance = channel_distance; } - } - if (distance > 0) { - - - - Light.fade_duration = (distance * Settings.light_speed * 500) / 1023; - if (Settings.save_data) { - - uint32_t delay_seconds = 1 + (Light.fade_duration + 999) / 1000; - - if (save_data_counter < delay_seconds) { - save_data_counter = delay_seconds; - } - } - } else { - - Light.fade_running = false; - } - } - - uint16_t fade_current = now - Light.fade_start; - if (fade_current <= Light.fade_duration) { - - for (uint32_t i = 0; i < Light.subtype; i++) { - Light.fade_cur_10[i] = fadeGamma(i, - changeUIntScale(fadeGammaReverse(i, fade_current), - 0, Light.fade_duration, - fadeGammaReverse(i, Light.fade_start_10[i]), - fadeGammaReverse(i, Light.fade_end_10[i]))); - - - - } - } else { - - - Light.fade_running = false; - Light.fade_start = 0; - Light.fade_duration = 0; - - memcpy(Light.fade_cur_10, Light.fade_end_10, sizeof(Light.fade_end_10)); - - memcpy(Light.fade_start_10, Light.fade_end_10, sizeof(Light.fade_start_10)); - } - return true; -} - - - -void LightApplyPower(uint8_t new_color[LST_MAX], power_t power) { - - if (Light.pwm_multi_channels) { - - for (uint32_t i = 0; i < LST_MAX; i++) { - if (0 == bitRead(power,i)) { - new_color[i] = 0; - } - } - - - - - - } else { - if (!light_controller.isCTRGBLinked()) { - - if (0 == (power & 1)) { - new_color[0] = new_color[1] = new_color[2] = 0; - } - if (0 == (power & 2)) { - new_color[3] = new_color[4] = 0; - } - } else if (!power) { - for (uint32_t i = 0; i < LST_MAX; i++) { - new_color[i] = 0; - } - } - } -} - -void LightSetOutputs(const uint16_t *cur_col_10) { - - if (light_type < LT_PWM6) { - for (uint32_t i = 0; i < (Light.subtype - Light.pwm_offset); i++) { - if (pin[GPIO_PWM1 +i] < 99) { - - uint16_t cur_col = cur_col_10[i + Light.pwm_offset]; - if (!isChannelCT(i)) { - cur_col = cur_col > 0 ? changeUIntScale(cur_col, 0, Settings.pwm_range, Light.pwm_min, Light.pwm_max) : 0; - } - analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col : cur_col); - } - } - } - - - - - uint8_t cur_col[LST_MAX]; - for (uint32_t i = 0; i < LST_MAX; i++) { - cur_col[i] = change10to8(cur_col_10[i]); - } - - - uint8_t scale_col[3]; - uint32_t max = (cur_col[0] > cur_col[1] && cur_col[0] > cur_col[2]) ? cur_col[0] : (cur_col[1] > cur_col[2]) ? cur_col[1] : cur_col[2]; - for (uint32_t i = 0; i < 3; i++) { - scale_col[i] = (0 == max) ? 255 : (255 > max) ? changeUIntScale(cur_col[i], 0, max, 0, 255) : cur_col[i]; - } - - char *tmp_data = XdrvMailbox.data; - char *tmp_topic = XdrvMailbox.topic; - XdrvMailbox.data = (char*)cur_col; - XdrvMailbox.topic = (char*)scale_col; - if (XlgtCall(FUNC_SET_CHANNELS)) { } - else if (XdrvCall(FUNC_SET_CHANNELS)) { } - XdrvMailbox.data = tmp_data; - XdrvMailbox.topic = tmp_topic; -} - - -void calcGammaMultiChannels(uint16_t cur_col_10[5]) { - - if (Settings.light_correction) { - for (uint32_t i = 0; i < LST_MAX; i++) { - cur_col_10[i] = ledGamma10_10(cur_col_10[i]); - } - } -} - -void calcGammaBulbs(uint16_t cur_col_10[5]) { - - - - if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) { - - uint32_t cw1 = Light.subtype - 1; - uint32_t cw0 = Light.subtype - 2; - uint16_t white_bri10 = cur_col_10[cw0] + cur_col_10[cw1]; - uint16_t white_bri10_1023 = (white_bri10 > 1023) ? 1023 : white_bri10; - -#ifdef ESP8266 - if (PHILIPS == my_module_type) { - - cur_col_10[cw1] = light_state.getCT10bits(); - - if (Settings.light_correction) { - cur_col_10[cw0] = ledGamma10_10(white_bri10_1023); - } else { - cur_col_10[cw0] = white_bri10_1023; - } - } else -#endif - if (Settings.light_correction) { - - if (white_bri10 <= 1031) { - - uint16_t white_bri_gamma10 = ledGamma10_10(white_bri10_1023); - - cur_col_10[cw0] = changeUIntScale(cur_col_10[cw0], 0, white_bri10_1023, 0, white_bri_gamma10); - cur_col_10[cw1] = changeUIntScale(cur_col_10[cw1], 0, white_bri10_1023, 0, white_bri_gamma10); - } else { - cur_col_10[cw0] = ledGamma10_10(cur_col_10[cw0]); - cur_col_10[cw1] = ledGamma10_10(cur_col_10[cw1]); - } - } - } - - if (Settings.light_correction) { - - if (LST_RGB <= Light.subtype) { - for (uint32_t i = 0; i < 3; i++) { - cur_col_10[i] = ledGamma10_10(cur_col_10[i]); - } - } - - if ((LST_SINGLE == Light.subtype) || (LST_RGBW == Light.subtype)) { - cur_col_10[Light.subtype - 1] = ledGamma10_10(cur_col_10[Light.subtype - 1]); - } - } -} - -#ifdef USE_DEVICE_GROUPS -void LightSendDeviceGroupStatus(bool force) -{ - static uint8_t last_channels[LST_MAX]; - static uint8_t last_bri; - - uint8_t bri = light_state.getBri(); - bool send_bri_update = (force || bri != last_bri); - - if (Light.subtype > LST_SINGLE && !Light.devgrp_no_channels_out) { - uint8_t channels[LST_MAX]; - light_state.getChannels(channels); - if (force || memcmp(last_channels, channels, LST_MAX)) { - memcpy(last_channels, channels, LST_MAX); - SendLocalDeviceGroupMessage((send_bri_update ? DGR_MSGTYP_PARTIAL_UPDATE : DGR_MSGTYP_UPDATE), DGR_ITEM_LIGHT_CHANNELS, channels); - } - } - if (send_bri_update) { - last_bri = bri; - SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_LIGHT_BRI, light_state.getBri()); - } -} - -void LightHandleDevGroupItem(void) -{ - static bool send_state = false; - static bool restore_power = false; - bool more_to_come; - uint32_t value = XdrvMailbox.payload; -#ifdef USE_PWM_DIMMER_REMOTE - if (*XdrvMailbox.topic) return; -#endif - switch (XdrvMailbox.command_code) { - case DGR_ITEM_EOL: - more_to_come = (XdrvMailbox.index & DGR_FLAG_MORE_TO_COME); - if (restore_power && !more_to_come) { - restore_power = false; - Light.power = Light.old_power; - } - - LightAnimate(); - - if (send_state && !more_to_come) { - light_controller.saveSettings(); - if (Settings.flag3.hass_tele_on_power) { - MqttPublishTeleState(); - } - send_state = false; - } - break; - case DGR_ITEM_LIGHT_BRI: - if (light_state.getBri() != value) { - light_state.setBri(value); - send_state = true; - } - break; - case DGR_ITEM_LIGHT_SCHEME: - if (Settings.light_scheme != value) { - Settings.light_scheme = value; - Light.devgrp_no_channels_out = (value != 0); - send_state = true; - } - break; - case DGR_ITEM_LIGHT_CHANNELS: - light_controller.changeChannels((uint8_t *)XdrvMailbox.data); - send_state = true; - break; - case DGR_ITEM_LIGHT_FIXED_COLOR: - if (Light.subtype >= LST_RGBW) { - send_state = true; -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count) { - Light.wheel = value % Light.palette_count; - LightSetPaletteEntry(); - break; - } -#endif - value = value % MAX_FIXED_COLOR; - if (value) { - bool save_decimal_text = Settings.flag.decimal_text; - char str[16]; - LightColorEntry(str, sprintf_P(str, PSTR("%u"), value)); - Settings.flag.decimal_text = save_decimal_text; - uint32_t old_bri = light_state.getBri(); - light_controller.changeChannels(Light.entry_color); - light_controller.changeBri(old_bri); - Settings.light_scheme = 0; - Light.devgrp_no_channels_out = false; - } - else { - light_state.setColorMode(LCM_CT); - } - if (!restore_power && !Light.power) { - Light.old_power = Light.power; - Light.power = 0xff; - restore_power = true; - } - } - break; - case DGR_ITEM_LIGHT_FADE: - if (Settings.light_fade != value) { - Settings.light_fade = value; - send_state = true; - } - break; - case DGR_ITEM_LIGHT_SPEED: - if (Settings.light_speed != value && value > 0 && value <= 40) { - Settings.light_speed = value; - send_state = true; - } - break; - case DGR_ITEM_STATUS: - SendLocalDeviceGroupMessage(DGR_MSGTYP_PARTIAL_UPDATE, DGR_ITEM_LIGHT_FADE, Settings.light_fade, - DGR_ITEM_LIGHT_SPEED, Settings.light_speed, DGR_ITEM_LIGHT_SCHEME, Settings.light_scheme); - LightSendDeviceGroupStatus(true); - break; - } -} - -void LightUpdateScheme(void) -{ - static uint8_t last_scheme; - - if (Settings.light_scheme != last_scheme) { - last_scheme = Settings.light_scheme; - SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_LIGHT_SCHEME, Settings.light_scheme); - } - Light.devgrp_no_channels_out = false; -} -#endif - - - - - -bool LightColorEntry(char *buffer, uint32_t buffer_length) -{ - char scolor[10]; - char *p; - char *str; - uint32_t entry_type = 0; - uint8_t value = Light.fixed_color_index; -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count) value = Light.wheel; -#endif - - if (buffer[0] == '#') { - buffer++; - buffer_length--; - } - - if (Light.subtype >= LST_RGB) { - char option = (1 == buffer_length) ? buffer[0] : '\0'; - if ('+' == option) { -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count || Light.fixed_color_index < MAX_FIXED_COLOR) { -#else - if (Light.fixed_color_index < MAX_FIXED_COLOR) { -#endif - value++; - } - } - else if ('-' == option) { -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count || Light.fixed_color_index > 1) { -#else - if (Light.fixed_color_index > 1) { -#endif - value--; - } - } else { - value = atoi(buffer); -#ifdef USE_LIGHT_PALETTE - value--; -#endif - } -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count) value = value % Light.palette_count; -#endif - } - - memset(&Light.entry_color, 0x00, sizeof(Light.entry_color)); - - while ((buffer_length > 0) && ('=' == buffer[buffer_length - 1])) { - buffer_length--; - memcpy(&Light.entry_color, &Light.current_color, sizeof(Light.entry_color)); - } - if (strstr(buffer, ",") != nullptr) { - int8_t i = 0; - for (str = strtok_r(buffer, ",", &p); str && i < 6; str = strtok_r(nullptr, ",", &p)) { - if (i < LST_MAX) { - Light.entry_color[i++] = atoi(str); - } - } - entry_type = 2; - } - else if (((2 * Light.subtype) == buffer_length) || (buffer_length > 3)) { - for (uint32_t i = 0; i < tmin((uint)(buffer_length / 2), sizeof(Light.entry_color)); i++) { - strlcpy(scolor, buffer + (i *2), 3); - Light.entry_color[i] = (uint8_t)strtol(scolor, &p, 16); - } - entry_type = 1; - } -#ifdef USE_LIGHT_PALETTE - else if (Light.palette_count) { - Light.wheel = value; - memcpy_P(&Light.entry_color, &Light.palette[value * LST_MAX], LST_MAX); - entry_type = 1; - } -#endif - else if ((Light.subtype >= LST_RGB) && (value > 0) && (value <= MAX_FIXED_COLOR)) { - Light.fixed_color_index = value; - memcpy_P(&Light.entry_color, &kFixedColor[value -1], 3); - entry_type = 1; - } - else if ((value > 199) && (value <= 199 + MAX_FIXED_COLD_WARM)) { - if (LST_RGBW == Light.subtype) { - memcpy_P(&Light.entry_color[3], &kFixedWhite[value -200], 1); - entry_type = 1; - } - else if (LST_COLDWARM == Light.subtype) { - memcpy_P(&Light.entry_color, &kFixedColdWarm[value -200], 2); - entry_type = 1; - } - else if (LST_RGBCW == Light.subtype) { - memcpy_P(&Light.entry_color[3], &kFixedColdWarm[value -200], 2); - entry_type = 1; - } - } - if (entry_type) { - Settings.flag.decimal_text = entry_type -1; - } - return (entry_type); -} - - - -void CmndSupportColor(void) -{ - bool valid_entry = false; - bool coldim = false; - - if (XdrvMailbox.data_len > 0) { - valid_entry = LightColorEntry(XdrvMailbox.data, XdrvMailbox.data_len); - if (valid_entry) { - if (XdrvMailbox.index <= 2) { -#ifdef USE_LIGHT_PALETTE - if (Light.palette_count && XdrvMailbox.index == 2) { - LightSetPaletteEntry(); - } - else { -#endif - uint32_t old_bri = light_state.getBri(); - - light_controller.changeChannels(Light.entry_color); - if (2 == XdrvMailbox.index) { - - light_controller.changeBri(old_bri); - } -#ifdef USE_LIGHT_PALETTE - } -#endif - Settings.light_scheme = 0; -#ifdef USE_DEVICE_GROUPS - LightUpdateScheme(); -#endif - coldim = true; - } else { - for (uint32_t i = 0; i < LST_RGB; i++) { - Settings.ws_color[XdrvMailbox.index -3][i] = Light.entry_color[i]; - } - } - } - } - char scolor[LIGHT_COLOR_SIZE]; - if (!valid_entry && (XdrvMailbox.index <= 2)) { - ResponseCmndChar(LightGetColor(scolor)); - } - if (XdrvMailbox.index >= 3) { - scolor[0] = '\0'; - for (uint32_t i = 0; i < LST_RGB; i++) { - if (Settings.flag.decimal_text) { - snprintf_P(scolor, sizeof(scolor), PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.ws_color[XdrvMailbox.index -3][i]); - } else { - snprintf_P(scolor, sizeof(scolor), PSTR("%s%02X"), scolor, Settings.ws_color[XdrvMailbox.index -3][i]); - } - } - ResponseCmndIdxChar(scolor); - } - if (coldim) { - LightPreparePower(); - } -} - -void CmndColor(void) -{ - - - - - - - - if ((Light.subtype > LST_SINGLE) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) { - CmndSupportColor(); - } -} - -void CmndWhite(void) -{ - - - if (Light.pwm_multi_channels) { return; } - if ( ((Light.subtype >= LST_RGBW) || (LST_COLDWARM == Light.subtype)) && (XdrvMailbox.index == 1)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - light_controller.changeDimmer(XdrvMailbox.payload, 2); - LightPreparePower(2); - } else { - ResponseCmndNumber(light_state.getDimmer(2)); - } - } -} - -void CmndChannel(void) -{ - - - - - if ((XdrvMailbox.index >= Light.device) && (XdrvMailbox.index < Light.device + Light.subtype )) { - uint32_t light_index = XdrvMailbox.index - Light.device; - power_t coldim = 0; - - - if (1 == XdrvMailbox.data_len) { - uint8_t channel = changeUIntScale(Light.current_color[light_index],0,255,0,100); - if ('+' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (channel > 89) ? 100 : channel + 10; - } else if ('-' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (channel < 11) ? 1 : channel - 10; - } - } - - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - Light.current_color[light_index] = changeUIntScale(XdrvMailbox.payload,0,100,0,255); - if (Light.pwm_multi_channels) { - coldim = 1 << light_index; - } else { - if (light_controller.isCTRGBLinked()) { - - if ((light_index < 3) && (light_controller.isCTRGBLinked())) { - Light.current_color[3] = Light.current_color[4] = 0; - } else { - Light.current_color[0] = Light.current_color[1] = Light.current_color[2] = 0; - } - coldim = 1; - } else { - if (light_index < 3) { coldim = 1; } - else { coldim = 2; } - } - } - light_controller.changeChannels(Light.current_color); - } - ResponseCmndIdxNumber(changeUIntScale(Light.current_color[light_index],0,255,0,100)); - if (coldim) { - LightPreparePower(coldim); - } - } -} - -void CmndHsbColor(void) -{ - - - - - - - - if (Light.subtype >= LST_RGB) { - if (XdrvMailbox.data_len > 0) { - uint16_t c_hue; - uint8_t c_sat; - light_state.getHSB(&c_hue, &c_sat, nullptr); - uint32_t HSB[3]; - HSB[0] = c_hue; - HSB[1] = c_sat; - HSB[2] = light_state.getBriRGB(); - if ((2 == XdrvMailbox.index) || (3 == XdrvMailbox.index)) { - if ((uint32_t)XdrvMailbox.payload > 100) { XdrvMailbox.payload = 100; } - HSB[XdrvMailbox.index-1] = changeUIntScale(XdrvMailbox.payload, 0, 100, 0, 255); - } else { - uint32_t paramcount = ParseParameters(3, HSB); - if (HSB[0] > 360) { HSB[0] = 360; } - for (uint32_t i = 1; i < paramcount; i++) { - if (HSB[i] > 100) { HSB[i] == 100; } - HSB[i] = changeUIntScale(HSB[i], 0, 100, 0, 255); - } - } - light_controller.changeHSB(HSB[0], HSB[1], HSB[2]); - LightPreparePower(1); - } else { - LightState(0); - } - } -} - -void CmndScheme(void) -{ - - - - - - if (Light.subtype >= LST_RGB) { - uint32_t max_scheme = Light.max_scheme; - - if (1 == XdrvMailbox.data_len) { - if (('+' == XdrvMailbox.data[0]) && (Settings.light_scheme < max_scheme)) { - XdrvMailbox.payload = Settings.light_scheme + ((0 == Settings.light_scheme) ? 2 : 1); - } - else if (('-' == XdrvMailbox.data[0]) && (Settings.light_scheme > 0)) { - XdrvMailbox.payload = Settings.light_scheme - ((2 == Settings.light_scheme) ? 2 : 1); - } - } - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= max_scheme)) { - uint32_t parm[2]; - if (ParseParameters(2, parm) > 1) { - Light.wheel = parm[1]; -#ifdef USE_LIGHT_PALETTE - Light.wheel--; -#endif - } - Settings.light_scheme = XdrvMailbox.payload; -#ifdef USE_DEVICE_GROUPS - LightUpdateScheme(); -#endif - if (LS_WAKEUP == Settings.light_scheme) { - Light.wakeup_active = 3; - } - LightPowerOn(); - Light.strip_timer_counter = 0; - - if (Settings.flag3.hass_tele_on_power) { - MqttPublishTeleState(); - } - } - ResponseCmndNumber(Settings.light_scheme); - } -} - -void CmndWakeup(void) -{ - - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - light_controller.changeDimmer(XdrvMailbox.payload); - } - Light.wakeup_active = 3; - Settings.light_scheme = LS_WAKEUP; -#ifdef USE_DEVICE_GROUPS - LightUpdateScheme(); -#endif - LightPowerOn(); - ResponseCmndChar(D_JSON_STARTED); -} - -void CmndColorTemperature(void) -{ - - - - - if (Light.pwm_multi_channels) { return; } - if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) { - uint32_t ct = light_state.getCT(); - if (1 == XdrvMailbox.data_len) { - if ('+' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (ct > (CT_MAX-34)) ? CT_MAX : ct + 34; - } - else if ('-' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (ct < (CT_MIN+34)) ? CT_MIN : ct - 34; - } - } - if ((XdrvMailbox.payload >= CT_MIN) && (XdrvMailbox.payload <= CT_MAX)) { - light_controller.changeCTB(XdrvMailbox.payload, light_state.getBriCT()); - LightPreparePower(2); - } else { - ResponseCmndNumber(ct); - } - } -} - -void CmndDimmer(void) -{ - - - - - - - - uint32_t dimmer; - if (XdrvMailbox.index == 3) { - skip_light_fade = true; - XdrvMailbox.index = 0; - } - else if (XdrvMailbox.index > 2) { - XdrvMailbox.index = 1; - } - - if ((light_controller.isCTRGBLinked()) || (0 == XdrvMailbox.index)) { - dimmer = light_state.getDimmer(); - } else { - dimmer = light_state.getDimmer(XdrvMailbox.index); - } - - if (1 == XdrvMailbox.data_len) { - if ('+' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (dimmer > 89) ? 100 : dimmer + 10; - } else if ('-' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (dimmer < 11) ? 1 : dimmer - 10; - } - } - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - if (light_controller.isCTRGBLinked()) { - - light_controller.changeDimmer(XdrvMailbox.payload); - LightPreparePower(); - } else { - if (0 != XdrvMailbox.index) { - light_controller.changeDimmer(XdrvMailbox.payload, XdrvMailbox.index); - LightPreparePower(1 << (XdrvMailbox.index - 1)); - } else { - - light_controller.changeDimmer(XdrvMailbox.payload, 1); - light_controller.changeDimmer(XdrvMailbox.payload, 2); - LightPreparePower(); - } - } -#if defined(USE_PWM_DIMMER) && defined(USE_DEVICE_GROUPS) - Settings.bri_power_on = light_state.getBri();; - SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_BRI_POWER_ON, Settings.bri_power_on); -#endif - Light.update = true; - if (skip_light_fade) LightAnimate(); - } else { - ResponseCmndNumber(dimmer); - } - skip_light_fade = false; -} - -void CmndDimmerRange(void) -{ - - - if (XdrvMailbox.data_len > 0) { - uint32_t parm[2]; - parm[0] = Settings.dimmer_hw_min; - parm[1] = Settings.dimmer_hw_max; - ParseParameters(2, parm); - if (parm[0] < parm[1]) { - Settings.dimmer_hw_min = parm[0]; - Settings.dimmer_hw_max = parm[1]; - } else { - Settings.dimmer_hw_min = parm[1]; - Settings.dimmer_hw_max = parm[0]; - } - LightCalcPWMRange(); - Light.update = true; - } - Response_P(PSTR("{\"" D_CMND_DIMMER_RANGE "\":{\"Min\":%d,\"Max\":%d}}"), Settings.dimmer_hw_min, Settings.dimmer_hw_max); -} - -void CmndLedTable(void) -{ - - - - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { - switch (XdrvMailbox.payload) { - case 0: - case 1: - Settings.light_correction = XdrvMailbox.payload; - break; - case 2: - Settings.light_correction ^= 1; - break; - } - LightCalcPWMRange(); - Light.update = true; - } - ResponseCmndStateText(Settings.light_correction); -} - -void CmndRgbwwTable(void) -{ - - - if ((XdrvMailbox.data_len > 0)) { - uint32_t parm[LST_RGBCW -1]; - uint32_t parmcount = ParseParameters(LST_RGBCW, parm); - for (uint32_t i = 0; i < parmcount; i++) { - Settings.rgbwwTable[i] = parm[i]; - } - Light.update = true; - } - char scolor[LIGHT_COLOR_SIZE]; - scolor[0] = '\0'; - for (uint32_t i = 0; i < LST_RGBCW; i++) { - snprintf_P(scolor, sizeof(scolor), PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.rgbwwTable[i]); - } - ResponseCmndChar(scolor); -} - -void CmndFade(void) -{ - - - - - switch (XdrvMailbox.payload) { - case 0: - case 1: - Settings.light_fade = XdrvMailbox.payload; - break; - case 2: - Settings.light_fade ^= 1; - break; - } -#ifdef USE_DEVICE_GROUPS - if (XdrvMailbox.payload >= 0 && XdrvMailbox.payload <= 2) SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_LIGHT_FADE, Settings.light_fade); -#endif -#ifdef USE_LIGHT - if (!Settings.light_fade) { Light.fade_running = false; } -#endif - ResponseCmndStateText(Settings.light_fade); -} - -void CmndSpeed(void) -{ - - - - - if (1 == XdrvMailbox.data_len) { - if (('+' == XdrvMailbox.data[0]) && (Settings.light_speed > 1)) { - XdrvMailbox.payload = Settings.light_speed - 1; - } - else if (('-' == XdrvMailbox.data[0]) && (Settings.light_speed < 40)) { - XdrvMailbox.payload = Settings.light_speed + 1; - } - } - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 40)) { - Settings.light_speed = XdrvMailbox.payload; -#ifdef USE_DEVICE_GROUPS - SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_LIGHT_SPEED, Settings.light_speed); -#endif - } - ResponseCmndNumber(Settings.light_speed); -} - -void CmndWakeupDuration(void) -{ - - - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3001)) { - Settings.light_wakeup = XdrvMailbox.payload; - Light.wakeup_active = 0; - } - ResponseCmndNumber(Settings.light_wakeup); -} - -#ifdef USE_LIGHT_PALETTE -void CmndPalette(void) -{ - uint8_t * palette_entry; - char * p; - - - if (XdrvMailbox.data_len) { - Light.wheel = 0; - Light.palette_count = 0; - if (Light.palette) { - free(Light.palette); - Light.palette = nullptr; - } - if (XdrvMailbox.data_len > 1 || XdrvMailbox.data[0] != '0') { - uint8_t palette_count = 0; - char * color = XdrvMailbox.data; - if (!(Light.palette = (uint8_t *)malloc(255 * Light.subtype))) return; - palette_entry = Light.palette; - for (;;) { - p = strchr(color, ' '); - if (p) *p = 0; - color = Trim(color); - if (*color && LightColorEntry(color, strlen(color))) { - memcpy(palette_entry, Light.entry_color, Light.subtype); - palette_entry += Light.subtype; - palette_count++; - } - if (!p) break; - color = p + 1; - } - if (!(Light.palette = (uint8_t *)realloc(Light.palette, palette_count * Light.subtype))) return; - Light.palette_count = palette_count; - } - } - - char palette_str[5 * Light.subtype * Light.palette_count + 3]; - p = palette_str; - *p++ = '['; - if (Light.palette_count) { - palette_entry = Light.palette; - for (int entry = 0; entry < Light.palette_count; entry++) { - if (Settings.flag.decimal_text) { - *p++ = '"'; - } - memcpy(Light.current_color, palette_entry, Light.subtype); - LightGetColor(p); - p += strlen(p); - if (Settings.flag.decimal_text) { - *p++ = '"'; - } - *p++ = ','; - } - p--; - } - *p++ = ']'; - *p = 0; - ResponseCmndChar(palette_str); -} -#endif - -void CmndUndocA(void) -{ - - char scolor[LIGHT_COLOR_SIZE]; - LightGetColor(scolor, true); - scolor[6] = '\0'; - Response_P(PSTR("%s,%d,%d,%d,%d,%d"), scolor, Settings.light_fade, Settings.light_correction, Settings.light_scheme, Settings.light_speed, Settings.light_width); - MqttPublishPrefixTopic_P(STAT, XdrvMailbox.topic); - mqtt_data[0] = '\0'; -} - - - - - -bool Xdrv04(uint8_t function) -{ - bool result = false; - - if (FUNC_MODULE_INIT == function) { - return LightModuleInit(); - } - else if (light_type) { - switch (function) { - case FUNC_SERIAL: - result = XlgtCall(FUNC_SERIAL); - break; - case FUNC_LOOP: - if (Light.fade_running) { - if (LightApplyFade()) { - LightSetOutputs(Light.fade_cur_10); - } - } - break; - case FUNC_EVERY_50_MSECOND: - LightAnimate(); - break; -#ifdef USE_DEVICE_GROUPS - case FUNC_DEVICE_GROUP_ITEM: - LightHandleDevGroupItem(); - break; -#endif - case FUNC_SET_POWER: - LightSetPower(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kLightCommands, LightCommand); - if (!result) { - result = XlgtCall(FUNC_COMMAND); - } - break; - case FUNC_PRE_INIT: - LightInit(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_05_irremote.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_05_irremote.ino" -#if defined(USE_IR_REMOTE) && !defined(USE_IR_REMOTE_FULL) - - - - -#define XDRV_05 5 - -#include - -enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND }; - -const char kIrRemoteCommands[] PROGMEM = "|" D_CMND_IRSEND ; - - -void (* const IrRemoteCommand[])(void) PROGMEM = { - &CmndIrSend }; - - -static const uint8_t MAX_STANDARD_IR = NEC; -const char kIrRemoteProtocols[] PROGMEM = "UNKNOWN|RC5|RC6|NEC"; - - - - - -#include - -IRsend *irsend = nullptr; -bool irsend_active = false; - -void IrSendInit(void) -{ - irsend = new IRsend(pin[GPIO_IRSEND]); - irsend->begin(); -} - -#ifdef USE_IR_RECEIVE - - - - -const bool IR_RCV_SAVE_BUFFER = false; -const uint32_t IR_TIME_AVOID_DUPLICATE = 500; - -#include - -IRrecv *irrecv = nullptr; - -unsigned long ir_lasttime = 0; - -void IrReceiveUpdateThreshold(void) -{ - if (irrecv != nullptr) { - if (Settings.param[P_IR_UNKNOW_THRESHOLD] < 6) { Settings.param[P_IR_UNKNOW_THRESHOLD] = 6; } - irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]); - } -} - -void IrReceiveInit(void) -{ - - irrecv = new IRrecv(pin[GPIO_IRRECV], IR_RCV_BUFFER_SIZE, IR_RCV_TIMEOUT, IR_RCV_SAVE_BUFFER); - irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]); - irrecv->enableIRIn(); - - -} - -void IrReceiveCheck(void) -{ - char sirtype[8]; - int8_t iridx = 0; - - decode_results results; - - if (irrecv->decode(&results)) { - char hvalue[65]; - - iridx = results.decode_type; - if ((iridx < 0) || (iridx > MAX_STANDARD_IR)) { iridx = 0; } - - if (iridx) { - if (results.bits > 64) { - - uint32_t digits2 = results.bits / 8; - if (results.bits % 8) { digits2++; } - ToHex_P((unsigned char*)results.state, digits2, hvalue, sizeof(hvalue)); - } else { - Uint64toHex(results.value, hvalue, results.bits); - } - } else { - Uint64toHex(results.value, hvalue, 32); - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_IRR "Echo %d, RawLen %d, Overflow %d, Bits %d, Value 0x%s, Decode %d"), - irsend_active, results.rawlen, results.overflow, results.bits, hvalue, results.decode_type); - - unsigned long now = millis(); - - if (!irsend_active && (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE)) { - ir_lasttime = now; - - char svalue[64]; - if (Settings.flag.ir_receive_decimal) { - ulltoa(results.value, svalue, 10); - } else { - snprintf_P(svalue, sizeof(svalue), PSTR("\"0x%s\""), hvalue); - } - ResponseTime_P(PSTR(",\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d"), - GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits); - if (iridx) { - ResponseAppend_P(PSTR(",\"" D_JSON_IR_DATA "\":%s"), svalue); - } else { - ResponseAppend_P(PSTR(",\"" D_JSON_IR_HASH "\":%s"), svalue); - } - - if (Settings.flag3.receive_raw) { - ResponseAppend_P(PSTR(",\"" D_JSON_IR_RAWDATA "\":[")); - uint16_t i; - for (i = 1; i < results.rawlen; i++) { - if (i > 1) { ResponseAppend_P(PSTR(",")); } - uint32_t usecs; - for (usecs = results.rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) { - ResponseAppend_P(PSTR("%d,0,"), UINT16_MAX); - } - ResponseAppend_P(PSTR("%d"), usecs); - if (strlen(mqtt_data) > sizeof(mqtt_data) - 40) { break; } - } - uint16_t extended_length = results.rawlen - 1; - for (uint32_t j = 0; j < results.rawlen - 1; j++) { - uint32_t usecs = results.rawbuf[j] * kRawTick; - - extended_length += (usecs / (UINT16_MAX + 1)) * 2; - } - ResponseAppend_P(PSTR("],\"" D_JSON_IR_RAWDATA "Info\":[%d,%d,%d]"), extended_length, i -1, results.overflow); - } - - ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); - - XdrvRulesProcess(); -#ifdef USE_DOMOTICZ - if (iridx) { - unsigned long value = results.value | (iridx << 28); - DomoticzSensor(DZ_COUNT, value); - } -#endif - } - - irrecv->resume(); - } -} -#endif - - - - - -uint32_t IrRemoteCmndIrSendJson(void) -{ - - - - - char dataBufUc[XdrvMailbox.data_len + 1]; - UpperCase(dataBufUc, XdrvMailbox.data); - RemoveSpace(dataBufUc); - if (strlen(dataBufUc) < 8) { - return IE_INVALID_JSON; - } - - StaticJsonBuffer<140> jsonBuf; - JsonObject &root = jsonBuf.parseObject(dataBufUc); - if (!root.success()) { - return IE_INVALID_JSON; - } - - - - char parm_uc[10]; - const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))]; - uint16_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))]; - uint64_t data = strtoull(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], nullptr, 0); - uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))]; - - if (XdrvMailbox.index > repeat + 1) { - repeat = XdrvMailbox.index - 1; - } - if (!(protocol && bits)) { - return IE_SYNTAX_IRSEND; - } - - char protocol_text[20]; - int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols); - - char dvalue[64]; - char hvalue[20]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %s (0x%s), repeat %d, protocol_code %d"), - protocol_text, protocol, bits, ulltoa(data, dvalue, 10), Uint64toHex(data, hvalue, bits), repeat, protocol_code); - - irsend_active = true; - switch (protocol_code) { -#ifdef USE_IR_SEND_RC5 - case RC5: - irsend->sendRC5(data, bits, repeat); break; -#endif -#ifdef USE_IR_SEND_RC6 - case RC6: - irsend->sendRC6(data, bits, repeat); break; -#endif -#ifdef USE_IR_SEND_NEC - case NEC: - irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits, repeat); break; -#endif - default: - irsend_active = false; - ResponseCmndChar(D_JSON_PROTOCOL_NOT_SUPPORTED); - } - - return IE_NO_ERROR; -} - -void CmndIrSend(void) -{ - uint8_t error = IE_SYNTAX_IRSEND; - - if (XdrvMailbox.data_len) { - - if (strstr(XdrvMailbox.data, "{") == nullptr) { - error = IE_INVALID_JSON; - } else { - error = IrRemoteCmndIrSendJson(); - } - } - IrRemoteCmndResponse(error); -} - -void IrRemoteCmndResponse(uint32_t error) -{ - switch (error) { - case IE_INVALID_RAWDATA: - ResponseCmndChar_P(PSTR(D_JSON_INVALID_RAWDATA)); - break; - case IE_INVALID_JSON: - ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); - break; - case IE_SYNTAX_IRSEND: - Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_PROTOCOL ", " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}")); - break; - default: - ResponseCmndDone(); - } -} - - - - - -bool Xdrv05(uint8_t function) -{ - bool result = false; - - if ((pin[GPIO_IRSEND] < 99) || (pin[GPIO_IRRECV] < 99)) { - switch (function) { - case FUNC_PRE_INIT: - if (pin[GPIO_IRSEND] < 99) { - IrSendInit(); - } -#ifdef USE_IR_RECEIVE - if (pin[GPIO_IRRECV] < 99) { - IrReceiveInit(); - } -#endif - break; - case FUNC_EVERY_50_MSECOND: -#ifdef USE_IR_RECEIVE - if (pin[GPIO_IRRECV] < 99) { - IrReceiveCheck(); - } -#endif - irsend_active = false; - break; - case FUNC_COMMAND: - if (pin[GPIO_IRSEND] < 99) { - result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand); - } - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_05_irremote_full.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_05_irremote_full.ino" -#ifdef USE_IR_REMOTE_FULL - - - - -#define XDRV_05 5 - -#include -#include -#include -#include -#include - -enum IrErrors { IE_RESPONSE_PROVIDED, IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC, - IE_UNSUPPORTED_HVAC, IE_UNSUPPORTED_PROTOCOL }; - -const char kIrRemoteCommands[] PROGMEM = "|" - D_CMND_IRHVAC "|" D_CMND_IRSEND ; - -void (* const IrRemoteCommand[])(void) PROGMEM = { - &CmndIrHvac, &CmndIrSend }; - - - - - -IRsend *irsend = nullptr; -bool irsend_active = false; - -void IrSendInit(void) -{ - irsend = new IRsend(pin[GPIO_IRSEND]); - irsend->begin(); -} - - - -uint8_t reverseBitsInByte(uint8_t b) { - b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; - b = (b & 0xCC) >> 2 | (b & 0x33) << 2; - b = (b & 0xAA) >> 1 | (b & 0x55) << 1; - return b; -} - - -uint64_t reverseBitsInBytes64(uint64_t b) { - union { - uint8_t b[8]; - uint64_t i; - } a; - a.i = b; - for (uint32_t i=0; i<8; i++) { - a.b[i] = reverseBitsInByte(a.b[i]); - } - return a.i; -} - - - - - -const bool IR_FULL_RCV_SAVE_BUFFER = false; -const uint32_t IR_TIME_AVOID_DUPLICATE = 500; - - - - -const uint16_t IR_FULL_BUFFER_SIZE = 1024; - - - -const uint8_t IR__FULL_RCV_TIMEOUT = 50; - -IRrecv *irrecv = nullptr; - -unsigned long ir_lasttime = 0; - -void IrReceiveUpdateThreshold(void) -{ - if (irrecv != nullptr) { - if (Settings.param[P_IR_UNKNOW_THRESHOLD] < 6) { Settings.param[P_IR_UNKNOW_THRESHOLD] = 6; } - irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]); - } -} - -void IrReceiveInit(void) -{ - - irrecv = new IRrecv(pin[GPIO_IRRECV], IR_FULL_BUFFER_SIZE, IR__FULL_RCV_TIMEOUT, IR_FULL_RCV_SAVE_BUFFER); - irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]); - irrecv->enableIRIn(); -} - -String sendACJsonState(const stdAc::state_t &state) { - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json[D_JSON_IRHVAC_VENDOR] = typeToString(state.protocol); - json[D_JSON_IRHVAC_MODEL] = state.model; - json[D_JSON_IRHVAC_POWER] = IRac::boolToString(state.power); - json[D_JSON_IRHVAC_MODE] = IRac::opmodeToString(state.mode); - - if (state.mode == stdAc::opmode_t::kOff || !state.power) { - json[D_JSON_IRHVAC_MODE] = IRac::opmodeToString(stdAc::opmode_t::kOff); - json[D_JSON_IRHVAC_POWER] = IRac::boolToString(false); - } - json[D_JSON_IRHVAC_CELSIUS] = IRac::boolToString(state.celsius); - if (floorf(state.degrees) == state.degrees) { - json[D_JSON_IRHVAC_TEMP] = floorf(state.degrees); - } else { - json[D_JSON_IRHVAC_TEMP] = RawJson(String(state.degrees, 1)); - } - json[D_JSON_IRHVAC_FANSPEED] = IRac::fanspeedToString(state.fanspeed); - json[D_JSON_IRHVAC_SWINGV] = IRac::swingvToString(state.swingv); - json[D_JSON_IRHVAC_SWINGH] = IRac::swinghToString(state.swingh); - json[D_JSON_IRHVAC_QUIET] = IRac::boolToString(state.quiet); - json[D_JSON_IRHVAC_TURBO] = IRac::boolToString(state.turbo); - json[D_JSON_IRHVAC_ECONO] = IRac::boolToString(state.econo); - json[D_JSON_IRHVAC_LIGHT] = IRac::boolToString(state.light); - json[D_JSON_IRHVAC_FILTER] = IRac::boolToString(state.filter); - json[D_JSON_IRHVAC_CLEAN] = IRac::boolToString(state.clean); - json[D_JSON_IRHVAC_BEEP] = IRac::boolToString(state.beep); - json[D_JSON_IRHVAC_SLEEP] = state.sleep; - - String payload = ""; - payload.reserve(200); - json.printTo(payload); - return payload; -} - -String sendIRJsonState(const struct decode_results &results) { - String json("{"); - json += "\"" D_JSON_IR_PROTOCOL "\":\""; - json += typeToString(results.decode_type); - json += "\",\"" D_JSON_IR_BITS "\":"; - json += results.bits; - - if (hasACState(results.decode_type)) { - json += ",\"" D_JSON_IR_DATA "\":\"0x"; - json += resultToHexidecimal(&results); - json += "\""; - } else { - if (UNKNOWN != results.decode_type) { - json += ",\"" D_JSON_IR_DATA "\":"; - } else { - json += ",\"" D_JSON_IR_HASH "\":"; - } - if (Settings.flag.ir_receive_decimal) { - char svalue[32]; - ulltoa(results.value, svalue, 10); - json += svalue; - } else { - char hvalue[64]; - if (UNKNOWN != results.decode_type) { - Uint64toHex(results.value, hvalue, results.bits); - json += "\"0x"; - json += hvalue; - json += "\",\"" D_JSON_IR_DATALSB "\":\"0x"; - Uint64toHex(reverseBitsInBytes64(results.value), hvalue, results.bits); - json += hvalue; - json += "\""; - } else { - Uint64toHex(results.value, hvalue, 32); - json += "\"0x"; - json += hvalue; - json += "\""; - } - } - } - json += ",\"" D_JSON_IR_REPEAT "\":"; - json += results.repeat; - - stdAc::state_t ac_result; - if (IRAcUtils::decodeToState(&results, &ac_result, nullptr)) { - - json += ",\"" D_CMND_IRHVAC "\":"; - json += sendACJsonState(ac_result); - } - - return json; -} - -void IrReceiveCheck(void) -{ - decode_results results; - - if (irrecv->decode(&results)) { - uint32_t now = millis(); - - - if (!irsend_active && (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE)) { - ir_lasttime = now; - Response_P(PSTR("{\"" D_JSON_IRRECEIVED "\":%s"), sendIRJsonState(results).c_str()); - - if (Settings.flag3.receive_raw) { - ResponseAppend_P(PSTR(",\"" D_JSON_IR_RAWDATA "\":[")); - uint16_t i; - for (i = 1; i < results.rawlen; i++) { - if (i > 1) { ResponseAppend_P(PSTR(",")); } - uint32_t usecs; - for (usecs = results.rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) { - ResponseAppend_P(PSTR("%d,0,"), UINT16_MAX); - } - ResponseAppend_P(PSTR("%d"), usecs); - if (strlen(mqtt_data) > sizeof(mqtt_data) - 40) { break; } - } - uint16_t extended_length = results.rawlen - 1; - for (uint32_t j = 0; j < results.rawlen - 1; j++) { - uint32_t usecs = results.rawbuf[j] * kRawTick; - - extended_length += (usecs / (UINT16_MAX + 1)) * 2; - } - ResponseAppend_P(PSTR("],\"" D_JSON_IR_RAWDATA "Info\":[%d,%d,%d]"), extended_length, i -1, results.overflow); - } - - ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); - - XdrvRulesProcess(); - } - - irrecv->resume(); - } -} - - - - - - - -String listSupportedProtocols(bool hvac) { - String l(""); - bool first = true; - for (uint32_t i = UNUSED + 1; i <= kLastDecodeType; i++) { - bool found = false; - if (hvac) { - found = IRac::isProtocolSupported((decode_type_t)i); - } else { - found = (IRsend::defaultBits((decode_type_t)i) > 0) && (!IRac::isProtocolSupported((decode_type_t)i)); - } - if (found) { - if (first) { - first = false; - } else { - l += "|"; - } - l += typeToString((decode_type_t)i); - } - } - return l; -} - - -const stdAc::fanspeed_t IrHvacFanSpeed[] PROGMEM = { stdAc::fanspeed_t::kAuto, - stdAc::fanspeed_t::kMin, stdAc::fanspeed_t::kLow,stdAc::fanspeed_t::kMedium, - stdAc::fanspeed_t::kHigh, stdAc::fanspeed_t::kMax }; - -uint32_t IrRemoteCmndIrHvacJson(void) -{ - stdAc::state_t state, prev; - char parm_uc[12]; - - - char dataBufUc[XdrvMailbox.data_len + 1]; - UpperCase(dataBufUc, XdrvMailbox.data); - RemoveSpace(dataBufUc); - if (strlen(dataBufUc) < 8) { return IE_INVALID_JSON; } - - DynamicJsonBuffer jsonBuf; - JsonObject &json = jsonBuf.parseObject(dataBufUc); - if (!json.success()) { return IE_INVALID_JSON; } - - - state.protocol = decode_type_t::UNKNOWN; - state.model = 1; - state.mode = stdAc::opmode_t::kAuto; - state.power = false; - state.celsius = true; - state.degrees = 21.0f; - state.fanspeed = stdAc::fanspeed_t::kMedium; - state.swingv = stdAc::swingv_t::kOff; - state.swingh = stdAc::swingh_t::kOff; - state.light = false; - state.beep = false; - state.econo = false; - state.filter = false; - state.turbo = false; - state.quiet = false; - state.sleep = -1; - state.clean = false; - state.clock = -1; - - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_VENDOR)); - if (json.containsKey(parm_uc)) { state.protocol = strToDecodeType(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_PROTOCOL)); - if (json.containsKey(parm_uc)) { state.protocol = strToDecodeType(json[parm_uc]); } - if (decode_type_t::UNKNOWN == state.protocol) { return IE_UNSUPPORTED_HVAC; } - if (!IRac::isProtocolSupported(state.protocol)) { return IE_UNSUPPORTED_HVAC; } - - - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_FANSPEED)); - if (json.containsKey(parm_uc)) { - uint32_t fan_speed = json[parm_uc]; - if ((fan_speed >= 1) && (fan_speed <= 5)) { - state.fanspeed = (stdAc::fanspeed_t) pgm_read_byte(&IrHvacFanSpeed[fan_speed]); - } else { - state.fanspeed = IRac::strToFanspeed(json[parm_uc]); - } - } - - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_MODEL)); - if (json.containsKey(parm_uc)) { state.model = IRac::strToModel(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_MODE)); - if (json.containsKey(parm_uc)) { state.mode = IRac::strToOpmode(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_SWINGV)); - if (json.containsKey(parm_uc)) { state.swingv = IRac::strToSwingV(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_SWINGH)); - if (json.containsKey(parm_uc)) { state.swingh = IRac::strToSwingH(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_TEMP)); - if (json.containsKey(parm_uc)) { state.degrees = json[parm_uc]; } - - - - - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_POWER)); - if (json.containsKey(parm_uc)) { state.power = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_CELSIUS)); - if (json.containsKey(parm_uc)) { state.celsius = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_LIGHT)); - if (json.containsKey(parm_uc)) { state.light = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_BEEP)); - if (json.containsKey(parm_uc)) { state.beep = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_ECONO)); - if (json.containsKey(parm_uc)) { state.econo = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_FILTER)); - if (json.containsKey(parm_uc)) { state.filter = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_TURBO)); - if (json.containsKey(parm_uc)) { state.turbo = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_QUIET)); - if (json.containsKey(parm_uc)) { state.quiet = IRac::strToBool(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_CLEAN)); - if (json.containsKey(parm_uc)) { state.clean = IRac::strToBool(json[parm_uc]); } - - - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_SLEEP)); - if (json[parm_uc]) { state.sleep = json[parm_uc]; } - - - IRac ac(pin[GPIO_IRSEND]); - bool success = ac.sendAc(state, &prev); - if (!success) { return IE_SYNTAX_IRHVAC; } - - Response_P(PSTR("{\"" D_CMND_IRHVAC "\":%s}"), sendACJsonState(state).c_str()); - return IE_RESPONSE_PROVIDED; -} - -void CmndIrHvac(void) -{ - uint8_t error = IE_SYNTAX_IRHVAC; - - if (XdrvMailbox.data_len) { - error = IrRemoteCmndIrHvacJson(); - } - if (error != IE_RESPONSE_PROVIDED) { IrRemoteCmndResponse(error); } -} - - - - - -uint32_t IrRemoteCmndIrSendJson(void) -{ - char parm_uc[12]; - - - - char dataBufUc[XdrvMailbox.data_len + 1]; - UpperCase(dataBufUc, XdrvMailbox.data); - RemoveSpace(dataBufUc); - if (strlen(dataBufUc) < 8) { return IE_INVALID_JSON; } - - DynamicJsonBuffer jsonBuf; - JsonObject &json = jsonBuf.parseObject(dataBufUc); - if (!json.success()) { return IE_INVALID_JSON; } - - - - decode_type_t protocol = decode_type_t::UNKNOWN; - uint16_t bits = 0; - uint64_t data; - uint8_t repeat = 0; - - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_VENDOR)); - if (json.containsKey(parm_uc)) { protocol = strToDecodeType(json[parm_uc]); } - UpperCase_P(parm_uc, PSTR(D_JSON_IRHVAC_PROTOCOL)); - if (json.containsKey(parm_uc)) { protocol = strToDecodeType(json[parm_uc]); } - if (decode_type_t::UNKNOWN == protocol) { return IE_UNSUPPORTED_PROTOCOL; } - - UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS)); - if (json.containsKey(parm_uc)) { bits = json[parm_uc]; } - UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT)); - if (json.containsKey(parm_uc)) { repeat = json[parm_uc]; } - UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATALSB)); - if (json.containsKey(parm_uc)) { data = reverseBitsInBytes64(strtoull(json[parm_uc], nullptr, 0)); } - UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA)); - if (json.containsKey(parm_uc)) { data = strtoull(json[parm_uc], nullptr, 0); } - if (0 == bits) { return IE_SYNTAX_IRSEND; } - - - if (XdrvMailbox.index > repeat + 1) { repeat = XdrvMailbox.index - 1; } - - char dvalue[32]; - char hvalue[32]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol %d, bits %d, data 0x%s (%s), repeat %d"), - protocol, bits, ulltoa(data, dvalue, 10), Uint64toHex(data, hvalue, bits), repeat); - - irsend_active = true; - bool success = irsend->send(protocol, data, bits, repeat); - - if (!success) { - irsend_active = false; - ResponseCmndChar(D_JSON_PROTOCOL_NOT_SUPPORTED); - } - return IE_NO_ERROR; -} - -uint32_t IrRemoteCmndIrSendRaw(void) -{ - - - - - - - - char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); - if (p == nullptr) { - return IE_INVALID_RAWDATA; - } - - - uint16_t repeat = XdrvMailbox.index > 0 ? XdrvMailbox.index - 1 : 0; - - uint16_t freq = atoi(str); - if (!freq && (*str != '0')) { - uint16_t count = 0; - char *q = p; - for (; *q; count += (*q++ == ',')); - if (count < 2) { - return IE_INVALID_RAWDATA; - } - - uint16_t parm[count]; - for (uint32_t i = 0; i < count; i++) { - parm[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); - if (!parm[i]) { - if (!i) { - parm[0] = 38000; - } else { - return IE_INVALID_RAWDATA; - } - } - } - - uint16_t i = 0; - if (count < 4) { - - uint16_t mark = parm[1] *2; - if (3 == count) { - if (parm[2] < parm[1]) { - - mark = parm[1] * parm[2]; - } else { - - mark = parm[2]; - } - } - uint16_t raw_array[strlen(p)]; - for (; *p; *p++) { - if (*p == '0') { - raw_array[i++] = parm[1]; - } - else if (*p == '1') { - raw_array[i++] = mark; - } - } - irsend_active = true; - for (uint32_t r = 0; r <= repeat; r++) { - irsend->sendRaw(raw_array, i, parm[0]); - if (r < repeat) { - irsend->space(40000); - } - } - } - else if (6 == count) { - - uint16_t raw_array[strlen(p)*2+3]; - raw_array[i++] = parm[1]; - raw_array[i++] = parm[2]; - uint32_t inter_message_32 = (parm[1] + parm[2]) * 3; - uint16_t inter_message = (inter_message_32 > 65000) ? 65000 : inter_message_32; - for (; *p; *p++) { - if (*p == '0') { - raw_array[i++] = parm[3]; - raw_array[i++] = parm[4]; - } - else if (*p == '1') { - raw_array[i++] = parm[3]; - raw_array[i++] = parm[5]; - } - } - raw_array[i++] = parm[3]; - irsend_active = true; - for (uint32_t r = 0; r <= repeat; r++) { - irsend->sendRaw(raw_array, i, parm[0]); - if (r < repeat) { - irsend->space(inter_message); - } - } - } - else { - return IE_INVALID_RAWDATA; - } - } else { - if (!freq) { freq = 38000; } - uint16_t count = 0; - char *q = p; - for (; *q; count += (*q++ == ',')); - if (0 == count) { - return IE_INVALID_RAWDATA; - } - - - count++; - if (count < 200) { - uint16_t raw_array[count]; - for (uint32_t i = 0; i < count; i++) { - raw_array[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); - } - - - - irsend_active = true; - for (uint32_t r = 0; r <= repeat; r++) { - irsend->sendRaw(raw_array, count, freq); - } - } else { - uint16_t *raw_array = reinterpret_cast(malloc(count * sizeof(uint16_t))); - if (raw_array == nullptr) { - return IE_INVALID_RAWDATA; - } - - for (uint32_t i = 0; i < count; i++) { - raw_array[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); - } - - - - irsend_active = true; - for (uint32_t r = 0; r <= repeat; r++) { - irsend->sendRaw(raw_array, count, freq); - } - free(raw_array); - } - } - - return IE_NO_ERROR; -} - -void CmndIrSend(void) -{ - uint8_t error = IE_SYNTAX_IRSEND; - - if (XdrvMailbox.data_len) { - if (strstr(XdrvMailbox.data, "{") == nullptr) { - error = IrRemoteCmndIrSendRaw(); - } else { - error = IrRemoteCmndIrSendJson(); - } - } - IrRemoteCmndResponse(error); -} - -void IrRemoteCmndResponse(uint32_t error) -{ - switch (error) { - case IE_INVALID_RAWDATA: - ResponseCmndChar_P(PSTR(D_JSON_INVALID_RAWDATA)); - break; - case IE_INVALID_JSON: - ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); - break; - case IE_SYNTAX_IRSEND: - Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}")); - break; - case IE_SYNTAX_IRHVAC: - Response_P(PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR ", " D_JSON_IRHVAC_MODE " " D_JSON_OR " " D_JSON_IRHVAC_FANSPEED "\"}")); - break; - case IE_UNSUPPORTED_HVAC: - Response_P(PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR " (%s)\"}"), listSupportedProtocols(true).c_str()); - break; - case IE_UNSUPPORTED_PROTOCOL: - Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_PROTOCOL " (%s)\"}"), listSupportedProtocols(false).c_str()); - break; - default: - ResponseCmndDone(); - } -} - - - - - -bool Xdrv05(uint8_t function) -{ - bool result = false; - - if ((pin[GPIO_IRSEND] < 99) || (pin[GPIO_IRRECV] < 99)) { - switch (function) { - case FUNC_PRE_INIT: - if (pin[GPIO_IRSEND] < 99) { - IrSendInit(); - } - if (pin[GPIO_IRRECV] < 99) { - IrReceiveInit(); - } - break; - case FUNC_EVERY_50_MSECOND: - if (pin[GPIO_IRRECV] < 99) { - IrReceiveCheck(); - } - irsend_active = false; - break; - case FUNC_COMMAND: - if (pin[GPIO_IRSEND] < 99) { - result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand); - } - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_06_snfbridge.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_06_snfbridge.ino" -#ifdef USE_SONOFF_RF - - - - -#define XDRV_06 6 - -const uint32_t SFB_TIME_AVOID_DUPLICATE = 2000; - -enum SonoffBridgeCommands { - CMND_RFSYNC, CMND_RFLOW, CMND_RFHIGH, CMND_RFHOST, CMND_RFCODE }; - -const char kSonoffBridgeCommands[] PROGMEM = "|" - D_CMND_RFSYNC "|" D_CMND_RFLOW "|" D_CMND_RFHIGH "|" D_CMND_RFHOST "|" D_CMND_RFCODE "|" D_CMND_RFKEY "|" D_CMND_RFRAW; - -void (* const SonoffBridgeCommand[])(void) PROGMEM = { - &CmndRfBridge, &CmndRfBridge, &CmndRfBridge, &CmndRfBridge, &CmndRfBridge, &CmndRfKey, &CmndRfRaw }; - -struct SONOFFBRIDGE { - uint32_t last_received_id = 0; - uint32_t last_send_code = 0; - uint32_t last_time = 0; - uint32_t last_learn_time = 0; - uint8_t receive_flag = 0; - uint8_t receive_raw_flag = 0; - uint8_t learn_key = 1; - uint8_t learn_active = 0; - uint8_t expected_bytes = 0; -} SnfBridge; - -#ifdef USE_RF_FLASH - - - - - - - -#include "ihx.h" -#include "c2.h" - -const ssize_t RF_RECORD_NO_START_FOUND = -1; -const ssize_t RF_RECORD_NO_END_FOUND = -2; - -ssize_t rf_find_hex_record_start(uint8_t *buf, size_t size) -{ - for (size_t i = 0; i < size; i++) { - if (buf[i] == ':') { - return i; - } - } - return RF_RECORD_NO_START_FOUND; -} - -ssize_t rf_find_hex_record_end(uint8_t *buf, size_t size) -{ - for (size_t i = 0; i < size; i++) { - if (buf[i] == '\n') { - return i; - } - } - return RF_RECORD_NO_END_FOUND; -} - -ssize_t rf_glue_remnant_with_new_data_and_write(const uint8_t *remnant_data, uint8_t *new_data, size_t new_data_len) -{ - ssize_t record_start; - ssize_t record_end; - ssize_t glue_record_sz; - uint8_t *glue_buf; - ssize_t result; - - if (remnant_data[0] != ':') { return -8; } - - - record_end = rf_find_hex_record_end(new_data, new_data_len); - record_start = rf_find_hex_record_start(new_data, new_data_len); - - - - - if ((record_start != RF_RECORD_NO_START_FOUND) && (record_start < record_end)) { - return -8; - } - - glue_record_sz = strlen((const char *) remnant_data) + record_end; - - glue_buf = (uint8_t *) malloc(glue_record_sz); - if (glue_buf == nullptr) { return -2; } - - - memcpy(glue_buf, remnant_data, strlen((const char *) remnant_data)); - memcpy(glue_buf + strlen((const char *) remnant_data), new_data, record_end); - - result = rf_decode_and_write(glue_buf, glue_record_sz); - free(glue_buf); - return result; -} - -ssize_t rf_decode_and_write(uint8_t *record, size_t size) -{ - uint8_t err = ihx_decode(record, size); - if (err != IHX_SUCCESS) { return -13; } - - ihx_t *h = (ihx_t *) record; - if (h->record_type == IHX_RT_DATA) { - int retries = 5; - uint16_t address = h->address_high * 0x100 + h->address_low; - - do { - err = c2_programming_init(); - err = c2_block_write(address, h->data, h->len); - } while (err != C2_SUCCESS && retries--); - } else if (h->record_type == IHX_RT_END_OF_FILE) { - - err = c2_reset(); - } - - if (err != C2_SUCCESS) { return -12; } - - return 0; -} - -ssize_t rf_search_and_write(uint8_t *buf, size_t size) -{ - - ssize_t rec_end; - ssize_t rec_start; - ssize_t err; - - for (size_t i = 0; i < size; i++) { - - rec_start = rf_find_hex_record_start(buf + i, size - i); - if (rec_start == RF_RECORD_NO_START_FOUND) { - - return -8; - } - - - rec_start += i; - rec_end = rf_find_hex_record_end(buf + rec_start, size - rec_start); - if (rec_end == RF_RECORD_NO_END_FOUND) { - - return rec_start; - } - - - rec_end += rec_start; - - err = rf_decode_and_write(buf + rec_start, rec_end - rec_start); - if (err < 0) { return err; } - i = rec_end; - } - - return 0; -} - -uint8_t rf_erase_flash(void) -{ - uint8_t err; - - for (uint32_t i = 0; i < 4; i++) { - err = c2_programming_init(); - if (err != C2_SUCCESS) { - return 10; - } - err = c2_device_erase(); - if (err != C2_SUCCESS) { - if (i < 3) { - c2_reset(); - } else { - return 11; - } - } else { - break; - } - } - return 0; -} - -uint8_t SnfBrUpdateInit(void) -{ - pinMode(PIN_C2CK, OUTPUT); - pinMode(PIN_C2D, INPUT); - - return rf_erase_flash(); -} -#endif - - - -void SonoffBridgeReceivedRaw(void) -{ - - uint8_t buckets = 0; - - if (0xB1 == serial_in_buffer[1]) { buckets = serial_in_buffer[2] << 1; } - - ResponseTime_P(PSTR(",\"" D_CMND_RFRAW "\":{\"" D_JSON_DATA "\":\"")); - for (uint32_t i = 0; i < serial_in_byte_counter; i++) { - ResponseAppend_P(PSTR("%02X"), serial_in_buffer[i]); - if (0xB1 == serial_in_buffer[1]) { - if ((i > 3) && buckets) { buckets--; } - if ((i < 3) || (buckets % 2) || (i == serial_in_byte_counter -2)) { - ResponseAppend_P(PSTR(" ")); - } - } - } - ResponseAppend_P(PSTR("\"}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_CMND_RFRAW)); - - XdrvRulesProcess(); -} - - - -void SonoffBridgeLearnFailed(void) -{ - SnfBridge.learn_active = 0; - Response_P(S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, SnfBridge.learn_key, D_JSON_LEARN_FAILED); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RFKEY)); -} - -void SonoffBridgeReceived(void) -{ - uint16_t sync_time = 0; - uint16_t low_time = 0; - uint16_t high_time = 0; - uint32_t received_id = 0; - char rfkey[8]; - char stemp[16]; - - AddLogSerial(LOG_LEVEL_DEBUG); - - if (0xA2 == serial_in_buffer[0]) { - SonoffBridgeLearnFailed(); - } - else if (0xA3 == serial_in_buffer[0]) { - SnfBridge.learn_active = 0; - low_time = serial_in_buffer[3] << 8 | serial_in_buffer[4]; - high_time = serial_in_buffer[5] << 8 | serial_in_buffer[6]; - if (low_time && high_time) { - for (uint32_t i = 0; i < 9; i++) { - Settings.rf_code[SnfBridge.learn_key][i] = serial_in_buffer[i +1]; - } - Response_P(S_JSON_COMMAND_INDEX_SVALUE, D_CMND_RFKEY, SnfBridge.learn_key, D_JSON_LEARNED); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_RFKEY)); - } else { - SonoffBridgeLearnFailed(); - } - } - else if (0xA4 == serial_in_buffer[0]) { - if (SnfBridge.learn_active) { - SonoffBridgeLearnFailed(); - } else { - sync_time = serial_in_buffer[1] << 8 | serial_in_buffer[2]; - low_time = serial_in_buffer[3] << 8 | serial_in_buffer[4]; - high_time = serial_in_buffer[5] << 8 | serial_in_buffer[6]; - received_id = serial_in_buffer[7] << 16 | serial_in_buffer[8] << 8 | serial_in_buffer[9]; - - unsigned long now = millis(); - if (!((received_id == SnfBridge.last_received_id) && (now - SnfBridge.last_time < SFB_TIME_AVOID_DUPLICATE))) { - SnfBridge.last_received_id = received_id; - SnfBridge.last_time = now; - strncpy_P(rfkey, PSTR("\"" D_JSON_NONE "\""), sizeof(rfkey)); - for (uint32_t i = 1; i <= 16; i++) { - if (Settings.rf_code[i][0]) { - uint32_t send_id = Settings.rf_code[i][6] << 16 | Settings.rf_code[i][7] << 8 | Settings.rf_code[i][8]; - if (send_id == received_id) { - snprintf_P(rfkey, sizeof(rfkey), PSTR("%d"), i); - break; - } - } - } - if (Settings.flag.rf_receive_decimal) { - snprintf_P(stemp, sizeof(stemp), PSTR("%u"), received_id); - } else { - snprintf_P(stemp, sizeof(stemp), PSTR("\"%06X\""), received_id); - } - ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"), - sync_time, low_time, high_time, stemp, rfkey); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); - XdrvRulesProcess(); - #ifdef USE_DOMOTICZ - DomoticzSensor(DZ_COUNT, received_id); - #endif - } - } - } -} - -bool SonoffBridgeSerialInput(void) -{ - - static int8_t receive_len = 0; - - if (SnfBridge.receive_flag) { - if (SnfBridge.receive_raw_flag) { - if (!serial_in_byte_counter) { - serial_in_buffer[serial_in_byte_counter++] = 0xAA; - } - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (serial_in_byte_counter == 3) { - if ((0xA6 == serial_in_buffer[1]) || (0xAB == serial_in_buffer[1])) { - receive_len = serial_in_buffer[2] + 4; - } - } - if ((!receive_len && (0x55 == serial_in_byte)) || (receive_len && (serial_in_byte_counter == receive_len))) { - SonoffBridgeReceivedRaw(); - SnfBridge.receive_flag = 0; - return 1; - } - } - else if (!((0 == serial_in_byte_counter) && (0 == serial_in_byte))) { - if (0 == serial_in_byte_counter) { - SnfBridge.expected_bytes = 2; - if (serial_in_byte >= 0xA3) { - SnfBridge.expected_bytes = 11; - } - if (serial_in_byte == 0xA6) { - SnfBridge.expected_bytes = 0; - serial_in_buffer[serial_in_byte_counter++] = 0xAA; - SnfBridge.receive_raw_flag = 1; - } - } - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if ((SnfBridge.expected_bytes == serial_in_byte_counter) && (0x55 == serial_in_byte)) { - SonoffBridgeReceived(); - SnfBridge.receive_flag = 0; - return 1; - } - } - serial_in_byte = 0; - } - if (0xAA == serial_in_byte) { - serial_in_byte_counter = 0; - serial_in_byte = 0; - SnfBridge.receive_flag = 1; - receive_len = 0; - } - return 0; -} - -void SonoffBridgeSendCommand(uint8_t code) -{ - Serial.write(0xAA); - Serial.write(code); - Serial.write(0x55); -} - -void SonoffBridgeSendAck(void) -{ - Serial.write(0xAA); - Serial.write(0xA0); - Serial.write(0x55); -} - -void SonoffBridgeSendCode(uint32_t code) -{ - Serial.write(0xAA); - Serial.write(0xA5); - for (uint32_t i = 0; i < 6; i++) { - Serial.write(Settings.rf_code[0][i]); - } - Serial.write((code >> 16) & 0xff); - Serial.write((code >> 8) & 0xff); - Serial.write(code & 0xff); - Serial.write(0x55); - Serial.flush(); -} - -void SonoffBridgeSend(uint8_t idx, uint8_t key) -{ - uint8_t code; - - key--; - Serial.write(0xAA); - Serial.write(0xA5); - for (uint32_t i = 0; i < 8; i++) { - Serial.write(Settings.rf_code[idx][i]); - } - if (0 == idx) { - code = (0x10 << (key >> 2)) | (1 << (key & 3)); - } else { - code = Settings.rf_code[idx][8]; - } - Serial.write(code); - Serial.write(0x55); - Serial.flush(); -#ifdef USE_DOMOTICZ - - -#endif -} - -void SonoffBridgeLearn(uint8_t key) -{ - SnfBridge.learn_key = key; - SnfBridge.learn_active = 1; - SnfBridge.last_learn_time = millis(); - Serial.write(0xAA); - Serial.write(0xA1); - Serial.write(0x55); -} - - - - - -void CmndRfBridge(void) -{ - char *p; - char stemp [10]; - uint32_t code = 0; - uint8_t radix = 10; - - uint32_t set_index = XdrvMailbox.command_code *2; - - if (XdrvMailbox.data[0] == '#') { - XdrvMailbox.data++; - XdrvMailbox.data_len--; - radix = 16; - } - - if (XdrvMailbox.data_len) { - code = strtol(XdrvMailbox.data, &p, radix); - if (code) { - if (CMND_RFCODE == XdrvMailbox.command_code) { - SnfBridge.last_send_code = code; - SonoffBridgeSendCode(code); - } else { - if (1 == XdrvMailbox.payload) { - code = pgm_read_byte(kDefaultRfCode + set_index) << 8 | pgm_read_byte(kDefaultRfCode + set_index +1); - } - uint8_t msb = code >> 8; - uint8_t lsb = code & 0xFF; - if ((code > 0) && (code < 0x7FFF) && (msb != 0x55) && (lsb != 0x55)) { - Settings.rf_code[0][set_index] = msb; - Settings.rf_code[0][set_index +1] = lsb; - } - } - } - } - if (CMND_RFCODE == XdrvMailbox.command_code) { - code = SnfBridge.last_send_code; - } else { - code = Settings.rf_code[0][set_index] << 8 | Settings.rf_code[0][set_index +1]; - } - if (10 == radix) { - snprintf_P(stemp, sizeof(stemp), PSTR("%d"), code); - } else { - snprintf_P(stemp, sizeof(stemp), PSTR("\"#%06X\""), code); - } - Response_P(S_JSON_COMMAND_XVALUE, XdrvMailbox.command, stemp); -} - -void CmndRfKey(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 16)) { - unsigned long now = millis(); - if ((!SnfBridge.learn_active) || (now - SnfBridge.last_learn_time > 60100)) { - SnfBridge.learn_active = 0; - if (2 == XdrvMailbox.payload) { - SonoffBridgeLearn(XdrvMailbox.index); - ResponseCmndIdxChar(D_JSON_START_LEARNING); - } - else if (3 == XdrvMailbox.payload) { - Settings.rf_code[XdrvMailbox.index][0] = 0; - ResponseCmndIdxChar(D_JSON_SET_TO_DEFAULT); - } - else if (4 == XdrvMailbox.payload) { - for (uint32_t i = 0; i < 6; i++) { - Settings.rf_code[XdrvMailbox.index][i] = Settings.rf_code[0][i]; - } - Settings.rf_code[XdrvMailbox.index][6] = (SnfBridge.last_send_code >> 16) & 0xff; - Settings.rf_code[XdrvMailbox.index][7] = (SnfBridge.last_send_code >> 8) & 0xff; - Settings.rf_code[XdrvMailbox.index][8] = SnfBridge.last_send_code & 0xff; - ResponseCmndIdxChar(D_JSON_SAVED); - } else if (5 == XdrvMailbox.payload) { - uint8_t key = XdrvMailbox.index; - uint8_t index = (0 == Settings.rf_code[key][0]) ? 0 : key; - uint16_t sync_time = (Settings.rf_code[index][0] << 8) | Settings.rf_code[index][1]; - uint16_t low_time = (Settings.rf_code[index][2] << 8) | Settings.rf_code[index][3]; - uint16_t high_time = (Settings.rf_code[index][4] << 8) | Settings.rf_code[index][5]; - uint32_t code = (Settings.rf_code[index][6] << 16) | (Settings.rf_code[index][7] << 8); - if (0 == index) { - key--; - code |= (uint8_t)((0x10 << (key >> 2)) | (1 << (key & 3))); - } else { - code |= Settings.rf_code[index][8]; - } - Response_P(PSTR("{\"%s%d\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":\"%06X\"}}"), - XdrvMailbox.command, XdrvMailbox.index, sync_time, low_time, high_time, code); - } else { - if ((1 == XdrvMailbox.payload) || (0 == Settings.rf_code[XdrvMailbox.index][0])) { - SonoffBridgeSend(0, XdrvMailbox.index); - ResponseCmndIdxChar(D_JSON_DEFAULT_SENT); - } else { - SonoffBridgeSend(XdrvMailbox.index, 0); - ResponseCmndIdxChar(D_JSON_LEARNED_SENT); - } - } - } else { - Response_P(S_JSON_COMMAND_INDEX_SVALUE, XdrvMailbox.command, SnfBridge.learn_key, D_JSON_LEARNING_ACTIVE); - } - } -} - -void CmndRfRaw(void) -{ - if (XdrvMailbox.data_len) { - if (XdrvMailbox.data_len < 6) { - switch (XdrvMailbox.payload) { - case 0: - SonoffBridgeSendCommand(0xA7); - case 1: - SnfBridge.receive_raw_flag = XdrvMailbox.payload; - break; - case 166: - case 167: - case 169: - case 176: - case 177: - case 255: - SonoffBridgeSendCommand(XdrvMailbox.payload); - SnfBridge.receive_raw_flag = 1; - break; - case 192: - char beep[] = "AAC000C055\0"; - SerialSendRaw(beep); - break; - } - } else { - SerialSendRaw(RemoveSpace(XdrvMailbox.data)); - SnfBridge.receive_raw_flag = 1; - } - } - ResponseCmndStateText(SnfBridge.receive_raw_flag); -} - - - - - -bool Xdrv06(uint8_t function) -{ - bool result = false; - -#ifdef ESP8266 - if (SONOFF_BRIDGE == my_module_type) { - switch (function) { - case FUNC_SERIAL: - result = SonoffBridgeSerialInput(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kSonoffBridgeCommands, SonoffBridgeCommand); - break; - case FUNC_INIT: - SnfBridge.receive_raw_flag = 0; - SonoffBridgeSendCommand(0xA7); - break; - case FUNC_PRE_INIT: - SetSerial(19200, TS_SERIAL_8N1); - break; - } - } -#endif - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_07_domoticz.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_07_domoticz.ino" -#ifdef USE_DOMOTICZ - -#define XDRV_07 7 - -#define D_PRFX_DOMOTICZ "Domoticz" -#define D_CMND_IDX "Idx" -#define D_CMND_KEYIDX "KeyIdx" -#define D_CMND_SWITCHIDX "SwitchIdx" -#define D_CMND_SENSORIDX "SensorIdx" -#define D_CMND_UPDATETIMER "UpdateTimer" - -const char kDomoticzCommands[] PROGMEM = D_PRFX_DOMOTICZ "|" - D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER ; - -void (* const DomoticzCommand[])(void) PROGMEM = { - &CmndDomoticzIdx, &CmndDomoticzKeyIdx, &CmndDomoticzSwitchIdx, &CmndDomoticzSensorIdx, &CmndDomoticzUpdateTimer }; - -const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}"; - -#if MAX_DOMOTICZ_SNS_IDX < DZ_MAX_SENSORS - #error "Domoticz: Too many sensors or change settings.h layout" -#endif - -const char kDomoticzSensors[] PROGMEM = - D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|" - D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT "|" D_DOMOTICZ_AIRQUALITY "|" D_DOMOTICZ_P1_SMART_METER "|" D_DOMOTICZ_SHUTTER ; - -char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; - -int domoticz_update_timer = 0; -uint32_t domoticz_fan_debounce = 0; -bool domoticz_subscribe = false; -bool domoticz_update_flag = true; - -#ifdef USE_SHUTTER -bool domoticz_is_shutter = false; -#endif - -int DomoticzBatteryQuality(void) -{ - - - - - int quality = 100; - -#ifdef USE_ADC_VCC - uint16_t voltage = ESP.getVcc(); - if (voltage <= 2600) { - quality = 0; - } else if (voltage >= 4600) { - quality = 200; - } else { - quality = (voltage - 2600) / 10; - } -#endif - return quality; -} - -int DomoticzRssiQuality(void) -{ - - - return WifiGetRssiAsQuality(WiFi.RSSI()) / 10; -} - -#ifdef USE_SONOFF_IFAN -void MqttPublishDomoticzFanState(void) -{ - if (Settings.flag.mqtt_enabled && Settings.domoticz_relay_idx[1]) { - char svalue[8]; - - int fan_speed = GetFanspeed(); - snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fan_speed * 10); - Response_P(DOMOTICZ_MESSAGE, (int)Settings.domoticz_relay_idx[1], (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality()); - MqttPublish(domoticz_in_topic); - - domoticz_fan_debounce = millis(); - } -} - -void DomoticzUpdateFanState(void) -{ - if (domoticz_update_flag) { - MqttPublishDomoticzFanState(); - } - domoticz_update_flag = true; -} -#endif - -void MqttPublishDomoticzPowerState(uint8_t device) -{ - if (Settings.flag.mqtt_enabled) { - if ((device < 1) || (device > devices_present)) { device = 1; } - if (Settings.domoticz_relay_idx[device -1]) { -#ifdef USE_SHUTTER - if (domoticz_is_shutter) { - - } else { -#endif -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan() && (device > 1)) { - - } else { -#endif - char svalue[8]; - - snprintf_P(svalue, sizeof(svalue), PSTR("%d"), Settings.light_dimmer); - Response_P(DOMOTICZ_MESSAGE, (int)Settings.domoticz_relay_idx[device -1], (power & (1 << (device -1))) ? 1 : 0, (light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality()); - MqttPublish(domoticz_in_topic); -#ifdef USE_SONOFF_IFAN - } -#endif -#ifdef USE_SHUTTER - } -#endif - } - } -} - -void DomoticzUpdatePowerState(uint8_t device) -{ - if (domoticz_update_flag) { - MqttPublishDomoticzPowerState(device); - } - domoticz_update_flag = true; -} - -void DomoticzMqttUpdate(void) -{ - if (domoticz_subscribe && (Settings.domoticz_update_timer || domoticz_update_timer)) { - domoticz_update_timer--; - if (domoticz_update_timer <= 0) { - domoticz_update_timer = Settings.domoticz_update_timer; - for (uint32_t i = 1; i <= devices_present; i++) { -#ifdef USE_SHUTTER - if (domoticz_is_shutter) - { - - break; - } -#endif -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan() && (i > 1)) { - MqttPublishDomoticzFanState(); - break; - } else { -#endif - MqttPublishDomoticzPowerState(i); -#ifdef USE_SONOFF_IFAN - } -#endif - } - } - } -} - -void DomoticzMqttSubscribe(void) -{ - uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; - for (uint32_t i = 0; i < maxdev; i++) { - if (Settings.domoticz_relay_idx[i]) { - domoticz_subscribe = true; - } - } - - if (domoticz_subscribe) { - char stopic[TOPSZ]; - snprintf_P(stopic, sizeof(stopic), PSTR(DOMOTICZ_OUT_TOPIC "/#")); - MqttSubscribe(stopic); - } -} -# 219 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_07_domoticz.ino" -bool DomoticzMqttData(void) -{ - domoticz_update_flag = true; - - if (strncasecmp_P(XdrvMailbox.topic, PSTR(DOMOTICZ_OUT_TOPIC), strlen(DOMOTICZ_OUT_TOPIC)) != 0) { - return false; - } - - - if (XdrvMailbox.data_len < 20) { - return true; - } - StaticJsonBuffer<400> jsonBuf; - JsonObject& domoticz = jsonBuf.parseObject(XdrvMailbox.data); - if (!domoticz.success()) { - return true; - } - - - - uint32_t idx = domoticz["idx"]; - int16_t nvalue = -1; - if (domoticz.containsKey("nvalue")) { - nvalue = domoticz["nvalue"]; - } - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue); - - bool found = false; - if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) { - uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; - for (uint32_t i = 0; i < maxdev; i++) { - if (idx == Settings.domoticz_relay_idx[i]) { - bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0; - bool isShutter = strcmp_P(domoticz["dtype"],PSTR("Light/Switch")) == 0 & strncmp_P(domoticz["switchType"],PSTR("Blinds"), 6) == 0; - - char stemp1[10]; - snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1); -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan() && (1 == i)) { - uint8_t svalue = 0; - if (domoticz.containsKey("svalue1")) { - svalue = domoticz["svalue1"]; - } else { - return true; - } - svalue = (nvalue == 2) ? svalue / 10 : 0; - if (GetFanspeed() == svalue) { - return true; - } - if (TimePassedSince(domoticz_fan_debounce) < 1000) { - return true; - } - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED)); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue); - found = true; - } else -#endif -#ifdef USE_SHUTTER - if (isShutter) - { - if (domoticz.containsKey("nvalue")) { - nvalue = domoticz["nvalue"]; - } - - uint8_t position = 0; - if (domoticz.containsKey("svalue1")) { - position = domoticz["svalue1"]; - } - if (nvalue != 2) { - position = nvalue == 0 ? 0 : 100; - } - - snprintf_P(XdrvMailbox.topic, TOPSZ, PSTR("/" D_PRFX_SHUTTER D_CMND_SHUTTER_POSITION)); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), position); - XdrvMailbox.data_len = position > 99 ? 3 : (position > 9 ? 2 : 1); - - found = true; - } else -#endif -#ifdef USE_LIGHT - if (iscolordimmer && 10 == nvalue) { - - JsonObject& color = domoticz["Color"]; - uint16_t level = nvalue = domoticz["svalue1"]; - uint16_t r = color["r"]; r = r * level / 100; - uint16_t g = color["g"]; g = g * level / 100; - uint16_t b = color["b"]; b = b * level / 100; - uint16_t cw = color["cw"]; cw = cw * level / 100; - uint16_t ww = color["ww"]; ww = ww * level / 100; - uint16_t m = 0; - uint16_t t = 0; - if (color.containsKey("m")) { - m = color["m"]; - t = color["t"]; - } - if (2 == m) { - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_BACKLOG)); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR(D_CMND_COLORTEMPERATURE " %d;" D_CMND_DIMMER " %d"), changeUIntScale(t, 0, 255, CT_MIN, CT_MAX), level); - } else { - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_COLOR)); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%02x%02x%02x%02x%02x"), r, g, b, cw, ww); - } - found = true; - } - else if ((!iscolordimmer && 2 == nvalue) || - (iscolordimmer && 15 == nvalue)) { - if (domoticz.containsKey("svalue1")) { - nvalue = domoticz["svalue1"]; - } else { - return true; - } - if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &1)) { - return true; - } - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_DIMMER)); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue); - found = true; - } else -#endif - if (1 == nvalue || 0 == nvalue) { - if (((power >> i) &1) == (power_t)nvalue) { - return true; - } - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : ""); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue); - found = true; - } - break; - } - } - } - if (!found) { return true; } - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data); - - domoticz_update_flag = false; - return false; -} - - - -bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg) -{ - bool result = false; - - if (device <= MAX_DOMOTICZ_IDX) { - if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) { - Response_P(PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"), - (key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (POWER_TOGGLE == state) ? "Toggle" : "On" : "Off"); - MqttPublish(domoticz_in_topic); - result = true; - } - } - return result; -} -# 393 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_07_domoticz.ino" -uint8_t DomoticzHumidityState(float h) -{ - return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1; -} - -void DomoticzSensor(uint8_t idx, char *data) -{ - if (Settings.domoticz_sensor_idx[idx]) { - char dmess[128]; - - memcpy(dmess, mqtt_data, sizeof(dmess)); - if (DZ_AIRQUALITY == idx) { - Response_P(PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"), - Settings.domoticz_sensor_idx[idx], data, DomoticzBatteryQuality(), DomoticzRssiQuality()); - } else { - uint8_t nvalue = 0; -#ifdef USE_SHUTTER - if (DZ_SHUTTER == idx) { - uint8_t position = atoi(data); - nvalue = position < 2 ? 0 : (position == 100 ? 1 : 2); - } -#endif - Response_P(DOMOTICZ_MESSAGE, - Settings.domoticz_sensor_idx[idx], nvalue, data, DomoticzBatteryQuality(), DomoticzRssiQuality()); - } - MqttPublish(domoticz_in_topic); - memcpy(mqtt_data, dmess, sizeof(dmess)); - } -} - -void DomoticzSensor(uint8_t idx, uint32_t value) -{ - char data[16]; - snprintf_P(data, sizeof(data), PSTR("%d"), value); - DomoticzSensor(idx, data); -} - - -void DomoticzTempHumPressureSensor(float temp, float hum, float baro) -{ - char temperature[FLOATSZ]; - dtostrfd(temp, 2, temperature); - char humidity[FLOATSZ]; - dtostrfd(hum, 2, humidity); - - char data[32]; - if (baro > -1) { - char pressure[FLOATSZ]; - dtostrfd(baro, 2, pressure); - - snprintf_P(data, sizeof(data), PSTR("%s;%s;%d;%s;5"), temperature, humidity, DomoticzHumidityState(hum), pressure); - DomoticzSensor(DZ_TEMP_HUM_BARO, data); - } else { - snprintf_P(data, sizeof(data), PSTR("%s;%s;%d"), temperature, humidity, DomoticzHumidityState(hum)); - DomoticzSensor(DZ_TEMP_HUM, data); - } -} - -void DomoticzSensorPowerEnergy(int power, char *energy) -{ - char data[16]; - snprintf_P(data, sizeof(data), PSTR("%d;%s"), power, energy); - DomoticzSensor(DZ_POWER_ENERGY, data); -} - -void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int power) -{ - - - - - - int consumed = power; - int produced = 0; - if (power < 0) { - consumed = 0; - produced = -power; - } - char data[64]; - snprintf_P(data, sizeof(data), PSTR("%s;%s;%s;%s;%d;%d"), usage1, usage2, return1, return2, consumed, produced); - DomoticzSensor(DZ_P1_SMART_METER, data); -} - - - - - -void CmndDomoticzIdx(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) { - if (XdrvMailbox.payload >= 0) { - Settings.domoticz_relay_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; - restart_flag = 2; - } - ResponseCmndIdxNumber(Settings.domoticz_relay_idx[XdrvMailbox.index -1]); - } -} - -void CmndDomoticzKeyIdx(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) { - if (XdrvMailbox.payload >= 0) { - Settings.domoticz_key_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; - } - ResponseCmndIdxNumber(Settings.domoticz_key_idx[XdrvMailbox.index -1]); - } -} - -void CmndDomoticzSwitchIdx(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) { - if (XdrvMailbox.payload >= 0) { - Settings.domoticz_switch_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; - } - ResponseCmndIdxNumber(Settings.domoticz_switch_idx[XdrvMailbox.index -1]); - } -} - -void CmndDomoticzSensorIdx(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= DZ_MAX_SENSORS)) { - if (XdrvMailbox.payload >= 0) { - Settings.domoticz_sensor_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; - } - ResponseCmndIdxNumber(Settings.domoticz_sensor_idx[XdrvMailbox.index -1]); - } -} - -void CmndDomoticzUpdateTimer(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { - Settings.domoticz_update_timer = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.domoticz_update_timer); -} - - - - - -#ifdef USE_WEBSERVER - -#define WEB_HANDLE_DOMOTICZ "dm" - -const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ; - -const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM = - "

"; - -const char HTTP_FORM_DOMOTICZ[] PROGMEM = - "
 " D_DOMOTICZ_PARAMETERS " " - "
" - ""; -const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = - "" - ""; -const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = - ""; -const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = - ""; -const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = - ""; - -void HandleDomoticzConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); - - if (Webserver->hasArg("save")) { - DomoticzSaveSettings(); - WebRestart(1); - return; - } - - char stemp[40]; - - WSContentStart_P(S_CONFIGURE_DOMOTICZ); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_DOMOTICZ); - for (uint32_t i = 0; i < MAX_DOMOTICZ_IDX; i++) { - if (i < devices_present) { - WSContentSend_P(HTTP_FORM_DOMOTICZ_RELAY, - i +1, i, Settings.domoticz_relay_idx[i], - i +1, i, Settings.domoticz_key_idx[i]); - } - if (pin[GPIO_SWT1 +i] < 99) { - WSContentSend_P(HTTP_FORM_DOMOTICZ_SWITCH, - i +1, i, Settings.domoticz_switch_idx[i]); - } -#ifdef USE_SONOFF_IFAN - if (IsModuleIfan() && (1 == i)) { break; } -#endif - } - for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) { - WSContentSend_P(HTTP_FORM_DOMOTICZ_SENSOR, - i +1, GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors), i, Settings.domoticz_sensor_idx[i]); - } - WSContentSend_P(HTTP_FORM_DOMOTICZ_TIMER, Settings.domoticz_update_timer); - WSContentSend_P(PSTR("
" D_DOMOTICZ_IDX " %d
" D_DOMOTICZ_KEY_IDX " %d
" D_DOMOTICZ_SWITCH_IDX " %d
" D_DOMOTICZ_SENSOR_IDX " %d %s
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
")); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void DomoticzSaveSettings(void) -{ - char stemp[20]; - char ssensor_indices[6 * MAX_DOMOTICZ_SNS_IDX]; - char tmp[100]; - - for (uint32_t i = 0; i < MAX_DOMOTICZ_IDX; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_relay_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_key_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_switch_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - } - ssensor_indices[0] = '\0'; - for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_sensor_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(ssensor_indices, sizeof(ssensor_indices), PSTR("%s%s%d"), ssensor_indices, (strlen(ssensor_indices)) ? "," : "", Settings.domoticz_sensor_idx[i]); - } - WebGetArg("ut", tmp, sizeof(tmp)); - Settings.domoticz_update_timer = (!strlen(tmp)) ? DOMOTICZ_UPDATE_TIMER : atoi(tmp); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_DOMOTICZ D_CMND_IDX " %d,%d,%d,%d, " D_CMND_KEYIDX " %d,%d,%d,%d, " D_CMND_SWITCHIDX " %d,%d,%d,%d, " D_CMND_SENSORIDX " %s, " D_CMND_UPDATETIMER " %d"), - Settings.domoticz_relay_idx[0], Settings.domoticz_relay_idx[1], Settings.domoticz_relay_idx[2], Settings.domoticz_relay_idx[3], - Settings.domoticz_key_idx[0], Settings.domoticz_key_idx[1], Settings.domoticz_key_idx[2], Settings.domoticz_key_idx[3], - Settings.domoticz_switch_idx[0], Settings.domoticz_switch_idx[1], Settings.domoticz_switch_idx[2], Settings.domoticz_switch_idx[3], - ssensor_indices, Settings.domoticz_update_timer); -} -#endif - - - - - -bool Xdrv07(uint8_t function) -{ - bool result = false; - - if (Settings.flag.mqtt_enabled) { - switch (function) { - case FUNC_EVERY_SECOND: - DomoticzMqttUpdate(); - break; - case FUNC_MQTT_DATA: - result = DomoticzMqttData(); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_DOMOTICZ); - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); - break; -#endif - case FUNC_MQTT_SUBSCRIBE: - DomoticzMqttSubscribe(); -#ifdef USE_SHUTTER - if (Settings.domoticz_sensor_idx[DZ_SHUTTER]) { domoticz_is_shutter = true; } -#endif - break; - case FUNC_MQTT_INIT: - domoticz_update_timer = 2; - break; - case FUNC_SHOW_SENSOR: - - break; - case FUNC_COMMAND: - result = DecodeCommand(kDomoticzCommands, DomoticzCommand); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_08_serial_bridge.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_08_serial_bridge.ino" -#ifdef USE_SERIAL_BRIDGE - - - - -#define XDRV_08 8 - -const uint8_t SERIAL_BRIDGE_BUFFER_SIZE = 130; - -const char kSerialBridgeCommands[] PROGMEM = "|" - D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE; - -void (* const SerialBridgeCommand[])(void) PROGMEM = { - &CmndSSerialSend, &CmndSBaudrate }; - -#include - -TasmotaSerial *SerialBridgeSerial = nullptr; - -unsigned long serial_bridge_polling_window = 0; -char *serial_bridge_buffer = nullptr; -int serial_bridge_in_byte_counter = 0; -bool serial_bridge_active = true; -bool serial_bridge_raw = false; - -void SerialBridgeInput(void) -{ - while (SerialBridgeSerial->available()) { - yield(); - uint8_t serial_in_byte = SerialBridgeSerial->read(); - - if ((serial_in_byte > 127) && !serial_bridge_raw) { - serial_bridge_in_byte_counter = 0; - SerialBridgeSerial->flush(); - return; - } - if (serial_in_byte || serial_bridge_raw) { - - if ((serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) && - ((isprint(serial_in_byte) && (128 == Settings.serial_delimiter)) || - ((serial_in_byte != Settings.serial_delimiter) && (128 != Settings.serial_delimiter)) || - serial_bridge_raw)) { - serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte; - serial_bridge_polling_window = millis(); - } else { - serial_bridge_polling_window = 0; - break; - } - } - } - - if (serial_bridge_in_byte_counter && (millis() > (serial_bridge_polling_window + SERIAL_POLLING))) { - serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; - char hex_char[(serial_bridge_in_byte_counter * 2) + 2]; - bool assume_json = (!serial_bridge_raw && (serial_bridge_buffer[0] == '{')); - Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":%s%s%s}"), - (assume_json) ? "" : "\"", - (serial_bridge_raw) ? ToHex_P((unsigned char*)serial_bridge_buffer, serial_bridge_in_byte_counter, hex_char, sizeof(hex_char)) : serial_bridge_buffer, - (assume_json) ? "" : "\""); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED)); - XdrvRulesProcess(); - serial_bridge_in_byte_counter = 0; - } -} - - - -void SerialBridgeInit(void) -{ - serial_bridge_active = false; - if ((pin[GPIO_SBR_RX] < 99) && (pin[GPIO_SBR_TX] < 99)) { - SerialBridgeSerial = new TasmotaSerial(pin[GPIO_SBR_RX], pin[GPIO_SBR_TX]); - if (SerialBridgeSerial->begin(Settings.sbaudrate * 300)) { - if (SerialBridgeSerial->hardwareSerial()) { - ClaimSerial(); - serial_bridge_buffer = serial_in_buffer; - } else { - serial_bridge_buffer = (char*)(malloc(SERIAL_BRIDGE_BUFFER_SIZE)); - } - serial_bridge_active = true; - SerialBridgeSerial->flush(); - } - } -} - - - - - -void CmndSSerialSend(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { - serial_bridge_raw = (XdrvMailbox.index > 3); - if (XdrvMailbox.data_len > 0) { - if (1 == XdrvMailbox.index) { - SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); - SerialBridgeSerial->write("\n"); - } - else if ((2 == XdrvMailbox.index) || (4 == XdrvMailbox.index)) { - SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); - } - else if (3 == XdrvMailbox.index) { - SerialBridgeSerial->write(Unescape(XdrvMailbox.data, &XdrvMailbox.data_len), XdrvMailbox.data_len); - } - else if (5 == XdrvMailbox.index) { - char *p; - char stemp[3]; - uint8_t code; - - char *codes = RemoveSpace(XdrvMailbox.data); - int size = strlen(XdrvMailbox.data); - - while (size > 1) { - strlcpy(stemp, codes, sizeof(stemp)); - code = strtol(stemp, &p, 16); - SerialBridgeSerial->write(code); - size -= 2; - codes += 2; - } - } - ResponseCmndDone(); - } - } -} - -void CmndSBaudrate(void) -{ - if (XdrvMailbox.payload >= 300) { - XdrvMailbox.payload /= 300; - Settings.sbaudrate = XdrvMailbox.payload; - SerialBridgeSerial->begin(Settings.sbaudrate * 300); - } - ResponseCmndNumber(Settings.sbaudrate * 300); -} - - - - - -bool Xdrv08(uint8_t function) -{ - bool result = false; - - if (serial_bridge_active) { - switch (function) { - case FUNC_LOOP: - if (SerialBridgeSerial) { SerialBridgeInput(); } - break; - case FUNC_PRE_INIT: - SerialBridgeInit(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kSerialBridgeCommands, SerialBridgeCommand); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_09_timers.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_09_timers.ino" -#ifdef USE_TIMERS -# 39 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_09_timers.ino" -#define XDRV_09 9 - -const char kTimerCommands[] PROGMEM = "|" - D_CMND_TIMER "|" D_CMND_TIMERS -#ifdef USE_SUNRISE - "|" D_CMND_LATITUDE "|" D_CMND_LONGITUDE -#endif - ; - -void (* const TimerCommand[])(void) PROGMEM = { - &CmndTimer, &CmndTimers -#ifdef USE_SUNRISE - , &CmndLatitude, &CmndLongitude -#endif - }; - -uint16_t timer_last_minute = 60; -int8_t timer_window[MAX_TIMERS] = { 0 }; - -#ifdef USE_SUNRISE -# 67 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_09_timers.ino" -const float pi2 = TWO_PI; -const float pi = PI; -const float RAD = DEG_TO_RAD; - -float JulianischesDatum(void) -{ - - int Gregor; - int Jahr = RtcTime.year; - int Monat = RtcTime.month; - int Tag = RtcTime.day_of_month; - - if (Monat <= 2) { - Monat += 12; - Jahr -= 1; - } - Gregor = (Jahr / 400) - (Jahr / 100) + (Jahr / 4); - return 2400000.5f + 365.0f*Jahr - 679004.0f + Gregor + (int)(30.6001f * (Monat +1)) + Tag + 0.5f; -} - -float InPi(float x) -{ - int n = (int)(x / pi2); - x = x - n*pi2; - if (x < 0) x += pi2; - return x; -} - -float eps(float T) -{ - - return RAD * (23.43929111f + (-46.8150f*T - 0.00059f*T*T + 0.001813f*T*T*T)/3600.0f); -} - -float BerechneZeitgleichung(float *DK,float T) -{ - float RA_Mittel = 18.71506921f + 2400.0513369f*T +(2.5862e-5f - 1.72e-9f*T)*T*T; - float M = InPi(pi2 * (0.993133f + 99.997361f*T)); - float L = InPi(pi2 * (0.7859453f + M/pi2 + (6893.0f*sinf(M)+72.0f*sinf(2.0f*M)+6191.2f*T) / 1296.0e3f)); - float e = eps(T); - float RA = atanf(tanf(L)*cosf(e)); - if (RA < 0.0) RA += pi; - if (L > pi) RA += pi; - RA = 24.0*RA/pi2; - *DK = asinf(sinf(e)*sinf(L)); - - RA_Mittel = 24.0f * InPi(pi2*RA_Mittel/24.0f)/pi2; - float dRA = RA_Mittel - RA; - if (dRA < -12.0f) dRA += 24.0f; - if (dRA > 12.0f) dRA -= 24.0f; - dRA = dRA * 1.0027379f; - return dRA; -} - -void DuskTillDawn(uint8_t *hour_up,uint8_t *minute_up, uint8_t *hour_down, uint8_t *minute_down) -{ - float JD2000 = 2451545.0f; - float JD = JulianischesDatum(); - float T = (JD - JD2000) / 36525.0f; - float DK; - - - - - - - - float h = SUNRISE_DAWN_ANGLE *RAD; - float B = (((float)Settings.latitude)/1000000) * RAD; - float GeographischeLaenge = ((float)Settings.longitude)/1000000; - - - - float Zeitzone = ((float)Rtc.time_timezone) / 60; - float Zeitgleichung = BerechneZeitgleichung(&DK, T); - float Zeitdifferenz = 12.0f*acosf((sinf(h) - sinf(B)*sinf(DK)) / (cosf(B)*cosf(DK)))/pi; - float AufgangOrtszeit = 12.0f - Zeitdifferenz - Zeitgleichung; - float UntergangOrtszeit = 12.0f + Zeitdifferenz - Zeitgleichung; - float AufgangWeltzeit = AufgangOrtszeit - GeographischeLaenge / 15.0f; - float UntergangWeltzeit = UntergangOrtszeit - GeographischeLaenge / 15.0f; - float Aufgang = AufgangWeltzeit + Zeitzone; - if (Aufgang < 0.0f) { - Aufgang += 24.0f; - } else { - if (Aufgang >= 24.0f) Aufgang -= 24.0f; - } - float Untergang = UntergangWeltzeit + Zeitzone; - if (Untergang < 0.0f) { - Untergang += 24.0f; - } else { - if (Untergang >= 24.0f) Untergang -= 24.0f; - } - int AufgangMinuten = (int)(60.0f*(Aufgang - (int)Aufgang)+0.5f); - int AufgangStunden = (int)Aufgang; - if (AufgangMinuten >= 60.0f) { - AufgangMinuten -= 60.0f; - AufgangStunden++; - } else { - if (AufgangMinuten < 0.0f) { - AufgangMinuten += 60.0f; - AufgangStunden--; - if (AufgangStunden < 0.0f) AufgangStunden += 24.0f; - } - } - int UntergangMinuten = (int)(60.0f*(Untergang - (int)Untergang)+0.5f); - int UntergangStunden = (int)Untergang; - if (UntergangMinuten >= 60.0f) { - UntergangMinuten -= 60.0f; - UntergangStunden++; - } else { - if (UntergangMinuten<0) { - UntergangMinuten += 60.0f; - UntergangStunden--; - if (UntergangStunden < 0.0f) UntergangStunden += 24.0f; - } - } - *hour_up = AufgangStunden; - *minute_up = AufgangMinuten; - *hour_down = UntergangStunden; - *minute_down = UntergangMinuten; -} - -void ApplyTimerOffsets(Timer *duskdawn) -{ - uint8_t hour[2]; - uint8_t minute[2]; - Timer stored = (Timer)*duskdawn; - - - DuskTillDawn(&hour[0], &minute[0], &hour[1], &minute[1]); - uint8_t mode = (duskdawn->mode -1) &1; - duskdawn->time = (hour[mode] *60) + minute[mode]; - - - uint16_t timeBuffer; - if ((uint16_t)stored.time > 719) { - - timeBuffer = (uint16_t)stored.time - 720; - - if (timeBuffer > (uint16_t)duskdawn->time) { - timeBuffer = 1440 - (timeBuffer - (uint16_t)duskdawn->time); - duskdawn->days = duskdawn->days >> 1; - duskdawn->days |= (stored.days << 6); - } else { - timeBuffer = (uint16_t)duskdawn->time - timeBuffer; - } - } else { - - timeBuffer = (uint16_t)duskdawn->time + (uint16_t)stored.time; - - if (timeBuffer > 1440) { - timeBuffer -= 1440; - duskdawn->days = duskdawn->days << 1; - duskdawn->days |= (stored.days >> 6); - } - } - duskdawn->time = timeBuffer; -} - -String GetSun(uint32_t dawn) -{ - char stime[6]; - - uint8_t hour[2]; - uint8_t minute[2]; - - DuskTillDawn(&hour[0], &minute[0], &hour[1], &minute[1]); - dawn &= 1; - snprintf_P(stime, sizeof(stime), PSTR("%02d:%02d"), hour[dawn], minute[dawn]); - return String(stime); -} - -uint16_t SunMinutes(uint32_t dawn) -{ - uint8_t hour[2]; - uint8_t minute[2]; - - DuskTillDawn(&hour[0], &minute[0], &hour[1], &minute[1]); - dawn &= 1; - return (hour[dawn] *60) + minute[dawn]; -} - -#endif - - - -void TimerSetRandomWindow(uint32_t index) -{ - timer_window[index] = 0; - if (Settings.timer[index].window) { - timer_window[index] = (random(0, (Settings.timer[index].window << 1) +1)) - Settings.timer[index].window; - } -} - -void TimerSetRandomWindows(void) -{ - for (uint32_t i = 0; i < MAX_TIMERS; i++) { TimerSetRandomWindow(i); } -} - -void TimerEverySecond(void) -{ - if (RtcTime.valid) { - if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second) { TimerSetRandomWindows(); } - if (Settings.flag3.timers_enable && - (uptime > 60) && (RtcTime.minute != timer_last_minute)) { - timer_last_minute = RtcTime.minute; - int32_t time = (RtcTime.hour *60) + RtcTime.minute; - uint8_t days = 1 << (RtcTime.day_of_week -1); - - for (uint32_t i = 0; i < MAX_TIMERS; i++) { - - Timer xtimer = Settings.timer[i]; -#ifdef USE_SUNRISE - if ((1 == xtimer.mode) || (2 == xtimer.mode)) { - ApplyTimerOffsets(&xtimer); - } -#endif - if (xtimer.arm) { - int32_t set_time = xtimer.time + timer_window[i]; - if (set_time < 0) { - set_time = abs(timer_window[i]); - } - if (set_time > 1439) { - set_time = xtimer.time - abs(timer_window[i]); - } - if (set_time > 1439) { set_time = 1439; } - - DEBUG_DRIVER_LOG(PSTR("TIM: Timer %d, Time %d, Window %d, SetTime %d"), i +1, xtimer.time, timer_window[i], set_time); - - if (time == set_time) { - if (xtimer.days & days) { - Settings.timer[i].arm = xtimer.repeat; -#if defined(USE_RULES) || defined(USE_SCRIPT) - if (POWER_BLINK == xtimer.power) { - Response_P(PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1); - XdrvRulesProcess(); - } else -#endif - if (devices_present) { ExecuteCommandPower(xtimer.device +1, xtimer.power, SRC_TIMER); } - } - } - } - } - } - } -} - -void PrepShowTimer(uint32_t index) -{ - Timer xtimer = Settings.timer[index -1]; - - char days[8] = { 0 }; - for (uint32_t i = 0; i < 7; i++) { - uint8_t mask = 1 << i; - snprintf(days, sizeof(days), "%s%d", days, ((xtimer.days & mask) > 0)); - } - - char soutput[80]; - soutput[0] = '\0'; - if (devices_present) { - snprintf_P(soutput, sizeof(soutput), PSTR(",\"" D_JSON_TIMER_OUTPUT "\":%d"), xtimer.device +1); - } -#ifdef USE_SUNRISE - char sign[2] = { 0 }; - int16_t hour = xtimer.time / 60; - if ((1 == xtimer.mode) || (2 == xtimer.mode)) { - if (hour > 11) { - hour -= 12; - sign[0] = '-'; - } - } - ResponseAppend_P(PSTR("\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_MODE "\":%d,\"" D_JSON_TIMER_TIME "\":\"%s%02d:%02d\",\"" D_JSON_TIMER_WINDOW "\":%d,\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d%s,\"" D_JSON_TIMER_ACTION "\":%d}"), - index, xtimer.arm, xtimer.mode, sign, hour, xtimer.time % 60, xtimer.window, days, xtimer.repeat, soutput, xtimer.power); -#else - ResponseAppend_P(PSTR("\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_TIME "\":\"%02d:%02d\",\"" D_JSON_TIMER_WINDOW "\":%d,\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d%s,\"" D_JSON_TIMER_ACTION "\":%d}"), - index, xtimer.arm, xtimer.time / 60, xtimer.time % 60, xtimer.window, days, xtimer.repeat, soutput, xtimer.power); -#endif -} - - - - - -void CmndTimer(void) -{ - uint32_t index = XdrvMailbox.index; - if ((index > 0) && (index <= MAX_TIMERS)) { - uint32_t error = 0; - if (XdrvMailbox.data_len) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= MAX_TIMERS)) { - if (XdrvMailbox.payload == 0) { - Settings.timer[index -1].data = 0; - } else { - Settings.timer[index -1].data = Settings.timer[XdrvMailbox.payload -1].data; - } - } else { - -#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0 - if (devices_present) { -#endif - char dataBufUc[XdrvMailbox.data_len + 1]; - UpperCase(dataBufUc, XdrvMailbox.data); - StaticJsonBuffer<256> jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(dataBufUc); - if (!root.success()) { - Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); - error = 1; - } - else { - char parm_uc[10]; - index--; - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ARM))].success()) { - Settings.timer[index].arm = (root[parm_uc] != 0); - } -#ifdef USE_SUNRISE - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_MODE))].success()) { - Settings.timer[index].mode = (uint8_t)root[parm_uc] & 0x03; - } -#endif - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_TIME))].success()) { - uint16_t itime = 0; - int8_t value = 0; - uint8_t sign = 0; - char time_str[10]; - - strlcpy(time_str, root[parm_uc], sizeof(time_str)); - const char *substr = strtok(time_str, ":"); - if (substr != nullptr) { - if (strchr(substr, '-')) { - sign = 1; - substr++; - } - value = atoi(substr); - if (sign) { value += 12; } - if (value > 23) { value = 23; } - itime = value * 60; - substr = strtok(nullptr, ":"); - if (substr != nullptr) { - value = atoi(substr); - if (value < 0) { value = 0; } - if (value > 59) { value = 59; } - itime += value; - } - } - Settings.timer[index].time = itime; - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_WINDOW))].success()) { - Settings.timer[index].window = (uint8_t)root[parm_uc] & 0x0F; - TimerSetRandomWindow(index); - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_DAYS))].success()) { - - Settings.timer[index].days = 0; - const char *tday = root[parm_uc]; - uint8_t i = 0; - char ch = *tday++; - while ((ch != '\0') && (i < 7)) { - if (ch == '-') { ch = '0'; } - uint8_t mask = 1 << i++; - Settings.timer[index].days |= (ch == '0') ? 0 : mask; - ch = *tday++; - } - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_REPEAT))].success()) { - Settings.timer[index].repeat = (root[parm_uc] != 0); - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_OUTPUT))].success()) { - uint8_t device = ((uint8_t)root[parm_uc] -1) & 0x0F; - Settings.timer[index].device = (device < devices_present) ? device : 0; - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ACTION))].success()) { - uint8_t action = (uint8_t)root[parm_uc] & 0x03; - Settings.timer[index].power = (devices_present) ? action : 3; - } - - index++; - } - -#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0 - } else { - Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_TIMER_NO_DEVICE "\"}"), index); - error = 1; - } -#endif - } - } - if (!error) { - Response_P(PSTR("{")); - PrepShowTimer(index); - ResponseJsonEnd(); - } - } -} - -void CmndTimers(void) -{ - if (XdrvMailbox.data_len) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - Settings.flag3.timers_enable = XdrvMailbox.payload; - } - if (XdrvMailbox.payload == 2) { - Settings.flag3.timers_enable = !Settings.flag3.timers_enable; - } - } - - ResponseCmndStateText(Settings.flag3.timers_enable); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, XdrvMailbox.command); - - uint32_t jsflg = 0; - uint32_t lines = 1; - for (uint32_t i = 0; i < MAX_TIMERS; i++) { - if (!jsflg) { - Response_P(PSTR("{\"" D_CMND_TIMERS "%d\":{"), lines++); - } else { - ResponseAppend_P(PSTR(",")); - } - jsflg++; - PrepShowTimer(i +1); - if (jsflg > 3) { - ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_TIMERS)); - jsflg = 0; - } - } - mqtt_data[0] = '\0'; -} - -#ifdef USE_SUNRISE -void CmndLongitude(void) -{ - if (XdrvMailbox.data_len) { - Settings.longitude = (int)(CharToFloat(XdrvMailbox.data) *1000000); - } - ResponseCmndFloat((float)(Settings.longitude) /1000000, 6); -} - -void CmndLatitude(void) -{ - if (XdrvMailbox.data_len) { - Settings.latitude = (int)(CharToFloat(XdrvMailbox.data) *1000000); - } - ResponseCmndFloat((float)(Settings.latitude) /1000000, 6); -} -#endif - - - - - -#ifdef USE_WEBSERVER -#ifdef USE_TIMERS_WEB - -#define WEB_HANDLE_TIMER "tm" - -const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; - -const char HTTP_BTN_MENU_TIMER[] PROGMEM = - "

"; - -const char HTTP_TIMER_SCRIPT1[] PROGMEM = - "var pt=[],ct=99;" - "function ce(i,q){" - "var o=document.createElement('option');" - "o.textContent=i;" - "q.appendChild(o);" - "}"; -#ifdef USE_SUNRISE -const char HTTP_TIMER_SCRIPT2[] PROGMEM = - "function gt(){" - "var m,p,q;" - "m=qs('input[name=\"rd\"]:checked').value;" - "p=pt[ct]&0x7FF;" - "if(m==0){" - "so(0);" - "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" - "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" - "}" - "if((m==1)||(m==2)){" - "so(1);" - "q=Math.floor(p/60);" - "if(q>=12){q-=12;qs('#dr').selectedIndex=1;}" - "else{qs('#dr').selectedIndex=0;}" - "if(q<10){q='0'+q;}qs('#ho').value=q;" - "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" - "}" - "}" - "function so(b){" - "o=qs('#ho');" - "e=o.childElementCount;" - "if(b==1){" - "qs('#dr').style.visibility='';" - "if(e>12){for(i=12;i<=23;i++){o.removeChild(o.lastElementChild);}}" - "}else{" - "qs('#dr').style.visibility='hidden';" - "if(e<23){for(i=12;i<=23;i++){ce(i,o);}}" - "}" - "}"; -#endif -const char HTTP_TIMER_SCRIPT3[] PROGMEM = - "function st(){" - "var i,l,m,n,p,s;" - "m=0;s=0;" - "n=1<<31;if(eb('a0').checked){s|=n;}" - "n=1<<15;if(eb('r0').checked){s|=n;}" - "for(i=0;i<7;i++){n=1<<(16+i);if(eb('w'+i).checked){s|=n;}}" -#ifdef USE_SUNRISE - "m=qs('input[name=\"rd\"]:checked').value;" - "s|=(qs('input[name=\"rd\"]:checked').value<<29);" -#endif - "if(%d>0){" - "i=qs('#d1').selectedIndex;if(i>=0){s|=(i<<23);}" - "s|=(qs('#p1').selectedIndex<<27);" - "}else{" - "s|=3<<27;" - "}" - "l=((qs('#ho').selectedIndex*60)+qs('#mi').selectedIndex)&0x7FF;" - "if(m==0){s|=l;}" -#ifdef USE_SUNRISE - "if((m==1)||(m==2)){" - "if(qs('#dr').selectedIndex>0){if(l>0){l+=720;}}" - "s|=l&0x7FF;" - "}" -#endif - "s|=((qs('#mw').selectedIndex)&0x0F)<<11;" - "pt[ct]=s;" - "eb('t0').value=pt.join();" - "}"; -const char HTTP_TIMER_SCRIPT4[] PROGMEM = - "function ot(t,e){" - "var i,n,o,p,q,s;" - "if(ct<99){st();}" - "ct=t;" - "o=document.getElementsByClassName('tl');" - "for(i=0;i>29)&3;eb('b'+p).checked=1;" - "gt();" -#else - "p=s&0x7FF;" - "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" - "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" -#endif - "q=(s>>11)&0xF;if(q<10){q='0'+q;}qs('#mw').value=q;" - "for(i=0;i<7;i++){p=(s>>(16+i))&1;eb('w'+i).checked=p;}" - "if(%d>0){" - "p=(s>>23)&0xF;qs('#d1').value=p+1;" - "p=(s>>27)&3;qs('#p1').selectedIndex=p;" - "}" - "p=(s>>15)&1;eb('r0').checked=p;" - "p=(s>>31)&1;eb('a0').checked=p;" - "}"; -const char HTTP_TIMER_SCRIPT5[] PROGMEM = - "function it(){" - "var b,i,o,s;" - "pt=eb('t0').value.split(',').map(Number);" - "s='';" - "for(i=0;i<%d;i++){" - "b='';" - "if(0==i){b=\" id='dP'\";}" - "s+=\"\"" - "}" - "eb('bt').innerHTML=s;" - "if(%d>0){" - "eb('oa').innerHTML=\"" D_TIMER_OUTPUT " " D_TIMER_ACTION " \";" - "o=qs('#p1');ce('" D_OFF "',o);ce('" D_ON "',o);ce('" D_TOGGLE "',o);" -#if defined(USE_RULES) || defined(USE_SCRIPT) - "ce('" D_RULE "',o);" -#else - "ce('" D_BLINK "',o);" -#endif - "}else{" - "eb('oa').innerHTML=\"" D_TIMER_ACTION " " D_RULE "\";" - "}"; -const char HTTP_TIMER_SCRIPT6[] PROGMEM = -#ifdef USE_SUNRISE - "o=qs('#dr');ce('+',o);ce('-',o);" -#endif - "o=qs('#ho');for(i=0;i<=23;i++){ce((i<10)?('0'+i):i,o);}" - "o=qs('#mi');for(i=0;i<=59;i++){ce((i<10)?('0'+i):i,o);}" - "o=qs('#mw');for(i=0;i<=15;i++){ce((i<10)?('0'+i):i,o);}" - "o=qs('#d1');for(i=0;i<%d;i++){ce(i+1,o);}" - "var a='" D_DAY3LIST "';" - - - - "s='';for(i=0;i<7;i++){s+=\" \"}" - - "eb('ds').innerHTML=s;" - "eb('dP').click();" - "}" - "wl(it);"; -const char HTTP_TIMER_STYLE[] PROGMEM = - ".tl{float:left;border-radius:0;border:1px solid #%06x;padding:1px;width:6.25%%;}"; -const char HTTP_FORM_TIMER1[] PROGMEM = - "
" - " " D_TIMER_PARAMETERS " " - "
" - "



" - "



" - "

" - "
" - " " - "" - "

" - "
"; -#ifdef USE_SUNRISE -const char HTTP_FORM_TIMER3[] PROGMEM = - "
" - "
" - "
" - "
" - "
" - "

" - "" - " "; -#else -const char HTTP_FORM_TIMER3[] PROGMEM = - "" D_TIMER_TIME " "; -#endif -const char HTTP_FORM_TIMER4[] PROGMEM = - "" - " " D_HOUR_MINUTE_SEPARATOR " " - "" - " +/- " - "" - "

" - "
"; - -void HandleTimerConfiguration(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); - - if (Webserver->hasArg("save")) { - TimerSaveSettings(); - HandleConfiguration(); - return; - } - - WSContentStart_P(S_CONFIGURE_TIMER); - WSContentSend_P(HTTP_TIMER_SCRIPT1); -#ifdef USE_SUNRISE - WSContentSend_P(HTTP_TIMER_SCRIPT2); -#endif - WSContentSend_P(HTTP_TIMER_SCRIPT3, devices_present); - WSContentSend_P(HTTP_TIMER_SCRIPT4, WebColor(COL_TIMER_TAB_BACKGROUND), WebColor(COL_TIMER_TAB_TEXT), WebColor(COL_FORM), WebColor(COL_TEXT), devices_present); - WSContentSend_P(HTTP_TIMER_SCRIPT5, MAX_TIMERS, devices_present); - WSContentSend_P(HTTP_TIMER_SCRIPT6, devices_present); - WSContentSendStyle_P(HTTP_TIMER_STYLE, WebColor(COL_FORM)); - WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? " checked" : ""); - for (uint32_t i = 0; i < MAX_TIMERS; i++) { - WSContentSend_P(PSTR("%s%u"), (i > 0) ? "," : "", Settings.timer[i].data); - } - WSContentSend_P(HTTP_FORM_TIMER2); -#ifdef USE_SUNRISE - WSContentSend_P(HTTP_FORM_TIMER3, 100 + (strlen(D_SUNSET) *12), GetSun(0).c_str(), GetSun(1).c_str()); -#else - WSContentSend_P(HTTP_FORM_TIMER3); -#endif - WSContentSend_P(HTTP_FORM_TIMER4); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void TimerSaveSettings(void) -{ - char tmp[MAX_TIMERS *12]; - char message[LOGSZ]; - Timer timer; - - Settings.flag3.timers_enable = Webserver->hasArg("e0"); - WebGetArg("t0", tmp, sizeof(tmp)); - char *p = tmp; - snprintf_P(message, sizeof(message), PSTR(D_LOG_MQTT D_CMND_TIMERS " %d"), Settings.flag3.timers_enable); - for (uint32_t i = 0; i < MAX_TIMERS; i++) { - timer.data = strtol(p, &p, 10); - p++; - if (timer.time < 1440) { - bool flag = (timer.window != Settings.timer[i].window); - Settings.timer[i].data = timer.data; - if (flag) TimerSetRandomWindow(i); - } - snprintf_P(message, sizeof(message), PSTR("%s,0x%08X"), message, Settings.timer[i].data); - } - AddLog_P(LOG_LEVEL_DEBUG, message); -} -#endif -#endif - - - - - -bool Xdrv09(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_PRE_INIT: - TimerSetRandomWindows(); - break; -#ifdef USE_WEBSERVER -#ifdef USE_TIMERS_WEB - case FUNC_WEB_ADD_BUTTON: -#if defined(USE_RULES) || defined(USE_SCRIPT) - WSContentSend_P(HTTP_BTN_MENU_TIMER); -#else - if (devices_present) { WSContentSend_P(HTTP_BTN_MENU_TIMER); } -#endif - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration); - break; -#endif -#endif - case FUNC_EVERY_SECOND: - TimerEverySecond(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kTimerCommands, TimerCommand); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -#ifdef USE_RULES -#ifndef USE_SCRIPT -# 67 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -#define XDRV_10 10 - -#define D_CMND_RULE "Rule" -#define D_CMND_RULETIMER "RuleTimer" -#define D_CMND_EVENT "Event" -#define D_CMND_VAR "Var" -#define D_CMND_MEM "Mem" -#define D_CMND_ADD "Add" -#define D_CMND_SUB "Sub" -#define D_CMND_MULT "Mult" -#define D_CMND_SCALE "Scale" -#define D_CMND_CALC_RESOLUTION "CalcRes" -#define D_CMND_SUBSCRIBE "Subscribe" -#define D_CMND_UNSUBSCRIBE "Unsubscribe" -#define D_CMND_IF "If" - -#define D_JSON_INITIATED "Initiated" - -#define COMPARE_OPERATOR_NONE -1 -#define COMPARE_OPERATOR_EQUAL 0 -#define COMPARE_OPERATOR_BIGGER 1 -#define COMPARE_OPERATOR_SMALLER 2 -#define COMPARE_OPERATOR_EXACT_DIVISION 3 -#define COMPARE_OPERATOR_NUMBER_EQUAL 4 -#define COMPARE_OPERATOR_NOT_EQUAL 5 -#define COMPARE_OPERATOR_BIGGER_EQUAL 6 -#define COMPARE_OPERATOR_SMALLER_EQUAL 7 -#define MAXIMUM_COMPARE_OPERATOR COMPARE_OPERATOR_SMALLER_EQUAL -const char kCompareOperators[] PROGMEM = "=\0>\0<\0|\0==!=>=<="; - -#ifdef USE_EXPRESSION - #include - - const char kExpressionOperators[] PROGMEM = "+-*/%^\0"; - #define EXPRESSION_OPERATOR_ADD 0 - #define EXPRESSION_OPERATOR_SUBTRACT 1 - #define EXPRESSION_OPERATOR_MULTIPLY 2 - #define EXPRESSION_OPERATOR_DIVIDEDBY 3 - #define EXPRESSION_OPERATOR_MODULO 4 - #define EXPRESSION_OPERATOR_POWER 5 - - const uint8_t kExpressionOperatorsPriorities[] PROGMEM = {1, 1, 2, 2, 3, 4}; - #define MAX_EXPRESSION_OPERATOR_PRIORITY 4 - - - #define LOGIC_OPERATOR_AND 1 - #define LOGIC_OPERATOR_OR 2 - - #define IF_BLOCK_INVALID -1 - #define IF_BLOCK_ANY 0 - #define IF_BLOCK_ELSEIF 1 - #define IF_BLOCK_ELSE 2 - #define IF_BLOCK_ENDIF 3 -#endif - -const char kRulesCommands[] PROGMEM = "|" - D_CMND_RULE "|" D_CMND_RULETIMER "|" D_CMND_EVENT "|" D_CMND_VAR "|" D_CMND_MEM "|" - D_CMND_ADD "|" D_CMND_SUB "|" D_CMND_MULT "|" D_CMND_SCALE "|" D_CMND_CALC_RESOLUTION -#ifdef SUPPORT_MQTT_EVENT - "|" D_CMND_SUBSCRIBE "|" D_CMND_UNSUBSCRIBE -#endif -#ifdef SUPPORT_IF_STATEMENT - "|" D_CMND_IF -#endif - ; - -void (* const RulesCommand[])(void) PROGMEM = { - &CmndRule, &CmndRuleTimer, &CmndEvent, &CmndVariable, &CmndMemory, - &CmndAddition, &CmndSubtract, &CmndMultiply, &CmndScale, &CmndCalcResolution -#ifdef SUPPORT_MQTT_EVENT - , &CmndSubscribe, &CmndUnsubscribe -#endif -#ifdef SUPPORT_IF_STATEMENT - , &CmndIf -#endif - }; - -#ifdef SUPPORT_MQTT_EVENT - #include - typedef struct { - String Event; - String Topic; - String Key; - } MQTT_Subscription; - LinkedList subscriptions; -#endif - -struct RULES { - String event_value; - unsigned long timer[MAX_RULE_TIMERS] = { 0 }; - uint32_t triggers[MAX_RULE_SETS] = { 0 }; - uint8_t trigger_count[MAX_RULE_SETS] = { 0 }; - - long new_power = -1; - long old_power = -1; - long old_dimm = -1; - - uint16_t last_minute = 60; - uint16_t vars_event = 0; - uint8_t mems_event = 0; - bool teleperiod = false; - - char event_data[100]; -} Rules; - -char rules_vars[MAX_RULE_VARS][33] = {{ 0 }}; - -#if (MAX_RULE_VARS>16) -#error MAX_RULE_VARS is bigger than 16 -#endif -#if (MAX_RULE_MEMS>16) -#error MAX_RULE_MEMS is bigger than 16 -#endif - - - -bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule) -{ - - - - - bool match = false; - char stemp[10]; - - - int pos = rule.indexOf('#'); - if (pos == -1) { return false; } - - String rule_task = rule.substring(0, pos); - if (Rules.teleperiod) { - int ppos = rule_task.indexOf("TELE-"); - if (ppos == -1) { return false; } - rule_task = rule.substring(5, pos); - } - - String rule_expr = rule.substring(pos +1); - String rule_name, rule_param; - int8_t compareOperator = parseCompareExpression(rule_expr, rule_name, rule_param); - - char rule_svalue[80] = { 0 }; - float rule_value = 0; - if (compareOperator != COMPARE_OPERATOR_NONE) { - for (uint32_t i = 0; i < MAX_RULE_VARS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1); - if (rule_param.startsWith(stemp)) { - rule_param = rules_vars[i]; - break; - } - } - for (uint32_t i = 0; i < MAX_RULE_MEMS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%%MEM%d%%"), i +1); - if (rule_param.startsWith(stemp)) { - rule_param = SettingsText(SET_MEM1 + i); - break; - } - } - snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%")); - if (rule_param.startsWith(stemp)) { - rule_param = String(MinutesPastMidnight()); - } - snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%")); - if (rule_param.startsWith(stemp)) { - rule_param = String(MinutesUptime()); - } - snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%")); - if (rule_param.startsWith(stemp)) { - rule_param = GetDateAndTime(DT_LOCAL).c_str(); - } -#if defined(USE_TIMERS) && defined(USE_SUNRISE) - snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%")); - if (rule_param.startsWith(stemp)) { - rule_param = String(SunMinutes(0)); - } - snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%")); - if (rule_param.startsWith(stemp)) { - rule_param = String(SunMinutes(1)); - } -#endif - rule_param.toUpperCase(); - strlcpy(rule_svalue, rule_param.c_str(), sizeof(rule_svalue)); - - int temp_value = GetStateNumber(rule_svalue); - if (temp_value > -1) { - rule_value = temp_value; - } else { - rule_value = CharToFloat((char*)rule_svalue); - } - } - - - int rule_name_idx = 0; - if ((pos = rule_name.indexOf("[")) > 0) { - rule_name_idx = rule_name.substring(pos +1).toInt(); - if ((rule_name_idx < 1) || (rule_name_idx > 6)) { - rule_name_idx = 1; - } - rule_name = rule_name.substring(0, pos); - } - - StaticJsonBuffer<1024> jsonBuf; - JsonObject &root = jsonBuf.parseObject(event); - if (!root.success()) { return false; } - if (!root[rule_task].success()) { return false; } - - JsonObject &obj1 = root[rule_task]; - JsonObject *obj = &obj1; - String subtype; - uint32_t i = 0; - while ((pos = rule_name.indexOf("#")) > 0) { - subtype = rule_name.substring(0, pos); - if (!(*obj)[subtype].success()) { return false; } - JsonObject &obj2 = (*obj)[subtype]; - obj = &obj2; - rule_name = rule_name.substring(pos +1); - if (i++ > 10) { return false; } - } - if (!(*obj)[rule_name].success()) { return false; } - const char* str_value; - if (rule_name_idx) { - str_value = (*obj)[rule_name][rule_name_idx -1]; - } else { - str_value = (*obj)[rule_name]; - } - - - - - Rules.event_value = str_value; - - - float value = 0; - if (str_value) { - value = CharToFloat((char*)str_value); - int int_value = int(value); - int int_rule_value = int(rule_value); - switch (compareOperator) { - case COMPARE_OPERATOR_EXACT_DIVISION: - match = (int_rule_value && (int_value % int_rule_value) == 0); - break; - case COMPARE_OPERATOR_EQUAL: - match = (!strcasecmp(str_value, rule_svalue)); - break; - case COMPARE_OPERATOR_BIGGER: - match = (value > rule_value); - break; - case COMPARE_OPERATOR_SMALLER: - match = (value < rule_value); - break; - case COMPARE_OPERATOR_NUMBER_EQUAL: - match = (value == rule_value); - break; - case COMPARE_OPERATOR_NOT_EQUAL: - match = (value != rule_value); - break; - case COMPARE_OPERATOR_BIGGER_EQUAL: - match = (value >= rule_value); - break; - case COMPARE_OPERATOR_SMALLER_EQUAL: - match = (value <= rule_value); - break; - default: - match = true; - } - } else match = true; - - - - - if (bitRead(Settings.rule_once, rule_set)) { - if (match) { - if (!bitRead(Rules.triggers[rule_set], Rules.trigger_count[rule_set])) { - bitSet(Rules.triggers[rule_set], Rules.trigger_count[rule_set]); - } else { - match = false; - } - } else { - bitClear(Rules.triggers[rule_set], Rules.trigger_count[rule_set]); - } - } - - - - return match; -} -# 368 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -int8_t parseCompareExpression(String &expr, String &leftExpr, String &rightExpr) -{ - char compare_operator[3]; - int8_t compare = COMPARE_OPERATOR_NONE; - leftExpr = expr; - int position; - for (int8_t i = MAXIMUM_COMPARE_OPERATOR; i >= 0; i--) { - snprintf_P(compare_operator, sizeof(compare_operator), kCompareOperators + (i *2)); - if ((position = expr.indexOf(compare_operator)) > 0) { - compare = i; - leftExpr = expr.substring(0, position); - leftExpr.trim(); - rightExpr = expr.substring(position + strlen(compare_operator)); - rightExpr.trim(); - break; - } - } - return compare; -} - -void RulesVarReplace(String &commands, const String &sfind, const String &replace) -{ - - - - char *find = (char*)sfind.c_str(); - uint32_t flen = strlen(find); - - String ucommand = commands; - ucommand.toUpperCase(); - char *read_from = (char*)ucommand.c_str(); - char *write_to = (char*)commands.c_str(); - char *found_at; - while ((found_at = strstr(read_from, find)) != nullptr) { - write_to += (found_at - read_from); - memmove_P(write_to, find, flen); - write_to += flen; - read_from = found_at + flen; - } - - commands.replace(find, replace); -} - - - -bool RuleSetProcess(uint8_t rule_set, String &event_saved) -{ - bool serviced = false; - char stemp[10]; - - delay(0); - - - - String rules = Settings.rules[rule_set]; - - Rules.trigger_count[rule_set] = 0; - int plen = 0; - int plen2 = 0; - bool stop_all_rules = false; - while (true) { - rules = rules.substring(plen); - rules.trim(); - if (!rules.length()) { return serviced; } - - String rule = rules; - rule.toUpperCase(); - if (!rule.startsWith("ON ")) { return serviced; } - - int pevt = rule.indexOf(" DO "); - if (pevt == -1) { return serviced; } - String event_trigger = rule.substring(3, pevt); - - plen = rule.indexOf(" ENDON"); - plen2 = rule.indexOf(" BREAK"); - if ((plen == -1) && (plen2 == -1)) { return serviced; } - - if (plen == -1) { plen = 9999; } - if (plen2 == -1) { plen2 = 9999; } - plen = tmin(plen, plen2); - - String commands = rules.substring(pevt +4, plen); - Rules.event_value = ""; - String event = event_saved; - - - - if (RulesRuleMatch(rule_set, event, event_trigger)) { - if (plen == plen2) { stop_all_rules = true; } - commands.trim(); - String ucommand = commands; - ucommand.toUpperCase(); - - - - if ((ucommand.indexOf("IF ") == -1) && - (ucommand.indexOf("EVENT ") != -1) && - (ucommand.indexOf("BACKLOG ") == -1)) { - commands = "backlog " + commands; - } - - RulesVarReplace(commands, F("%VALUE%"), Rules.event_value); - for (uint32_t i = 0; i < MAX_RULE_VARS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%%VAR%d%%"), i +1); - RulesVarReplace(commands, stemp, rules_vars[i]); - } - for (uint32_t i = 0; i < MAX_RULE_MEMS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%%MEM%d%%"), i +1); - RulesVarReplace(commands, stemp, SettingsText(SET_MEM1 +i)); - } - RulesVarReplace(commands, F("%TIME%"), String(MinutesPastMidnight())); - RulesVarReplace(commands, F("%UTCTIME%"), String(UtcTime())); - RulesVarReplace(commands, F("%UPTIME%"), String(MinutesUptime())); - RulesVarReplace(commands, F("%TIMESTAMP%"), GetDateAndTime(DT_LOCAL)); - RulesVarReplace(commands, F("%TOPIC%"), SettingsText(SET_MQTT_TOPIC)); -#if defined(USE_TIMERS) && defined(USE_SUNRISE) - RulesVarReplace(commands, F("%SUNRISE%"), String(SunMinutes(0))); - RulesVarReplace(commands, F("%SUNSET%"), String(SunMinutes(1))); -#endif - - char command[commands.length() +1]; - strlcpy(command, commands.c_str(), sizeof(command)); - - AddLog_P2(LOG_LEVEL_INFO, PSTR("RUL: %s performs \"%s\""), event_trigger.c_str(), command); - - - -#ifdef SUPPORT_IF_STATEMENT - char *pCmd = command; - RulesPreprocessCommand(pCmd); -#endif - ExecuteCommand(command, SRC_RULE); - serviced = true; - if (stop_all_rules) { return serviced; } - } - plen += 6; - Rules.trigger_count[rule_set]++; - } - return serviced; -} - - - -bool RulesProcessEvent(char *json_event) -{ - bool serviced = false; - -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("RulesProcessEvent")); -#endif - - String event_saved = json_event; - - - - char *p = strchr(json_event, ':'); - if ((p != NULL) && !(strchr(++p, ':'))) { - event_saved.replace(F(":"), F(":{\"Data\":")); - event_saved += F("}"); - - } - event_saved.toUpperCase(); - - - - for (uint32_t i = 0; i < MAX_RULE_SETS; i++) { - if (strlen(Settings.rules[i]) && bitRead(Settings.rule_enabled, i)) { - if (RuleSetProcess(i, event_saved)) { serviced = true; } - } - } - return serviced; -} - -bool RulesProcess(void) -{ - return RulesProcessEvent(mqtt_data); -} - -void RulesInit(void) -{ - rules_flag.data = 0; - for (uint32_t i = 0; i < MAX_RULE_SETS; i++) { - if (Settings.rules[i][0] == '\0') { - bitWrite(Settings.rule_enabled, i, 0); - bitWrite(Settings.rule_once, i, 0); - } - } - Rules.teleperiod = false; -} - -void RulesEvery50ms(void) -{ - if (Settings.rule_enabled) { - char json_event[120]; - - if (-1 == Rules.new_power) { Rules.new_power = power; } - if (Rules.new_power != Rules.old_power) { - if (Rules.old_power != -1) { - for (uint32_t i = 0; i < devices_present; i++) { - uint8_t new_state = (Rules.new_power >> i) &1; - if (new_state != ((Rules.old_power >> i) &1)) { - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"State\":%d}}"), i +1, new_state); - RulesProcessEvent(json_event); - } - } - } else { - - for (uint32_t i = 0; i < devices_present; i++) { - uint8_t new_state = (Rules.new_power >> i) &1; - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"Boot\":%d}}"), i +1, new_state); - RulesProcessEvent(json_event); - } - - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { -#ifdef USE_TM1638 - if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) { -#else - if (pin[GPIO_SWT1 +i] < 99) { -#endif - snprintf_P(json_event, sizeof(json_event), PSTR("{\"" D_JSON_SWITCH "%d\":{\"Boot\":%d}}"), i +1, (SwitchState(i))); - RulesProcessEvent(json_event); - } - } - } - Rules.old_power = Rules.new_power; - } - else if (Rules.old_dimm != Settings.light_dimmer) { - if (Rules.old_dimm != -1) { - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Dimmer\":{\"State\":%d}}"), Settings.light_dimmer); - } else { - - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Dimmer\":{\"Boot\":%d}}"), Settings.light_dimmer); - } - RulesProcessEvent(json_event); - Rules.old_dimm = Settings.light_dimmer; - } - else if (Rules.event_data[0]) { - char *event; - char *parameter; - event = strtok_r(Rules.event_data, "=", ¶meter); - if (event) { - event = Trim(event); - if (parameter) { - parameter = Trim(parameter); - } else { - parameter = event + strlen(event); - } - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Event\":{\"%s\":\"%s\"}}"), event, parameter); - Rules.event_data[0] ='\0'; - RulesProcessEvent(json_event); - } else { - Rules.event_data[0] ='\0'; - } - } - else if (Rules.vars_event || Rules.mems_event){ - if (Rules.vars_event) { - for (uint32_t i = 0; i < MAX_RULE_VARS; i++) { - if (bitRead(Rules.vars_event, i)) { - bitClear(Rules.vars_event, i); - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Var%d\":{\"State\":%s}}"), i+1, rules_vars[i]); - RulesProcessEvent(json_event); - break; - } - } - } - if (Rules.mems_event) { - for (uint32_t i = 0; i < MAX_RULE_MEMS; i++) { - if (bitRead(Rules.mems_event, i)) { - bitClear(Rules.mems_event, i); - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Mem%d\":{\"State\":%s}}"), i+1, SettingsText(SET_MEM1 +i)); - RulesProcessEvent(json_event); - break; - } - } - } - } - else if (rules_flag.data) { - uint16_t mask = 1; - for (uint32_t i = 0; i < MAX_RULES_FLAG; i++) { - if (rules_flag.data & mask) { - rules_flag.data ^= mask; - json_event[0] = '\0'; - switch (i) { - case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break; - case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break; - case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break; - case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break; - case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break; - case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break; - case 6: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Disconnected\":1}}"), sizeof(json_event)); break; - case 7: strncpy_P(json_event, PSTR("{\"HTTP\":{\"Initialized\":1}}"), sizeof(json_event)); break; -#ifdef USE_SHUTTER - case 8: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moved\":1}}"), sizeof(json_event)); break; - case 9: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moving\":1}}"), sizeof(json_event)); break; -#endif - } - if (json_event[0]) { - RulesProcessEvent(json_event); - break; - } - } - mask <<= 1; - } - } - } -} - -uint8_t rules_xsns_index = 0; - -void RulesEvery100ms(void) -{ - if (Settings.rule_enabled && (uptime > 4)) { - mqtt_data[0] = '\0'; - int tele_period_save = tele_period; - tele_period = 2; - XsnsNextCall(FUNC_JSON_APPEND, rules_xsns_index); - tele_period = tele_period_save; - if (strlen(mqtt_data)) { - mqtt_data[0] = '{'; - ResponseJsonEnd(); - RulesProcess(); - } - } -} - -void RulesEverySecond(void) -{ - if (Settings.rule_enabled) { - char json_event[120]; - - if (RtcTime.valid) { - if ((uptime > 60) && (RtcTime.minute != Rules.last_minute)) { - Rules.last_minute = RtcTime.minute; - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), MinutesPastMidnight()); - RulesProcessEvent(json_event); - } - } - for (uint32_t i = 0; i < MAX_RULE_TIMERS; i++) { - if (Rules.timer[i] != 0L) { - if (TimeReached(Rules.timer[i])) { - Rules.timer[i] = 0L; - snprintf_P(json_event, sizeof(json_event), PSTR("{\"Rules\":{\"Timer\":%d}}"), i +1); - RulesProcessEvent(json_event); - } - } - } - } -} - -void RulesSaveBeforeRestart(void) -{ - if (Settings.rule_enabled) { - char json_event[32]; - - strncpy_P(json_event, PSTR("{\"System\":{\"Save\":1}}"), sizeof(json_event)); - RulesProcessEvent(json_event); - } -} - -void RulesSetPower(void) -{ - Rules.new_power = XdrvMailbox.index; -} - -void RulesTeleperiod(void) -{ - Rules.teleperiod = true; - RulesProcess(); - Rules.teleperiod = false; -} - -#ifdef SUPPORT_MQTT_EVENT -# 750 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool RulesMqttData(void) -{ - if (XdrvMailbox.data_len < 1 || XdrvMailbox.data_len > 256) { - return false; - } - bool serviced = false; - String sTopic = XdrvMailbox.topic; - String sData = XdrvMailbox.data; - - MQTT_Subscription event_item; - - for (uint32_t index = 0; index < subscriptions.size(); index++) { - event_item = subscriptions.get(index); - - - if (sTopic.startsWith(event_item.Topic)) { - - serviced = true; - String value; - if (event_item.Key.length() == 0) { - value = sData; - } else { - StaticJsonBuffer<500> jsonBuf; - JsonObject& jsonData = jsonBuf.parseObject(sData); - String key1 = event_item.Key; - String key2; - if (!jsonData.success()) break; - int dot; - if ((dot = key1.indexOf('.')) > 0) { - key2 = key1.substring(dot+1); - key1 = key1.substring(0, dot); - if (!jsonData[key1][key2].success()) break; - value = (const char *)jsonData[key1][key2]; - } else { - if (!jsonData[key1].success()) break; - value = (const char *)jsonData[key1]; - } - } - value.trim(); - - snprintf_P(Rules.event_data, sizeof(Rules.event_data), PSTR("%s=%s"), event_item.Event.c_str(), value.c_str()); - } - } - return serviced; -} -# 812 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -void CmndSubscribe(void) -{ - MQTT_Subscription subscription_item; - String events; - if (XdrvMailbox.data_len > 0) { - char parameters[XdrvMailbox.data_len+1]; - memcpy(parameters, XdrvMailbox.data, XdrvMailbox.data_len); - parameters[XdrvMailbox.data_len] = '\0'; - String event_name, topic, key; - - char * pos = strtok(parameters, ","); - if (pos) { - event_name = Trim(pos); - pos = strtok(nullptr, ","); - if (pos) { - topic = Trim(pos); - pos = strtok(nullptr, ","); - if (pos) { - key = Trim(pos); - } - } - } - - event_name.toUpperCase(); - if (event_name.length() > 0 && topic.length() > 0) { - - for (uint32_t index=0; index < subscriptions.size(); index++) { - if (subscriptions.get(index).Event.equals(event_name)) { - - String stopic = subscriptions.get(index).Topic + "/#"; - MqttUnsubscribe(stopic.c_str()); - subscriptions.remove(index); - break; - } - } - - if (!topic.endsWith("#")) { - if (topic.endsWith("/")) { - topic.concat("#"); - } else { - topic.concat("/#"); - } - } - - - subscription_item.Event = event_name; - subscription_item.Topic = topic.substring(0, topic.length() - 2); - subscription_item.Key = key; - subscriptions.add(subscription_item); - - MqttSubscribe(topic.c_str()); - events.concat(event_name + "," + topic - + (key.length()>0 ? "," : "") - + key); - } else { - events = D_JSON_WRONG_PARAMETERS; - } - } else { - - for (uint32_t index=0; index < subscriptions.size(); index++) { - subscription_item = subscriptions.get(index); - events.concat(subscription_item.Event + "," + subscription_item.Topic - + (subscription_item.Key.length()>0 ? "," : "") - + subscription_item.Key + "; "); - } - } - ResponseCmndChar(events.c_str()); -} -# 892 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -void CmndUnsubscribe(void) -{ - MQTT_Subscription subscription_item; - String events; - if (XdrvMailbox.data_len > 0) { - for (uint32_t index = 0; index < subscriptions.size(); index++) { - subscription_item = subscriptions.get(index); - if (subscription_item.Event.equalsIgnoreCase(XdrvMailbox.data)) { - String stopic = subscription_item.Topic + "/#"; - MqttUnsubscribe(stopic.c_str()); - events = subscription_item.Event; - subscriptions.remove(index); - break; - } - } - } else { - - String stopic; - while (subscriptions.size() > 0) { - events.concat(subscriptions.get(0).Event + "; "); - stopic = subscriptions.get(0).Topic + "/#"; - MqttUnsubscribe(stopic.c_str()); - subscriptions.remove(0); - } - } - ResponseCmndChar(events.c_str()); -} - -#endif - -#ifdef USE_EXPRESSION -# 934 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -char * findClosureBracket(char * pStart) -{ - char * pointer = pStart + 1; - - bool bFindClosures = false; - uint8_t matchClosures = 1; - while (*pointer) - { - if (*pointer == ')') { - matchClosures--; - if (matchClosures == 0) { - bFindClosures = true; - break; - } - } else if (*pointer == '(') { - matchClosures++; - } - pointer++; - } - if (bFindClosures) { - return pointer; - } else { - return nullptr; - } -} -# 973 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool findNextNumber(char * &pNumber, float &value) -{ - bool bSucceed = false; - String sNumber = ""; - if (*pNumber == '-') { - sNumber = "-"; - pNumber++; - } - while (*pNumber) { - if (isdigit(*pNumber) || (*pNumber == '.')) { - sNumber += *pNumber; - pNumber++; - } else { - break; - } - } - if (sNumber.length() > 0) { - value = CharToFloat(sNumber.c_str()); - bSucceed = true; - } - return bSucceed; -} -# 1009 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool findNextVariableValue(char * &pVarname, float &value) -{ - bool succeed = true; - value = 0; - String sVarName = ""; - while (*pVarname) { - if (isalpha(*pVarname) || isdigit(*pVarname)) { - sVarName.concat(*pVarname); - pVarname++; - } else { - break; - } - } - sVarName.toUpperCase(); - if (sVarName.startsWith(F("VAR"))) { - int index = sVarName.substring(3).toInt(); - if (index > 0 && index <= MAX_RULE_VARS) { - value = CharToFloat(rules_vars[index -1]); - } - } else if (sVarName.startsWith(F("MEM"))) { - int index = sVarName.substring(3).toInt(); - if (index > 0 && index <= MAX_RULE_MEMS) { - value = CharToFloat(SettingsText(SET_MEM1 + index -1)); - } - } else if (sVarName.equals(F("TIME"))) { - value = MinutesPastMidnight(); - } else if (sVarName.equals(F("UPTIME"))) { - value = MinutesUptime(); - } else if (sVarName.equals(F("UTCTIME"))) { - value = UtcTime(); - } else if (sVarName.equals(F("LOCALTIME"))) { - value = LocalTime(); -#if defined(USE_TIMERS) && defined(USE_SUNRISE) - } else if (sVarName.equals(F("SUNRISE"))) { - value = SunMinutes(0); - } else if (sVarName.equals(F("SUNSET"))) { - value = SunMinutes(1); -#endif - } else { - succeed = false; - } - - return succeed; -} -# 1071 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool findNextObjectValue(char * &pointer, float &value) -{ - bool bSucceed = false; - while (*pointer) - { - if (isspace(*pointer)) { - pointer++; - continue; - } - if (isdigit(*pointer) || (*pointer) == '-') { - bSucceed = findNextNumber(pointer, value); - break; - } else if (isalpha(*pointer)) { - bSucceed = findNextVariableValue(pointer, value); - break; - } else if (*pointer == '(') { - char * closureBracket = findClosureBracket(pointer); - if (closureBracket != nullptr) { - value = evaluateExpression(pointer+1, closureBracket - pointer - 1); - pointer = closureBracket + 1; - bSucceed = true; - } - break; - } else { - break; - } - } - return bSucceed; -} -# 1115 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool findNextOperator(char * &pointer, int8_t &op) -{ - bool bSucceed = false; - while (*pointer) - { - if (isspace(*pointer)) { - pointer++; - continue; - } - op = EXPRESSION_OPERATOR_ADD; - const char *pch = kExpressionOperators; - char ch; - while ((ch = pgm_read_byte(pch++)) != '\0') { - if (ch == *pointer) { - bSucceed = true; - pointer++; - break; - } - op++; - } - break; - } - return bSucceed; -} -# 1152 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -float calculateTwoValues(float v1, float v2, uint8_t op) -{ - switch (op) - { - case EXPRESSION_OPERATOR_ADD: - return v1 + v2; - case EXPRESSION_OPERATOR_SUBTRACT: - return v1 - v2; - case EXPRESSION_OPERATOR_MULTIPLY: - return v1 * v2; - case EXPRESSION_OPERATOR_DIVIDEDBY: - return (0 == v2) ? 0 : (v1 / v2); - case EXPRESSION_OPERATOR_MODULO: - return (0 == v2) ? 0 : (int(v1) % int(v2)); - case EXPRESSION_OPERATOR_POWER: - return FastPrecisePow(v1, v2); - } - return 0; -} -# 1205 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -float evaluateExpression(const char * expression, unsigned int len) -{ - char expbuf[len + 1]; - memcpy(expbuf, expression, len); - expbuf[len] = '\0'; - char * scan_pointer = expbuf; - - LinkedList object_values; - LinkedList operators; - int8_t op; - float va; - - if (findNextObjectValue(scan_pointer, va)) { - object_values.add(va); - } else { - return 0; - } - while (*scan_pointer) - { - if (findNextOperator(scan_pointer, op) - && *scan_pointer - && findNextObjectValue(scan_pointer, va)) - { - operators.add(op); - object_values.add(va); - } else { - - break; - } - } - - - - for (int32_t priority = MAX_EXPRESSION_OPERATOR_PRIORITY; priority>0; priority--) { - int index = 0; - while (index < operators.size()) { - if (priority == pgm_read_byte(kExpressionOperatorsPriorities + operators.get(index))) { - - va = calculateTwoValues(object_values.get(index), object_values.remove(index + 1), operators.remove(index)); - - object_values.set(index, va); - } else { - index++; - } - } - } - return object_values.get(0); -} -#endif - -#ifdef SUPPORT_IF_STATEMENT -void CmndIf(void) -{ - if (XdrvMailbox.data_len > 0) { - char parameters[XdrvMailbox.data_len+1]; - memcpy(parameters, XdrvMailbox.data, XdrvMailbox.data_len); - parameters[XdrvMailbox.data_len] = '\0'; - ProcessIfStatement(parameters); - } - ResponseCmndDone(); -} -# 1279 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool evaluateComparisonExpression(const char *expression, int len) -{ - bool bResult = true; - char expbuf[len + 1]; - memcpy(expbuf, expression, len); - expbuf[len] = '\0'; - String compare_expression = expbuf; - String leftExpr, rightExpr; - int8_t compareOp = parseCompareExpression(compare_expression, leftExpr, rightExpr); - - double leftValue = evaluateExpression(leftExpr.c_str(), leftExpr.length()); - double rightValue = evaluateExpression(rightExpr.c_str(), rightExpr.length()); - switch (compareOp) { - case COMPARE_OPERATOR_EXACT_DIVISION: - bResult = (rightValue != 0 && leftValue == int(leftValue) - && rightValue == int(rightValue) && (int(leftValue) % int(rightValue)) == 0); - break; - case COMPARE_OPERATOR_EQUAL: - bResult = leftExpr.equalsIgnoreCase(rightExpr); - break; - case COMPARE_OPERATOR_BIGGER: - bResult = (leftValue > rightValue); - break; - case COMPARE_OPERATOR_SMALLER: - bResult = (leftValue < rightValue); - break; - case COMPARE_OPERATOR_NUMBER_EQUAL: - bResult = (leftValue == rightValue); - break; - case COMPARE_OPERATOR_NOT_EQUAL: - bResult = (leftValue != rightValue); - break; - case COMPARE_OPERATOR_BIGGER_EQUAL: - bResult = (leftValue >= rightValue); - break; - case COMPARE_OPERATOR_SMALLER_EQUAL: - bResult = (leftValue <= rightValue); - break; - } - return bResult; -} -# 1335 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool findNextLogicOperator(char * &pointer, int8_t &op) -{ - bool bSucceed = false; - while (*pointer && isspace(*pointer)) { - - pointer++; - } - if (*pointer) { - if (strncasecmp_P(pointer, PSTR("AND "), 4) == 0) { - op = LOGIC_OPERATOR_AND; - pointer += 4; - bSucceed = true; - } else if (strncasecmp_P(pointer, PSTR("OR "), 3) == 0) { - op = LOGIC_OPERATOR_OR; - pointer += 3; - bSucceed = true; - } - } - return bSucceed; -} -# 1372 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool findNextLogicObjectValue(char * &pointer, bool &value) -{ - bool bSucceed = false; - while (*pointer && isspace(*pointer)) { - - pointer++; - } - char * pExpr = pointer; - while (*pointer) { - if (isalpha(*pointer) - && (strncasecmp_P(pointer, PSTR("AND "), 4) == 0 - || strncasecmp_P(pointer, PSTR("OR "), 3) == 0)) - { - value = evaluateComparisonExpression(pExpr, pointer - pExpr); - bSucceed = true; - break; - } else if (*pointer == '(') { - char * closureBracket = findClosureBracket(pointer); - if (closureBracket != nullptr) { - value = evaluateLogicalExpression(pointer+1, closureBracket - pointer - 1); - pointer = closureBracket + 1; - bSucceed = true; - } - break; - } - pointer++; - } - if (!bSucceed && pointer > pExpr) { - - value = evaluateComparisonExpression(pExpr, pointer - pExpr); - bSucceed = true; - } - return bSucceed; -} -# 1421 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -bool evaluateLogicalExpression(const char * expression, int len) -{ - bool bResult = false; - - char expbuff[len + 1]; - memcpy(expbuff, expression, len); - expbuff[len] = '\0'; - - - char * pointer = expbuff; - LinkedList values; - LinkedList logicOperators; - - bool bValue; - if (findNextLogicObjectValue(pointer, bValue)) { - values.add(bValue); - } else { - return false; - } - int8_t op; - while (*pointer) { - if (findNextLogicOperator(pointer, op) - && (*pointer) && findNextLogicObjectValue(pointer, bValue)) - { - logicOperators.add(op); - values.add(bValue); - } else { - break; - } - } - - int index = 0; - while (index < logicOperators.size()) { - if (logicOperators.get(index) == LOGIC_OPERATOR_AND) { - values.set(index, values.get(index) && values.get(index+1)); - values.remove(index + 1); - logicOperators.remove(index); - } else { - index++; - } - } - - index = 0; - while (index < logicOperators.size()) { - if (logicOperators.get(index) == LOGIC_OPERATOR_OR) { - values.set(index, values.get(index) || values.get(index+1)); - values.remove(index + 1); - logicOperators.remove(index); - } else { - index++; - } - } - return values.get(0); -} -# 1492 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -int8_t findIfBlock(char * &pointer, int &lenWord, int8_t block_type) -{ - int8_t foundBlock = IF_BLOCK_INVALID; - - const char * word; - while (*pointer) { - if (!isalpha(*pointer)) { - pointer++; - continue; - } - word = pointer; - while (*pointer && isalpha(*pointer)) { - pointer++; - } - lenWord = pointer - word; - - if (2 == lenWord && 0 == strncasecmp_P(word, PSTR("IF"), 2)) { - - - if (findIfBlock(pointer, lenWord, IF_BLOCK_ENDIF) != IF_BLOCK_ENDIF) { - - break; - } - } else if ( (IF_BLOCK_ENDIF == block_type || IF_BLOCK_ANY == block_type) - && (5 == lenWord) && (0 == strncasecmp_P(word, PSTR("ENDIF"), 5))) - { - - foundBlock = IF_BLOCK_ENDIF; - break; - } else if ( (IF_BLOCK_ELSEIF == block_type || IF_BLOCK_ANY == block_type) - && (6 == lenWord) && (0 == strncasecmp_P(word, PSTR("ELSEIF"), 6))) - { - - foundBlock = IF_BLOCK_ELSEIF; - break; - } else if ( (IF_BLOCK_ELSE == block_type || IF_BLOCK_ANY == block_type) - && (4 == lenWord) && (0 == strncasecmp_P(word, PSTR("ELSE"), 4))) - { - - foundBlock = IF_BLOCK_ELSE; - break; - } - } - return foundBlock; -} -# 1549 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -void ExecuteCommandBlock(const char * commands, int len) -{ - char cmdbuff[len + 1]; - memcpy(cmdbuff, commands, len); - cmdbuff[len] = '\0'; - - - char oneCommand[len + 1]; - int insertPosition = 0; - char * pos = cmdbuff; - int lenEndBlock = 0; - while (*pos) { - if (isspace(*pos) || '\x1e' == *pos || ';' == *pos) { - pos++; - continue; - } - if (strncasecmp_P(pos, PSTR("BACKLOG "), 8) == 0) { - - pos += 8; - continue; - } - if (strncasecmp_P(pos, PSTR("IF "), 3) == 0) { - - - char *pEndif = pos + 3; - if (IF_BLOCK_ENDIF != findIfBlock(pEndif, lenEndBlock, IF_BLOCK_ENDIF)) { - - break; - } - - memcpy(oneCommand, pos, pEndif - pos); - oneCommand[pEndif - pos] = '\0'; - pos = pEndif; - } else { - - char *pEndOfCommand = strpbrk(pos, "\x1e;"); - if (NULL == pEndOfCommand) { - pEndOfCommand = pos + strlen(pos); - } - memcpy(oneCommand, pos, pEndOfCommand - pos); - oneCommand[pEndOfCommand - pos] = '\0'; - pos = pEndOfCommand; - } - - - String sCurrentCommand = oneCommand; - sCurrentCommand.trim(); - if (sCurrentCommand.length() > 0 - && backlog.size() < MAX_BACKLOG && !backlog_mutex) - { - - backlog_mutex = true; - backlog.add(insertPosition, sCurrentCommand); - backlog_mutex = false; - insertPosition++; - } - } - return; -} -# 1619 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -void ProcessIfStatement(const char* statements) -{ - String conditionExpression; - int len = strlen(statements); - char statbuff[len + 1]; - memcpy(statbuff, statements, len + 1); - char *pos = statbuff; - int lenEndBlock = 0; - while (true) { - - - while (*pos && *pos != '(') { - pos++; - } - if (0 == *pos) { break; } - char * posEnd = findClosureBracket(pos); - - if (true == evaluateLogicalExpression(pos + 1, posEnd - (pos + 1))) { - - char * cmdBlockStart = posEnd + 1; - char * cmdBlockEnd = cmdBlockStart; - int8_t nextBlock = findIfBlock(cmdBlockEnd, lenEndBlock, IF_BLOCK_ANY); - if (IF_BLOCK_INVALID == nextBlock) { - - break; - } - ExecuteCommandBlock(cmdBlockStart, cmdBlockEnd - cmdBlockStart - lenEndBlock); - pos = cmdBlockEnd; - break; - } else { - pos = posEnd + 1; - int8_t nextBlock = findIfBlock(pos, lenEndBlock, IF_BLOCK_ANY); - if (IF_BLOCK_ELSEIF == nextBlock) { - - continue; - } else if (IF_BLOCK_ELSE == nextBlock) { - - char * cmdBlockEnd = pos; - int8_t nextBlock = findIfBlock(cmdBlockEnd, lenEndBlock, IF_BLOCK_ENDIF); - if (IF_BLOCK_ENDIF != nextBlock) { - - break; - } - ExecuteCommandBlock(pos, cmdBlockEnd - pos - lenEndBlock); - break; - } else { - - break; - } - } - } -} -# 1683 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_rules.ino" -void RulesPreprocessCommand(char *pCommands) -{ - char * cmd = pCommands; - int lenEndBlock = 0; - while (*cmd) { - - if (';' == *cmd || isspace(*cmd)) { - cmd++; - } - else if (strncasecmp_P(cmd, PSTR("IF "), 3) == 0) { - - char * pIfStart = cmd; - char * pIfEnd = pIfStart + 3; - - if (IF_BLOCK_ENDIF == findIfBlock(pIfEnd, lenEndBlock, IF_BLOCK_ENDIF)) { - - cmd = pIfEnd; - - - while (pIfStart < pIfEnd) { - if (';' == *pIfStart) - *pIfStart = '\x1e'; - pIfStart++; - } - } - else { - break; - } - } - else { - while (*cmd && ';' != *cmd) { - cmd++; - } - } - } - return; -} -#endif - - - - - -void CmndRule(void) -{ - uint8_t index = XdrvMailbox.index; - if ((index > 0) && (index <= MAX_RULE_SETS)) { - if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.rules[index -1]))) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 10)) { - switch (XdrvMailbox.payload) { - case 0: - case 1: - bitWrite(Settings.rule_enabled, index -1, XdrvMailbox.payload); - break; - case 2: - bitWrite(Settings.rule_enabled, index -1, bitRead(Settings.rule_enabled, index -1) ^1); - break; - case 4: - case 5: - bitWrite(Settings.rule_once, index -1, XdrvMailbox.payload &1); - break; - case 6: - bitWrite(Settings.rule_once, index -1, bitRead(Settings.rule_once, index -1) ^1); - break; - case 8: - case 9: - bitWrite(Settings.rule_stop, index -1, XdrvMailbox.payload &1); - break; - case 10: - bitWrite(Settings.rule_stop, index -1, bitRead(Settings.rule_stop, index -1) ^1); - break; - } - } else { - int offset = 0; - if ('+' == XdrvMailbox.data[0]) { - offset = strlen(Settings.rules[index -1]); - if (XdrvMailbox.data_len < (sizeof(Settings.rules[index -1]) - offset -1)) { - XdrvMailbox.data[0] = ' '; - } else { - offset = -1; - } - } - if (offset != -1) { - strlcpy(Settings.rules[index -1] + offset, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.rules[index -1])); - } - } - Rules.triggers[index -1] = 0; - } - snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Free\":%d,\"Rules\":\"%s\"}"), - XdrvMailbox.command, index, GetStateText(bitRead(Settings.rule_enabled, index -1)), GetStateText(bitRead(Settings.rule_once, index -1)), - GetStateText(bitRead(Settings.rule_stop, index -1)), sizeof(Settings.rules[index -1]) - strlen(Settings.rules[index -1]) -1, Settings.rules[index -1]); - } -} - -void CmndRuleTimer(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_TIMERS)) { - if (XdrvMailbox.data_len > 0) { -#ifdef USE_EXPRESSION - float timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len); - Rules.timer[XdrvMailbox.index -1] = (timer_set > 0) ? millis() + (1000 * timer_set) : 0; -#else - Rules.timer[XdrvMailbox.index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; -#endif - } - mqtt_data[0] = '\0'; - for (uint32_t i = 0; i < MAX_RULE_TIMERS; i++) { - ResponseAppend_P(PSTR("%c\"T%d\":%d"), (i) ? ',' : '{', i +1, (Rules.timer[i]) ? (Rules.timer[i] - millis()) / 1000 : 0); - } - ResponseJsonEnd(); - } -} - -void CmndEvent(void) -{ - if (XdrvMailbox.data_len > 0) { - strlcpy(Rules.event_data, XdrvMailbox.data, sizeof(Rules.event_data)); - } - ResponseCmndDone(); -} - -void CmndVariable(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) { - if (!XdrvMailbox.usridx) { - mqtt_data[0] = '\0'; - for (uint32_t i = 0; i < MAX_RULE_VARS; i++) { - ResponseAppend_P(PSTR("%c\"Var%d\":\"%s\""), (i) ? ',' : '{', i +1, rules_vars[i]); - } - ResponseJsonEnd(); - } else { - if (XdrvMailbox.data_len > 0) { -#ifdef USE_EXPRESSION - if (XdrvMailbox.data[0] == '=') { - dtostrfd(evaluateExpression(XdrvMailbox.data + 1, XdrvMailbox.data_len - 1), Settings.flag2.calc_resolution, rules_vars[XdrvMailbox.index -1]); - } else { - strlcpy(rules_vars[XdrvMailbox.index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(rules_vars[XdrvMailbox.index -1])); - } -#else - strlcpy(rules_vars[XdrvMailbox.index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(rules_vars[XdrvMailbox.index -1])); -#endif - bitSet(Rules.vars_event, XdrvMailbox.index -1); - } - ResponseCmndIdxChar(rules_vars[XdrvMailbox.index -1]); - } - } -} - -void CmndMemory(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_MEMS)) { - if (!XdrvMailbox.usridx) { - ResponseCmndAll(SET_MEM1, MAX_RULE_MEMS); - } else { - if (XdrvMailbox.data_len > 0) { -#ifdef USE_EXPRESSION - if (XdrvMailbox.data[0] == '=') { - dtostrfd(evaluateExpression(XdrvMailbox.data + 1, XdrvMailbox.data_len - 1), Settings.flag2.calc_resolution, SettingsText(SET_MEM1 + XdrvMailbox.index -1)); - } else { - SettingsUpdateText(SET_MEM1 + XdrvMailbox.index -1, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data); - } -#else - SettingsUpdateText(SET_MEM1 + XdrvMailbox.index -1, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data); -#endif - bitSet(Rules.mems_event, XdrvMailbox.index -1); - } - ResponseCmndIdxChar(SettingsText(SET_MEM1 + XdrvMailbox.index -1)); - } - } -} - -void CmndCalcResolution(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 7)) { - Settings.flag2.calc_resolution = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.flag2.calc_resolution); -} - -void CmndAddition(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) { - if (XdrvMailbox.data_len > 0) { - float tempvar = CharToFloat(rules_vars[XdrvMailbox.index -1]) + CharToFloat(XdrvMailbox.data); - dtostrfd(tempvar, Settings.flag2.calc_resolution, rules_vars[XdrvMailbox.index -1]); - bitSet(Rules.vars_event, XdrvMailbox.index -1); - } - ResponseCmndIdxChar(rules_vars[XdrvMailbox.index -1]); - } -} - -void CmndSubtract(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) { - if (XdrvMailbox.data_len > 0) { - float tempvar = CharToFloat(rules_vars[XdrvMailbox.index -1]) - CharToFloat(XdrvMailbox.data); - dtostrfd(tempvar, Settings.flag2.calc_resolution, rules_vars[XdrvMailbox.index -1]); - bitSet(Rules.vars_event, XdrvMailbox.index -1); - } - ResponseCmndIdxChar(rules_vars[XdrvMailbox.index -1]); - } -} - -void CmndMultiply(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) { - if (XdrvMailbox.data_len > 0) { - float tempvar = CharToFloat(rules_vars[XdrvMailbox.index -1]) * CharToFloat(XdrvMailbox.data); - dtostrfd(tempvar, Settings.flag2.calc_resolution, rules_vars[XdrvMailbox.index -1]); - bitSet(Rules.vars_event, XdrvMailbox.index -1); - } - ResponseCmndIdxChar(rules_vars[XdrvMailbox.index -1]); - } -} - -void CmndScale(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) { - if (XdrvMailbox.data_len > 0) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { - char sub_string[XdrvMailbox.data_len +1]; - - float valueIN = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 1)); - float fromLow = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)); - float fromHigh = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 3)); - float toLow = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)); - float toHigh = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 5)); - float value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh); - dtostrfd(value, Settings.flag2.calc_resolution, rules_vars[XdrvMailbox.index -1]); - bitSet(Rules.vars_event, XdrvMailbox.index -1); - } - } - ResponseCmndIdxChar(rules_vars[XdrvMailbox.index -1]); - } -} - -float map_double(float x, float in_min, float in_max, float out_min, float out_max) -{ - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - - - - - -bool Xdrv10(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_50_MSECOND: - RulesEvery50ms(); - break; - case FUNC_EVERY_100_MSECOND: - RulesEvery100ms(); - break; - case FUNC_EVERY_SECOND: - RulesEverySecond(); - break; - case FUNC_SET_POWER: - RulesSetPower(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kRulesCommands, RulesCommand); - break; - case FUNC_RULES_PROCESS: - result = RulesProcess(); - break; - case FUNC_SAVE_BEFORE_RESTART: - RulesSaveBeforeRestart(); - break; -#ifdef SUPPORT_MQTT_EVENT - case FUNC_MQTT_DATA: - result = RulesMqttData(); - break; -#endif - case FUNC_PRE_INIT: - RulesInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -#ifdef USE_SCRIPT -#ifndef USE_RULES -# 41 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -#define XDRV_10 10 -#define XI2C_37 37 - -#define SCRIPT_DEBUG 0 - - -#ifndef MAXVARS -#define MAXVARS 50 -#endif -#ifndef MAXSVARS -#define MAXSVARS 5 -#endif -#define MAXNVARS MAXVARS-MAXSVARS - -#define MAXFILT 5 -#define SCRIPT_SVARSIZE 20 -#define SCRIPT_MAXSSIZE 48 -#define SCRIPT_EOL '\n' -#define SCRIPT_FLOAT_PRECISION 2 -#define PMEM_SIZE sizeof(Settings.script_pram) -#define SCRIPT_MAXPERM (PMEM_SIZE)-4/sizeof(float) -#define MAX_SCRIPT_SIZE MAX_RULE_SIZE*MAX_RULE_SETS - - -uint32_t EncodeLightId(uint8_t relay_id); -uint32_t DecodeLightId(uint32_t hue_id); - -#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS) - -#include "FS.h" -#include "SPIFFS.h" -void SaveFile(const char *name,const uint8_t *buf,uint32_t len) { - File file = SPIFFS.open(name, FILE_WRITE); - if (!file) return; - file.write(buf, len); - file.close(); -} - -#define FORMAT_SPIFFS_IF_FAILED true -uint8_t spiffs_mounted=0; - -void LoadFile(const char *name,uint8_t *buf,uint32_t len) { - if (!spiffs_mounted) { - if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){ - - return; - } - spiffs_mounted=1; - } - File file = SPIFFS.open(name); - if (!file) return; - file.read(buf, len); - file.close(); -} -#endif - - -#define EPOCH_OFFSET 1546300800 - -enum {OPER_EQU=1,OPER_PLS,OPER_MIN,OPER_MUL,OPER_DIV,OPER_PLSEQU,OPER_MINEQU,OPER_MULEQU,OPER_DIVEQU,OPER_EQUEQU,OPER_NOTEQU,OPER_GRTEQU,OPER_LOWEQU,OPER_GRT,OPER_LOW,OPER_PERC,OPER_XOR,OPER_AND,OPER_OR,OPER_ANDEQU,OPER_OREQU,OPER_XOREQU,OPER_PERCEQU}; -enum {SCRIPT_LOGLEVEL=1,SCRIPT_TELEPERIOD}; - -#ifdef USE_SCRIPT_FATFS -#include -#include -#ifndef FAT_SCRIPT_SIZE -#define FAT_SCRIPT_SIZE 4096 -#endif -#define FAT_SCRIPT_NAME "script.txt" -#if USE_LONG_FILE_NAMES==1 -#warning ("FATFS long filenames not supported"); -#endif -#if USE_STANDARD_SPI_LIBRARY==0 -#warning ("FATFS standard spi should be used"); -#endif -#endif - -#ifdef SUPPORT_MQTT_EVENT - #include - typedef struct { - String Event; - String Topic; - String Key; - } MQTT_Subscription; - LinkedList subscriptions; -#endif - -#ifdef USE_DISPLAY -#ifdef USE_TOUCH_BUTTONS -#include -extern VButton *buttons[MAXBUTTONS]; -#endif -#endif - -typedef union { - uint8_t data; - struct { - uint8_t is_string : 1; - uint8_t is_permanent : 1; - uint8_t is_timer : 1; - uint8_t is_autoinc : 1; - uint8_t changed : 1; - uint8_t settable : 1; - uint8_t is_filter : 1; - uint8_t constant : 1; - }; -} SCRIPT_TYPE; - -struct T_INDEX { - uint8_t index; - SCRIPT_TYPE bits; -}; - -struct M_FILT { - uint8_t numvals; - uint8_t index; - float maccu; - float rbuff[1]; -}; - -typedef union { - uint8_t data; - struct { - uint8_t nutu8 : 1; - uint8_t nutu7 : 1; - uint8_t nutu6 : 1; - uint8_t nutu5 : 1; - uint8_t nutu4 : 1; - uint8_t nutu3 : 1; - uint8_t is_dir : 1; - uint8_t is_open : 1; - }; -} FILE_FLAGS; - -#define SFS_MAX 4 - -struct SCRIPT_MEM { - float *fvars; - float *s_fvars; - struct T_INDEX *type; - struct M_FILT *mfilt; - char *glob_vnp; - uint8_t *vnp_offset; - char *glob_snp; - char *scriptptr; - char *section_ptr; - char *scriptptr_bu; - char *script_ram; - uint16_t script_size; - uint8_t *script_pram; - uint16_t script_pram_size; - uint8_t numvars; - void *script_mem; - uint16_t script_mem_size; - uint8_t script_dprec; - uint8_t var_not_found; - uint8_t glob_error; - uint8_t max_ssize; - uint8_t script_loglevel; - uint8_t flags; -#ifdef USE_SCRIPT_FATFS - File files[SFS_MAX]; - FILE_FLAGS file_flags[SFS_MAX]; - uint8_t script_sd_found; - char flink[2][14]; -#endif -} glob_script_mem; - - -int16_t last_findex; -uint8_t tasm_cmd_activ=0; -uint8_t fast_script=0; -uint32_t script_lastmillis; - - -#ifdef USE_BUTTON_EVENT -int8_t script_button[MAX_KEYS]; -#endif - -char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo); -char *GetStringResult(char *lp,uint8_t lastop,char *cp,JsonObject *jo); -char *ForceStringVar(char *lp,char *dstr); -void send_download(void); -uint8_t reject(char *name); - -void ScriptEverySecond(void) { - - if (bitRead(Settings.rule_enabled, 0)) { - struct T_INDEX *vtp=glob_script_mem.type; - float delta=(millis()-script_lastmillis)/1000; - script_lastmillis=millis(); - for (uint8_t count=0; count0) { - - *fp-=delta; - if (*fp<0) *fp=0; - } - } - if (vtp[count].bits.is_autoinc) { - - float *fp=&glob_script_mem.fvars[vtp[count].index]; - if (*fp>=0) { - *fp+=delta; - } - } - } - Run_Scripter(">S",2,0); - } -} - -void RulesTeleperiod(void) { - if (bitRead(Settings.rule_enabled, 0) && mqtt_data[0]) Run_Scripter(">T",2, mqtt_data); -} - - -#ifdef USE_24C256 -#ifndef USE_SCRIPT_FATFS - -#include -#define EEPROM_ADDRESS 0x50 - -#ifndef EEP_SCRIPT_SIZE -#define EEP_SCRIPT_SIZE 4095 -#endif - - -static Eeprom24C128_256 eeprom(EEPROM_ADDRESS); - -#define EEP_WRITE(A,B,C) eeprom.writeBytes(A,B,(uint8_t*)C); - -#define EEP_READ(A,B,C) eeprom.readBytes(A,B,(uint8_t*)C); -#endif -#endif - -#define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++; -#define SCRIPT_SKIP_EOL while (*lp==SCRIPT_EOL) lp++; - - -int16_t Init_Scripter(void) { -char *script; - - script=glob_script_mem.script_ram; - - - uint16_t lines=0,nvars=0,svars=0,vars=0; - char *lp=script; - char vnames[MAXVARS*10]; - char *vnames_p=vnames; - char *vnp[MAXVARS]; - char **vnp_p=vnp; - char strings[MAXSVARS*SCRIPT_MAXSSIZE]; - struct M_FILT mfilt[MAXFILT]; - - char *strings_p=strings; - char *snp[MAXSVARS]; - char **snp_p=snp; - uint8_t numperm=0,numflt=0,count; - - glob_script_mem.max_ssize=SCRIPT_SVARSIZE; - glob_script_mem.scriptptr=0; - - if (!*script) return -999; - - float fvalues[MAXVARS]; - struct T_INDEX vtypes[MAXVARS]; - char init=0; - while (1) { - - - SCRIPT_SKIP_SPACES - - if (*lp=='\n' || *lp=='\r') goto next_line; - - if (*lp==';') goto next_line; - if (init) { - - if (*lp=='>') { - init=0; - break; - } - char *op=strchr(lp,'='); - if (op) { - vtypes[vars].bits.data=0; - - if (*lp=='p' && *(lp+1)==':') { - lp+=2; - if (numpermMAXFILT) { - return -6; - } - } else { - vtypes[vars].bits.is_filter=0; - } - *vnp_p++=vnames_p; - while (lpMAXNVARS) { - return -1; - } - if (vtypes[vars].bits.is_filter) { - while (isdigit(*op) || *op=='.' || *op=='-') { - op++; - } - while (*op==' ') op++; - if (isdigit(*op)) { - - uint8_t flen=atoi(op); - mfilt[numflt-1].numvals&=0x80; - mfilt[numflt-1].numvals|=flen&0x7f; - } - } - - } else { - - op++; - *snp_p++=strings_p; - while (*op!='\"') { - if (*op==SCRIPT_EOL) break; - *strings_p++=*op++; - } - *strings_p++=0; - vtypes[vars].bits.is_string=1; - vtypes[vars].index=svars; - svars++; - if (svars>MAXSVARS) { - return -2; - } - } - vars++; - if (vars>MAXVARS) { - return -3; - } - } - } else { - if (!strncmp(lp,">D",2)) { - lp+=2; - SCRIPT_SKIP_SPACES - if (isdigit(*lp)) { - uint8_t ssize=atoi(lp)+1; - if (ssize<10 || ssize>SCRIPT_MAXSSIZE) ssize=SCRIPT_MAXSSIZE; - glob_script_mem.max_ssize=ssize; - } - init=1; - } - } - - next_line: - lp = strchr(lp, SCRIPT_EOL); - if (!lp) break; - lp++; - } - - uint16_t fsize=0; - for (count=0; count255) { - free(glob_script_mem.script_mem); - return -5; - } - } - - AddLog_P2(LOG_LEVEL_INFO, PSTR("Script: nv=%d, tv=%d, vns=%d, ram=%d"), nvars, svars, index, glob_script_mem.script_mem_size); - - - char *cp1=glob_script_mem.glob_snp; - char *sp=strings; - for (count=0; countnumvals=mfilt[count].numvals; - mp+=sizeof(struct M_FILT)+((mfilt[count].numvals&0x7f)-1)*sizeof(float); - } - - glob_script_mem.numvars=vars; - glob_script_mem.script_dprec=SCRIPT_FLOAT_PRECISION; - glob_script_mem.script_loglevel=LOG_LEVEL_INFO; - - -#if SCRIPT_DEBUG>2 - struct T_INDEX *dvtp=glob_script_mem.type; - for (uint8_t count=0; count0 - ClaimSerial(); - SetSerialBaudrate(9600); -#endif - - - glob_script_mem.scriptptr=lp-1; - glob_script_mem.scriptptr_bu=glob_script_mem.scriptptr; - return 0; - -} - -#ifdef USE_LIGHT -#ifdef USE_WS2812 -void ws2812_set_array(float *array ,uint8_t len) { - - Ws2812ForceSuspend(); - for (uint8_t cnt=0;cntSettings.light_pixels) break; - uint32_t col=array[cnt]; - Ws2812SetColor(cnt+1,col>>16,col>>8,col,0); - } - Ws2812ForceUpdate(); -} -#endif -#endif - -#define NUM_RES 0xfe -#define STR_RES 0xfd -#define VAR_NV 0xff - -#define NTYPE 0 -#define STYPE 0x80 - -#ifndef FLT_MAX -#define FLT_MAX 99999999 -#endif - -float median_array(float *array,uint8_t len) { - uint8_t ind[len]; - uint8_t mind=0,index=0,flg; - float min=FLT_MAX; - - for (uint8_t hcnt=0; hcntnumvals&0x7f; - return mflp->rbuff; - } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); - } - return 0; -} - - -float Get_MFVal(uint8_t index,uint8_t bind) { - uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; - for (uint8_t count=0; countnumvals&0x7f; - if (!bind) { - return mflp->index; - } - if (bind<1 || bind>maxind) bind=maxind; - return mflp->rbuff[bind-1]; - } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); - } - return 0; -} - -void Set_MFVal(uint8_t index,uint8_t bind,float val) { - uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; - for (uint8_t count=0; countnumvals&0x7f; - if (!bind) { - mflp->index=val; - } else { - if (bind<1 || bind>maxind) bind=maxind; - mflp->rbuff[bind-1]=val; - } - return; - } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); - } -} - - -float Get_MFilter(uint8_t index) { - uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; - for (uint8_t count=0; countnumvals&0x80) { - - return mflp->maccu/(mflp->numvals&0x7f); - } else { - - return median_array(mflp->rbuff,mflp->numvals); - } - } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); - } - return 0; -} - -void Set_MFilter(uint8_t index, float invar) { - uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; - for (uint8_t count=0; countnumvals&0x80) { - - mflp->maccu-=mflp->rbuff[mflp->index]; - mflp->maccu+=invar; - mflp->rbuff[mflp->index]=invar; - mflp->index++; - if (mflp->index>=(mflp->numvals&0x7f)) mflp->index=0; - } else { - - mflp->rbuff[mflp->index]=invar; - mflp->index++; - if (mflp->index>=mflp->numvals) mflp->index=0; - } - break; - } - mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); - } -} - -#define MEDIAN_SIZE 5 -#define MEDIAN_FILTER_NUM 2 - -struct MEDIAN_FILTER { -float buffer[MEDIAN_SIZE]; -int8_t index; -} script_mf[MEDIAN_FILTER_NUM]; - -float DoMedian5(uint8_t index, float in) { - - if (index>=MEDIAN_FILTER_NUM) index=0; - - struct MEDIAN_FILTER* mf=&script_mf[index]; - mf->buffer[mf->index]=in; - mf->index++; - if (mf->index>=MEDIAN_SIZE) mf->index=0; - return median_array(mf->buffer,MEDIAN_SIZE); -} - -#ifdef USE_LIGHT - -uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value) { -float r = 0, g = 0, b = 0; -struct HSV { - float H; - float S; - float V; -} hsv; - -hsv.H=hue; -hsv.S=(float)saturation/100.0; -hsv.V=(float)value/100.0; - -if (hsv.S == 0) { - r = hsv.V; - g = hsv.V; - b = hsv.V; - } else { - int i; - float f, p, q, t; - - if (hsv.H == 360) - hsv.H = 0; - else - hsv.H = hsv.H / 60; - - i = (int)trunc(hsv.H); - f = hsv.H - i; - - p = hsv.V * (1.0 - hsv.S); - q = hsv.V * (1.0 - (hsv.S * f)); - t = hsv.V * (1.0 - (hsv.S * (1.0 - f))); - - switch (i) - { - case 0: - r = hsv.V; - g = t; - b = p; - break; - - case 1: - r = q; - g = hsv.V; - b = p; - break; - - case 2: - r = p; - g = hsv.V; - b = t; - break; - - case 3: - r = p; - g = q; - b = hsv.V; - break; - - case 4: - r = t; - g = p; - b = hsv.V; - break; - - default: - r = hsv.V; - g = p; - b = q; - break; - } - - } - - uint8_t ir,ig,ib; - ir=r*255; - ig=g*255; - ib=b*255; - - uint32_t rgb=(ir<<16)|(ig<<8)|ib; - return rgb; -} -#endif - - - - -char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,JsonObject *jo) { - uint16_t count,len=0; - uint8_t nres=0; - char vname[32]; - float fvar=0; - tind->index=0; - tind->bits.data=0; - - if (isdigit(*lp) || (*lp=='-' && isdigit(*(lp+1))) || *lp=='.') { - - if (fp) { - if (*lp=='0' && *(lp+1)=='x') { - lp+=2; - *fp=strtol(lp,0,16); - } else { - *fp=CharToFloat(lp); - } - } - if (*lp=='-') lp++; - while (isdigit(*lp) || *lp=='.') { - if (*lp==0 || *lp==SCRIPT_EOL) break; - lp++; - } - tind->bits.constant=1; - tind->bits.is_string=0; - *vtype=NUM_RES; - return lp; - } - if (*lp=='"') { - lp++; - while (*lp!='"') { - if (*lp==0 || *lp==SCRIPT_EOL) break; - uint8_t iob=*lp; - if (iob=='\\') { - lp++; - if (*lp=='t') { - iob='\t'; - } else if (*lp=='n') { - iob='\n'; - } else if (*lp=='r') { - iob='\r'; - } else if (*lp=='\\') { - iob='\\'; - } else { - lp--; - } - if (sp) *sp++=iob; - } else { - if (sp) *sp++=iob; - } - lp++; - } - if (sp) *sp=0; - *vtype=STR_RES; - tind->bits.constant=1; - tind->bits.is_string=1; - return lp+1; - } - - if (*lp=='-') { - - nres=1; - lp++; - } - - const char *term="\n\r ])=+-/*%>index=VAR_NV; - glob_script_mem.var_not_found=1; - return lp; - } - - struct T_INDEX *vtp=glob_script_mem.type; - char dvnam[32]; - strcpy (dvnam,vname); - uint8_t olen=len; - last_findex=-1; - char *ja=strchr(dvnam,'['); - if (ja) { - *ja=0; - ja++; - olen=strlen(dvnam); - } - for (count=0; countindex=count; - if (vtp[count].bits.is_string==0) { - *vtype=NTYPE|index; - if (vtp[count].bits.is_filter) { - if (ja) { - lp+=olen+1; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - last_findex=fvar; - fvar=Get_MFVal(index,fvar); - len=1; - } else { - fvar=Get_MFilter(index); - } - } else { - fvar=glob_script_mem.fvars[index]; - } - if (nres) fvar=-fvar; - if (fp) *fp=fvar; - } else { - *vtype=STYPE|index; - if (sp) strlcpy(sp,glob_script_mem.glob_snp+(index*glob_script_mem.max_ssize),SCRIPT_MAXSSIZE); - } - return lp+len; - } - } - } - - if (jo) { - - const char* str_value; - uint8_t aindex; - String vn; - char *ja=strchr(vname,'['); - if (ja) { - - *ja=0; - ja++; - - float fvar; - GetNumericResult(ja,OPER_EQU,&fvar,0); - aindex=fvar; - if (aindex<1 || aindex>6) aindex=1; - aindex--; - } - if (jo->success()) { - char *subtype=strchr(vname,'#'); - char *subtype2; - if (subtype) { - *subtype=0; - subtype++; - subtype2=strchr(subtype,'#'); - if (subtype2) { - *subtype2=0; - *subtype2++; - } - } - vn=vname; - str_value = (*jo)[vn]; - if ((*jo)[vn].success()) { - if (subtype) { - JsonObject &jobj1=(*jo)[vn]; - if (jobj1.success()) { - vn=subtype; - jo=&jobj1; - str_value = (*jo)[vn]; - if ((*jo)[vn].success()) { - - if (subtype2) { - JsonObject &jobj2=(*jo)[vn]; - if ((*jo)[vn].success()) { - vn=subtype2; - jo=&jobj2; - str_value = (*jo)[vn]; - if ((*jo)[vn].success()) { - goto skip; - } else { - goto chknext; - } - } else { - goto chknext; - } - } - - goto skip; - } - } else { - goto chknext; - } - } - skip: - if (ja) { - - str_value = (*jo)[vn][aindex]; - } - if (str_value && *str_value) { - if ((*jo).is(vn)) { - if (!strncmp(str_value,"ON",2)) { - if (fp) *fp=1; - goto nexit; - } else if (!strncmp(str_value,"OFF",3)) { - if (fp) *fp=0; - goto nexit; - } else { - *vtype=STR_RES; - tind->bits.constant=1; - tind->bits.is_string=1; - if (sp) strlcpy(sp,str_value,SCRIPT_MAXSSIZE); - return lp+len; - } - - } else { - if (fp) { - if (!strncmp(vn.c_str(),"Epoch",5)) { - *fp=atoi(str_value)-(uint32_t)EPOCH_OFFSET; - } else { - *fp=CharToFloat((char*)str_value); - } - } - nexit: - *vtype=NUM_RES; - tind->bits.constant=1; - tind->bits.is_string=0; - return lp+len; - } - } - } - } - } - -chknext: - switch (vname[0]) { - case 'a': -#ifdef USE_ANGLE_FUNC - if (!strncmp(vname,"acos(",5)) { - lp+=5; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - fvar=acosf(fvar); - lp++; - len=0; - goto exit; - } -#endif - break; - - case 'b': - if (!strncmp(vname,"boot",4)) { - if (rules_flag.system_boot) { - rules_flag.system_boot=0; - fvar=1; - } - goto exit; - } -#ifdef USE_BUTTON_EVENT - if (!strncmp(vname,"bt[",3)) { - - GetNumericResult(vname+3,OPER_EQU,&fvar,0); - uint32_t index=fvar; - if (index<1 || index>MAX_KEYS) index=1; - fvar=script_button[index-1]; - script_button[index-1]|=0x80; - len++; - goto exit; - } -#endif - break; - case 'c': - if (!strncmp(vname,"chg[",4)) { - - struct T_INDEX ind; - uint8_t vtype; - isvar(vname+4,&vtype,&ind,0,0,0); - if (!ind.bits.constant) { - uint8_t index=glob_script_mem.type[ind.index].index; - if (glob_script_mem.fvars[index]!=glob_script_mem.s_fvars[index]) { - - glob_script_mem.s_fvars[index]=glob_script_mem.fvars[index]; - fvar=1; - len++; - goto exit; - } else { - fvar=0; - len++; - goto exit; - } - } - } - break; - case 'd': - if (!strncmp(vname,"day",3)) { - fvar=RtcTime.day_of_month; - goto exit; - } - break; - case 'e': - if (!strncmp(vname,"epoch",5)) { - fvar=UtcTime()-(uint32_t)EPOCH_OFFSET; - goto exit; - } - break; -#ifdef USE_SCRIPT_FATFS - case 'f': - if (!strncmp(vname,"fo(",3)) { - lp+=3; - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - while (*lp==' ') lp++; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - uint8_t mode=fvar; - fvar=-1; - for (uint8_t cnt=0;cnt=SFS_MAX) ind=SFS_MAX-1; - glob_script_mem.files[ind].close(); - glob_script_mem.file_flags[ind].is_open=0; - fvar=0; - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"ff(",3)) { - lp+=3; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - uint8_t ind=fvar; - if (ind>=SFS_MAX) ind=SFS_MAX-1; - glob_script_mem.files[ind].flush(); - fvar=0; - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"fw(",3)) { - lp+=3; - char str[SCRIPT_MAXSSIZE]; - lp=ForceStringVar(lp,str); - while (*lp==' ') lp++; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - uint8_t ind=fvar; - if (ind>=SFS_MAX) ind=SFS_MAX-1; - if (glob_script_mem.file_flags[ind].is_open) { - fvar=glob_script_mem.files[ind].print(str); - } else { - fvar=0; - } - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"fr(",3)) { - lp+=3; - struct T_INDEX ind; - uint8_t vtype; - uint8_t sindex=0; - lp=isvar(lp,&vtype,&ind,0,0,0); - if (vtype!=VAR_NV) { - - if ((vtype&STYPE)==0) { - - fvar=0; - goto exit; - } else { - - sindex=glob_script_mem.type[ind.index].index; - } - } else { - - fvar=0; - goto exit; - } - while (*lp==' ') lp++; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - uint8_t find=fvar; - if (find>=SFS_MAX) find=SFS_MAX-1; - uint8_t index=0; - char str[glob_script_mem.max_ssize+1]; - char *cp=str; - if (glob_script_mem.file_flags[find].is_open) { - if (glob_script_mem.file_flags[find].is_dir) { - while (true) { - File entry=glob_script_mem.files[find].openNextFile(); - if (entry) { - if (!reject((char*)entry.name())) { - strcpy(str,entry.name()); - entry.close(); - break; - } - } else { - *cp=0; - break; - } - entry.close(); - } - index=strlen(str); - } else { - while (glob_script_mem.files[find].available()) { - uint8_t buf[1]; - glob_script_mem.files[find].read(buf,1); - if (buf[0]=='\t' || buf[0]==',' || buf[0]=='\n' || buf[0]=='\r') { - break; - } else { - *cp++=buf[0]; - index++; - if (index>=glob_script_mem.max_ssize-1) break; - } - } - *cp=0; - } - } else { - strcpy(str,"file error"); - } - lp++; - strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize); - fvar=index; - len=0; - goto exit; - } - if (!strncmp(vname,"fd(",3)) { - lp+=3; - char str[glob_script_mem.max_ssize+1]; - lp=GetStringResult(lp,OPER_EQU,str,0); - SD.remove(str); - lp++; - len=0; - goto exit; - } -#ifdef USE_SCRIPT_FATFS_EXT - if (!strncmp(vname,"fe(",3)) { - lp+=3; - char str[glob_script_mem.max_ssize+1]; - lp=GetStringResult(lp,OPER_EQU,str,0); - - File ef=SD.open(str); - if (ef) { - uint16_t fsiz=ef.size(); - if (fsiz<2048) { - char *script=(char*)calloc(fsiz+16,1); - if (script) { - ef.read((uint8_t*)script,fsiz); - execute_script(script); - free(script); - fvar=1; - } - } - ef.close(); - } - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"fmd(",4)) { - lp+=4; - char str[glob_script_mem.max_ssize+1]; - lp=GetStringResult(lp,OPER_EQU,str,0); - fvar=SD.mkdir(str); - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"frd(",4)) { - lp+=4; - char str[glob_script_mem.max_ssize+1]; - lp=GetStringResult(lp,OPER_EQU,str,0); - fvar=SD.rmdir(str); - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"fx(",3)) { - lp+=3; - char str[glob_script_mem.max_ssize+1]; - lp=GetStringResult(lp,OPER_EQU,str,0); - if (SD.exists(str)) fvar=1; - else fvar=0; - lp++; - len=0; - goto exit; - } -#endif - if (!strncmp(vname,"fl1(",4) || !strncmp(vname,"fl2(",4) ) { - uint8_t lknum=*(lp+2)&3; - lp+=4; - char str[glob_script_mem.max_ssize+1]; - lp=GetStringResult(lp,OPER_EQU,str,0); - if (lknum<1 || lknum>2) lknum=1; - strlcpy(glob_script_mem.flink[lknum-1],str,14); - lp++; - fvar=0; - len=0; - goto exit; - } - if (!strncmp(vname,"fsm",3)) { - fvar=glob_script_mem.script_sd_found; - - goto exit; - } - break; - -#endif - case 'g': - if (!strncmp(vname,"gtmp",4)) { - fvar=global_temperature; - goto exit; - } - if (!strncmp(vname,"ghum",4)) { - fvar=global_humidity; - goto exit; - } - if (!strncmp(vname,"gprs",4)) { - fvar=global_pressure; - goto exit; - } - if (!strncmp(vname,"gtopic",6)) { - if (sp) strlcpy(sp,SettingsText(SET_MQTT_GRP_TOPIC),glob_script_mem.max_ssize); - goto strexit; - } - break; - case 'h': - if (!strncmp(vname,"hours",5)) { - fvar=RtcTime.hour; - goto exit; - } - if (!strncmp(vname,"heap",4)) { - fvar=ESP.getFreeHeap(); - goto exit; - } - if (!strncmp(vname,"hn(",3)) { - lp=GetNumericResult(lp+3,OPER_EQU,&fvar,0); - if (fvar<0 || fvar>255) fvar=0; - lp++; - len=0; - if (sp) { - sprintf(sp,"%02x",(uint8_t)fvar); - } - goto strexit; - } - if (!strncmp(vname,"hx(",3)) { - lp=GetNumericResult(lp+3,OPER_EQU,&fvar,0); - lp++; - len=0; - if (sp) { - sprintf(sp,"%08x",(uint32_t)fvar); - } - goto strexit; - } -#ifdef USE_LIGHT - - if (!strncmp(vname,"hsvrgb(",7)) { - lp=GetNumericResult(lp+7,OPER_EQU,&fvar,0); - if (fvar<0 || fvar>360) fvar=0; - SCRIPT_SKIP_SPACES - - float fvar2; - lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); - if (fvar2<0 || fvar2>100) fvar2=0; - SCRIPT_SKIP_SPACES - - float fvar3; - lp=GetNumericResult(lp,OPER_EQU,&fvar3,0); - if (fvar3<0 || fvar3>100) fvar3=0; - - fvar=HSVToRGB(fvar,fvar2,fvar3); - - lp++; - len=0; - goto exit; - } - -#endif - break; - case 'i': - if (!strncmp(vname,"int(",4)) { - lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0); - fvar=floor(fvar); - lp++; - len=0; - goto exit; - } - break; - case 'l': - if (!strncmp(vname,"loglvl",6)) { - fvar=glob_script_mem.script_loglevel; - tind->index=SCRIPT_LOGLEVEL; - exit_settable: - if (fp) *fp=fvar; - *vtype=NTYPE; - tind->bits.settable=1; - tind->bits.is_string=0; - return lp+len; - } - break; - case 'm': - if (!strncmp(vname,"med(",4)) { - float fvar1; - lp=GetNumericResult(lp+4,OPER_EQU,&fvar1,0); - SCRIPT_SKIP_SPACES - - float fvar2; - lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); - fvar=DoMedian5(fvar1,fvar2); - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"micros",6)) { - fvar=micros(); - goto exit; - } - if (!strncmp(vname,"millis",6)) { - fvar=millis(); - goto exit; - } - if (!strncmp(vname,"mins",4)) { - fvar=RtcTime.minute; - goto exit; - } - if (!strncmp(vname,"month",5)) { - fvar=RtcTime.month; - goto exit; - } - if (!strncmp(vname,"mqttc",5)) { - if (rules_flag.mqtt_connected) { - rules_flag.mqtt_connected=0; - fvar=1; - } - goto exit; - } - if (!strncmp(vname,"mqttd",5)) { - if (rules_flag.mqtt_disconnected) { - rules_flag.mqtt_disconnected=0; - fvar=1; - } - goto exit; - } - if (!strncmp(vname,"mqtts",5)) { - fvar=!global_state.mqtt_down; - goto exit; - } - if (!strncmp(vname,"mp(",3)) { - lp+=3; - float fvar1; - lp=GetNumericResult(lp,OPER_EQU,&fvar1,0); - SCRIPT_SKIP_SPACES - while (*lp!=')') { - char *opp=lp; - lp++; - float fvar2; - lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); - SCRIPT_SKIP_SPACES - fvar=fvar1; - if ((*opp=='<' && fvar1' && fvar1>fvar2) || - (*opp=='=' && fvar1==fvar2)) - { - if (*lp!='<' && *lp!='>' && *lp!='=' && *lp!=')' && *lp!=SCRIPT_EOL) { - float fvar3; - lp=GetNumericResult(lp,OPER_EQU,&fvar3,0); - SCRIPT_SKIP_SPACES - fvar=fvar3; - } else { - fvar=fvar2; - } - break; - } - while (*lp!='<' && *lp!='>' && *lp!='=' && *lp!=')' && *lp!=SCRIPT_EOL) lp++; - } - len=0; - goto exit; - } - break; - case 'p': - if (!strncmp(vname,"pin[",4)) { - - GetNumericResult(vname+4,OPER_EQU,&fvar,0); - fvar=digitalRead((uint8_t)fvar); - - len++; - goto exit; - } - if (!strncmp(vname,"pn[",3)) { - GetNumericResult(vname+3,OPER_EQU,&fvar,0); - fvar=pin[(uint8_t)fvar]; - - len++; - goto exit; - } - if (!strncmp(vname,"pd[",3)) { - GetNumericResult(vname+3,OPER_EQU,&fvar,0); - uint8_t gpiopin=fvar; - for (uint8_t i=0;iMAX_COUNTERS) index=1; - fvar=RtcSettings.pulse_counter[index-1]; - len+=1; - goto exit; - } - break; - - case 'r': - if (!strncmp(vname,"ram",3)) { - fvar=glob_script_mem.script_mem_size+(glob_script_mem.script_size)+(PMEM_SIZE); - goto exit; - } - break; - case 's': - if (!strncmp(vname,"secs",4)) { - fvar=RtcTime.second; - goto exit; - } - if (!strncmp(vname,"sw[",3)) { - - GetNumericResult(vname+3,OPER_EQU,&fvar,0); - fvar=SwitchLastState((uint32_t)fvar); - - len++; - goto exit; - } - if (!strncmp(vname,"stack",5)) { - fvar=GetStack(); - goto exit; - } - if (!strncmp(vname,"slen",4)) { - fvar=strlen(glob_script_mem.script_ram); - goto exit; - } - if (!strncmp(vname,"sl(",3)) { - lp+=3; - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - lp++; - len=0; - fvar=strlen(str); - goto exit; - } - if (!strncmp(vname,"sb(",3)) { - lp+=3; - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - SCRIPT_SKIP_SPACES - float fvar1; - lp=GetNumericResult(lp,OPER_EQU,&fvar1,0); - SCRIPT_SKIP_SPACES - float fvar2; - lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); - lp++; - len=0; - if (fvar1<0) { - fvar1=strlen(str)+fvar1; - } - memcpy(sp,&str[(uint8_t)fvar1],(uint8_t)fvar2); - sp[(uint8_t)fvar2] = '\0'; - goto strexit; - } - if (!strncmp(vname,"st(",3)) { - lp+=3; - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - while (*lp==' ') lp++; - char token[2]; - token[0]=*lp++; - token[1]=0; - while (*lp==' ') lp++; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - - lp++; - len=0; - if (sp) { - - char *st=strtok(str,token); - if (!st) { - *sp=0; - } else { - for (uint8_t cnt=1; cnt<=fvar; cnt++) { - if (cnt==fvar) { - strcpy(sp,st); - break; - } - st=strtok(NULL,token); - if (!st) { - *sp=0; - break; - } - } - } - } - goto strexit; - } - if (!strncmp(vname,"s(",2)) { - lp+=2; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - char str[glob_script_mem.max_ssize+1]; - dtostrfd(fvar,glob_script_mem.script_dprec,str); - if (sp) strlcpy(sp,str,glob_script_mem.max_ssize); - lp++; - len=0; - goto strexit; - } -#if defined(USE_TIMERS) && defined(USE_SUNRISE) - if (!strncmp(vname,"sunrise",7)) { - fvar=SunMinutes(0); - goto exit; - } - if (!strncmp(vname,"sunset",6)) { - fvar=SunMinutes(1); - goto exit; - } -#endif - -#ifdef USE_SHUTTER - if (!strncmp(vname,"sht[",4)) { - GetNumericResult(vname+4,OPER_EQU,&fvar,0); - uint8_t index=fvar; - if (index<=shutters_present) { - fvar=Settings.shutter_position[index-1]; - } else { - fvar=-1; - } - len+=1; - goto exit; - } -#endif -#ifdef USE_ANGLE_FUNC - if (!strncmp(vname,"sin(",4)) { - lp+=4; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - fvar=sinf(fvar); - lp++; - len=0; - goto exit; - } - if (!strncmp(vname,"sqrt(",5)) { - lp+=5; - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - fvar=sqrtf(fvar); - lp++; - len=0; - goto exit; - } -#endif -#ifdef USE_SML_SCRIPT_CMD - if (!strncmp(vname,"sml(",4)) { - lp+=4; - float fvar1; - lp=GetNumericResult(lp,OPER_EQU,&fvar1,0); - SCRIPT_SKIP_SPACES - float fvar2; - lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); - SCRIPT_SKIP_SPACES - if (fvar2==0) { - float fvar3; - lp=GetNumericResult(lp,OPER_EQU,&fvar3,0); - fvar=SML_SetBaud(fvar1,fvar3); - } else if (fvar2==1) { - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - fvar=SML_Write(fvar1,str); - } else { -#ifdef ED300L - fvar=SML_Status(fvar1); -#else - fvar=0; -#endif - } - lp++; - len=0; - goto exit; - } -#endif - break; - case 't': - if (!strncmp(vname,"time",4)) { - fvar=MinutesPastMidnight(); - goto exit; - } - if (!strncmp(vname,"tper",4)) { - fvar=Settings.tele_period; - tind->index=SCRIPT_TELEPERIOD; - goto exit_settable; - } - if (!strncmp(vname,"tinit",5)) { - if (rules_flag.time_init) { - rules_flag.time_init=0; - fvar=1; - } - goto exit; - } - if (!strncmp(vname,"tset",4)) { - if (rules_flag.time_set) { - rules_flag.time_set=0; - fvar=1; - } - goto exit; - } - if (!strncmp(vname,"tstamp",6)) { - if (sp) strlcpy(sp,GetDateAndTime(DT_LOCAL).c_str(),glob_script_mem.max_ssize); - goto strexit; - } - if (!strncmp(vname,"topic",5)) { - if (sp) strlcpy(sp,SettingsText(SET_MQTT_TOPIC),glob_script_mem.max_ssize); - goto strexit; - } -#ifdef USE_DISPLAY -#ifdef USE_TOUCH_BUTTONS - if (!strncmp(vname,"tbut[",5)) { - GetNumericResult(vname+5,OPER_EQU,&fvar,0); - uint8_t index=fvar; - if (index<1 || index>MAXBUTTONS) index=1; - index--; - if (buttons[index]) { - fvar=buttons[index]->vpower&0x80; - } else { - fvar=-1; - } - len+=1; - goto exit; - } - -#endif -#endif - break; - case 'u': - if (!strncmp(vname,"uptime",6)) { - fvar=MinutesUptime(); - goto exit; - } - if (!strncmp(vname,"upsecs",6)) { - fvar=uptime; - goto exit; - } - if (!strncmp(vname,"upd[",4)) { - - struct T_INDEX ind; - uint8_t vtype; - isvar(vname+4,&vtype,&ind,0,0,0); - if (!ind.bits.constant) { - if (!ind.bits.changed) { - fvar=0; - len++; - goto exit; - } else { - glob_script_mem.type[ind.index].bits.changed=0; - fvar=1; - len++; - goto exit; - } - } - goto notfound; - } - break; - - case 'w': - if (!strncmp(vname,"wday",4)) { - fvar=RtcTime.day_of_week; - goto exit; - } - if (!strncmp(vname,"wific",5)) { - if (rules_flag.wifi_connected) { - rules_flag.wifi_connected=0; - fvar=1; - } - goto exit; - } - if (!strncmp(vname,"wifid",5)) { - if (rules_flag.wifi_disconnected) { - rules_flag.wifi_disconnected=0; - fvar=1; - } - goto exit; - } - if (!strncmp(vname,"wifis",5)) { - fvar=!global_state.wifi_down; - goto exit; - } - break; - case 'y': - if (!strncmp(vname,"year",4)) { - fvar=RtcTime.year; - goto exit; - } - break; - default: - break; - } - -notfound: - if (fp) *fp=0; - *vtype=VAR_NV; - tind->index=VAR_NV; - glob_script_mem.var_not_found=1; - return lp; - -exit: - if (fp) *fp=fvar; - *vtype=NUM_RES; - tind->bits.constant=1; - tind->bits.is_string=0; - return lp+len; - -strexit: - *vtype=STYPE; - tind->bits.constant=1; - tind->bits.is_string=1; - return lp+len; -} - - - -char *getop(char *lp, uint8_t *operand) { - switch (*lp) { - case '=': - if (*(lp+1)=='=') { - *operand=OPER_EQUEQU; - return lp+2; - } else { - *operand=OPER_EQU; - return lp+1; - } - break; - case '+': - if (*(lp+1)=='=') { - *operand=OPER_PLSEQU; - return lp+2; - } else { - *operand=OPER_PLS; - return lp+1; - } - break; - case '-': - if (*(lp+1)=='=') { - *operand=OPER_MINEQU; - return lp+2; - } else { - *operand=OPER_MIN; - return lp+1; - } - break; - case '*': - if (*(lp+1)=='=') { - *operand=OPER_MULEQU; - return lp+2; - } else { - *operand=OPER_MUL; - return lp+1; - } - break; - case '/': - if (*(lp+1)=='=') { - *operand=OPER_DIVEQU; - return lp+2; - } else { - *operand=OPER_DIV; - return lp+1; - } - break; - case '!': - if (*(lp+1)=='=') { - *operand=OPER_NOTEQU; - return lp+2; - } - break; - case '>': - if (*(lp+1)=='=') { - *operand=OPER_GRTEQU; - return lp+2; - } else { - *operand=OPER_GRT; - return lp+1; - - } - break; - case '<': - if (*(lp+1)=='=') { - *operand=OPER_LOWEQU; - return lp+2; - } else { - *operand=OPER_LOW; - return lp+1; - } - break; - case '%': - if (*(lp+1)=='=') { - *operand=OPER_PERCEQU; - return lp+2; - } else { - *operand=OPER_PERC; - return lp+1; - } - break; - case '^': - if (*(lp+1)=='=') { - *operand=OPER_XOREQU; - return lp+2; - } else { - *operand=OPER_XOR; - return lp+1; - } - break; - case '&': - if (*(lp+1)=='=') { - *operand=OPER_ANDEQU; - return lp+2; - } else { - *operand=OPER_AND; - return lp+1; - } - break; - case '|': - if (*(lp+1)=='=') { - *operand=OPER_OREQU; - return lp+2; - } else { - *operand=OPER_OR; - return lp+1; - } - break; - } - *operand=0; - return lp; -} - - -#ifdef ESP8266 -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) - - -extern "C" { -#include - extern cont_t g_cont; -} -uint16_t GetStack(void) { - register uint32_t *sp asm("a1"); - return (4 * (sp - g_cont.stack)); -} - -#else -extern "C" { -#include - extern cont_t* g_pcont; -} -uint16_t GetStack(void) { - register uint32_t *sp asm("a1"); - return (4 * (sp - g_pcont->stack)); -} -#endif -#else -uint16_t GetStack(void) { - register uint8_t *sp asm("a1"); - return (sp - pxTaskGetStackStart(NULL)); -} -#endif - -char *GetStringResult(char *lp,uint8_t lastop,char *cp,JsonObject *jo) { - uint8_t operand=0; - uint8_t vtype; - char *slp; - struct T_INDEX ind; - char str[SCRIPT_MAXSSIZE],str1[SCRIPT_MAXSSIZE]; - while (1) { - lp=isvar(lp,&vtype,&ind,0,str1,jo); - if (vtype!=STR_RES && !(vtype&STYPE)) { - - glob_script_mem.glob_error=1; - return lp; - } - switch (lastop) { - case OPER_EQU: - strlcpy(str,str1,sizeof(str)); - break; - case OPER_PLS: - strncat(str,str1,sizeof(str)); - break; - } - slp=lp; - lp=getop(lp,&operand); - switch (operand) { - case OPER_EQUEQU: - case OPER_NOTEQU: - case OPER_LOW: - case OPER_LOWEQU: - case OPER_GRT: - case OPER_GRTEQU: - lp=slp; - strcpy(cp,str); - return lp; - break; - default: - break; - } - lastop=operand; - if (!operand) { - strcpy(cp,str); - return lp; - } - } -} - -char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo) { -uint8_t operand=0; -float fvar1,fvar; -char *slp; -uint8_t vtype; -struct T_INDEX ind; - while (1) { - - if (*lp=='(') { - lp++; - lp=GetNumericResult(lp,OPER_EQU,&fvar1,jo); - lp++; - - } else { - lp=isvar(lp,&vtype,&ind,&fvar1,0,jo); - if (vtype!=NUM_RES && vtype&STYPE) { - - glob_script_mem.glob_error=1; - } - } - switch (lastop) { - case OPER_EQU: - fvar=fvar1; - break; - case OPER_PLS: - fvar+=fvar1; - break; - case OPER_MIN: - fvar-=fvar1; - break; - case OPER_MUL: - fvar*=fvar1; - break; - case OPER_DIV: - fvar/=fvar1; - break; - case OPER_PERC: - fvar=fmodf(fvar,fvar1); - break; - case OPER_XOR: - fvar=(uint32_t)fvar^(uint32_t)fvar1; - break; - case OPER_AND: - fvar=(uint32_t)fvar&(uint32_t)fvar1; - break; - case OPER_OR: - fvar=(uint32_t)fvar|(uint32_t)fvar1; - break; - default: - break; - - } - slp=lp; - lp=getop(lp,&operand); - switch (operand) { - case OPER_EQUEQU: - case OPER_NOTEQU: - case OPER_LOW: - case OPER_LOWEQU: - case OPER_GRT: - case OPER_GRTEQU: - lp=slp; - *fp=fvar; - return lp; - break; - default: - break; - } - lastop=operand; - if (!operand) { - *fp=fvar; - return lp; - } - } -} - - -char *ForceStringVar(char *lp,char *dstr) { - float fvar; - char *slp=lp; - glob_script_mem.glob_error=0; - lp=GetStringResult(lp,OPER_EQU,dstr,0); - if (glob_script_mem.glob_error) { - - lp=GetNumericResult(slp,OPER_EQU,&fvar,0); - dtostrfd(fvar,6,dstr); - glob_script_mem.glob_error=0; - } - return lp; -} - - -void Replace_Cmd_Vars(char *srcbuf,char *dstbuf,uint16_t dstsize) { - char *cp; - uint16_t count; - uint8_t vtype; - uint8_t dprec=glob_script_mem.script_dprec; - float fvar; - cp=srcbuf; - struct T_INDEX ind; - char string[SCRIPT_MAXSSIZE]; - dstsize-=2; - for (count=0;count=sizeof(str)) len=len>=sizeof(str); - strlcpy(str,cp,len); - toSLog(str); -} - -void toLogEOL(const char *s1,const char *str) { - if (!str) return; - uint8_t index=0; - char *cp=log_data; - strcpy(cp,s1); - cp+=strlen(s1); - while (*str) { - if (*str==SCRIPT_EOL) break; - *cp++=*str++; - } - *cp=0; - AddLog(LOG_LEVEL_INFO); -} - - -void toSLog(const char *str) { - if (!str) return; -#if SCRIPT_DEBUG>0 - while (*str) { - Serial.write(*str); - str++; - } -#endif -} - -char *Evaluate_expression(char *lp,uint8_t and_or, uint8_t *result,JsonObject *jo) { - float fvar,*dfvar,fvar1; - uint8_t numeric; - struct T_INDEX ind; - uint8_t vtype=0,lastop; - uint8_t res=0; - char *llp=lp; - char *slp; - - SCRIPT_SKIP_SPACES - if (*lp=='(') { - uint8_t res=0; - uint8_t xand_or=0; - lp++; - -loop: - SCRIPT_SKIP_SPACES - lp=Evaluate_expression(lp,xand_or,&res,jo); - if (*lp==')') { - lp++; - goto exit0; - } - - SCRIPT_SKIP_SPACES - if (!strncmp(lp,"or",2)) { - lp+=2; - xand_or=1; - goto loop; - } else if (!strncmp(lp,"and",3)) { - lp+=3; - xand_or=2; - goto loop; - } -exit0: - if (!and_or) { - *result=res; - } else if (and_or==1) { - *result|=res; - } else { - *result&=res; - } - goto exit10; - } - - llp=lp; - - dfvar=&fvar; - glob_script_mem.glob_error=0; - slp=lp; - numeric=1; - lp=GetNumericResult(lp,OPER_EQU,dfvar,0); - if (glob_script_mem.glob_error==1) { - - char cmpstr[SCRIPT_MAXSSIZE]; - lp=slp; - numeric=0; - - lp=isvar(lp,&vtype,&ind,0,cmpstr,0); - lp=getop(lp,&lastop); - - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,jo); - if (lastop==OPER_EQUEQU || lastop==OPER_NOTEQU) { - res=strcmp(cmpstr,str); - if (lastop==OPER_EQUEQU) res=!res; - goto exit; - } - - } else { - - - lp=getop(lp,&lastop); - lp=GetNumericResult(lp,OPER_EQU,&fvar1,jo); - switch (lastop) { - case OPER_EQUEQU: - res=(*dfvar==fvar1); - break; - case OPER_NOTEQU: - res=(*dfvar!=fvar1); - break; - case OPER_LOW: - res=(*dfvarfvar1); - break; - case OPER_GRTEQU: - res=(*dfvar>=fvar1); - break; - default: - - break; - } - -exit: - if (!and_or) { - *result=res; - } else if (and_or==1) { - *result|=res; - } else { - *result&=res; - } - } - - -exit10: -#if SCRIPT_DEBUG>0 - char tbuff[128]; - sprintf(tbuff,"p1=%d,p2=%d,cmpres=%d,and_or=%d line: ",(int32_t)*dfvar,(int32_t)fvar1,*result,and_or); - toLogEOL(tbuff,llp); -#endif - return lp; -} - - - -#define IF_NEST 8 - -int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { - - if (tasm_cmd_activ && tlen>0) return 0; - - uint8_t vtype=0,sindex,xflg,floop=0,globvindex,fromscriptcmd=0; - int8_t globaindex; - struct T_INDEX ind; - uint8_t operand,lastop,numeric=1,if_state[IF_NEST],if_exe[IF_NEST],if_result[IF_NEST],and_or,ifstck=0; - if_state[ifstck]=0; - if_result[ifstck]=0; - if_exe[ifstck]=1; - char cmpstr[SCRIPT_MAXSSIZE]; - uint8_t check=0; - if (tlen<0) { - tlen=abs(tlen); - check=1; - } - - float *dfvar,*cv_count,cv_max,cv_inc; - char *cv_ptr; - float fvar=0,fvar1,sysvar,swvar; - uint8_t section=0,sysv_type=0,swflg=0; - - if (!glob_script_mem.scriptptr) { - return -99; - } - - DynamicJsonBuffer jsonBuffer; - JsonObject &jobj=jsonBuffer.parseObject(js); - JsonObject *jo; - if (js) jo=&jobj; - else jo=0; - - char *lp=glob_script_mem.scriptptr; - - while (1) { - - - startline: - SCRIPT_SKIP_SPACES - - SCRIPT_SKIP_EOL - - if (*lp==';') goto next_line; - if (!*lp) break; - - if (section) { - - if (*lp=='>') { - return 0; - } - if (*lp=='#') { - return 0; - } - glob_script_mem.var_not_found=0; - - -#ifdef IFTHEN_DEBUG - char tbuff[128]; - sprintf(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]); - toLogEOL(tbuff,lp); -#endif - - - - - if (!strncmp(lp,"if",2)) { - lp+=2; - if (ifstck=2) { - lp+=5; - if (ifstck>0) { - if_state[ifstck]=0; - ifstck--; - } - goto next_line; - } else if (!strncmp(lp,"or",2) && if_state[ifstck]==1) { - lp+=2; - and_or=1; - } else if (!strncmp(lp,"and",3) && if_state[ifstck]==1) { - lp+=3; - and_or=2; - } - - if (*lp=='{' && if_state[ifstck]==1) { - lp+=1; - if_state[ifstck]=2; - if (if_exe[ifstck-1]) if_exe[ifstck]=if_result[ifstck]; - } else if (*lp=='{' && if_state[ifstck]==3) { - lp+=1; - - } else if (*lp=='}' && if_state[ifstck]>=2) { - lp++; - char *slp=lp; - uint8_t iselse=0; - for (uint8_t count=0; count<8;count++) { - if (*lp=='}') { - - break; - } - if (!strncmp(lp,"else",4)) { - - if_state[ifstck]=3; - if (if_exe[ifstck-1]) if_exe[ifstck]=!if_result[ifstck]; - lp+=4; - iselse=1; - SCRIPT_SKIP_SPACES - if (*lp=='{') lp++; - break; - } - lp++; - } - if (!iselse) { - lp=slp; - - if (ifstck>0) { - if_state[ifstck]=0; - ifstck--; - } - goto next_line; - } - } - - if (!strncmp(lp,"for",3)) { - - - lp+=3; - SCRIPT_SKIP_SPACES - lp=isvar(lp,&vtype,&ind,0,0,0); - if ((vtype!=VAR_NV) && (vtype&STYPE)==0) { - - uint8_t index=glob_script_mem.type[ind.index].index; - cv_count=&glob_script_mem.fvars[index]; - SCRIPT_SKIP_SPACES - lp=GetNumericResult(lp,OPER_EQU,cv_count,0); - SCRIPT_SKIP_SPACES - lp=GetNumericResult(lp,OPER_EQU,&cv_max,0); - SCRIPT_SKIP_SPACES - lp=GetNumericResult(lp,OPER_EQU,&cv_inc,0); - - cv_ptr=lp; - floop=1; - } else { - - toLogEOL("for error",lp); - } - } else if (!strncmp(lp,"next",4) && floop>0) { - - *cv_count+=cv_inc; - if (*cv_count<=cv_max) { - lp=cv_ptr; - } else { - lp+=4; - floop=0; - } - } - - if (!strncmp(lp,"switch",6)) { - lp+=6; - SCRIPT_SKIP_SPACES - char *slp=lp; - lp=GetNumericResult(lp,OPER_EQU,&swvar,0); - if (glob_script_mem.glob_error==1) { - - lp=slp; - - lp=isvar(lp,&vtype,&ind,0,cmpstr,0); - swflg=0x81; - } else { - swflg=1; - } - } else if (!strncmp(lp,"case",4) && swflg>0) { - lp+=4; - SCRIPT_SKIP_SPACES - float cvar; - if (!(swflg&0x80)) { - lp=GetNumericResult(lp,OPER_EQU,&cvar,0); - if (swvar!=cvar) { - swflg=2; - } else { - swflg=1; - } - } else { - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - if (!strcmp(cmpstr,str)) { - swflg=0x81; - } else { - swflg=0x82; - } - } - } else if (!strncmp(lp,"ends",4) && swflg>0) { - lp+=4; - swflg=0; - } - if ((swflg&3)==2) goto next_line; - - SCRIPT_SKIP_SPACES - - if (*lp==SCRIPT_EOL) { - goto next_line; - } - - - if (!if_exe[ifstck] && if_state[ifstck]!=1) goto next_line; - -#ifdef IFTHEN_DEBUG - sprintf(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d execute line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]); - toLogEOL(tbuff,lp); -#endif - - if (!strncmp(lp,"break",5)) { - if (floop) { - - floop=0; - } else { - section=0; - } - break; - } else if (!strncmp(lp,"dp",2) && isdigit(*(lp+2))) { - lp+=2; - - glob_script_mem.script_dprec=atoi(lp); - goto next_line; - } else if (!strncmp(lp,"delay(",6)) { - lp+=5; - - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - delay(fvar); - goto next_line; - } else if (!strncmp(lp,"spinm(",6)) { - lp+=6; - - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - int8_t pinnr=fvar; - SCRIPT_SKIP_SPACES - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - int8_t mode=fvar; - pinMode(pinnr,mode&3); - goto next_line; - } else if (!strncmp(lp,"spin(",5)) { - lp+=5; - - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - int8_t pinnr=fvar; - SCRIPT_SKIP_SPACES - lp=GetNumericResult(lp,OPER_EQU,&fvar,0); - int8_t mode=fvar; - digitalWrite(pinnr,mode&1); - goto next_line; - } else if (!strncmp(lp,"svars(",5)) { - lp+=5; - - Scripter_save_pvars(); - goto next_line; - } -#ifdef USE_LIGHT -#ifdef USE_WS2812 - else if (!strncmp(lp,"ws2812(",7)) { - lp+=7; - lp=isvar(lp,&vtype,&ind,0,0,0); - if (vtype!=VAR_NV) { - - uint8_t index=glob_script_mem.type[ind.index].index; - if ((vtype&STYPE)==0) { - - if (glob_script_mem.type[index].bits.is_filter) { - uint8_t len=0; - float *fa=Get_MFAddr(index,&len); - - if (fa && len) ws2812_set_array(fa,len); - } - } - } - goto next_line; - } -#endif -#endif - - else if (!strncmp(lp,"=>",2) || !strncmp(lp,"->",2) || !strncmp(lp,"+>",2) || !strncmp(lp,"print",5)) { - - uint8_t sflag=0,pflg=0,svmqtt,swll; - if (*lp=='p') { - pflg=1; - lp+=5; - } - else { - if (*lp=='-') sflag=1; - if (*lp=='+') sflag=2; - lp+=2; - } - char *slp=lp; - SCRIPT_SKIP_SPACES - #define SCRIPT_CMDMEM 512 - char *cmdmem=(char*)malloc(SCRIPT_CMDMEM); - if (cmdmem) { - char *cmd=cmdmem; - uint16_t count; - for (count=0; count=0) { - Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar); - } else { - Set_MFilter(glob_script_mem.type[globvindex].index,*dfvar); - } - } - - if (sysv_type) { - switch (sysv_type) { - case SCRIPT_LOGLEVEL: - glob_script_mem.script_loglevel=*dfvar; - break; - case SCRIPT_TELEPERIOD: - if (*dfvar<10) *dfvar=10; - if (*dfvar>300) *dfvar=300; - Settings.tele_period=*dfvar; - break; - } - sysv_type=0; - } - } else { - - numeric=0; - sindex=index; - - char str[SCRIPT_MAXSSIZE]; - lp=getop(lp,&lastop); - char *slp=lp; - glob_script_mem.glob_error=0; - lp=GetStringResult(lp,OPER_EQU,str,jo); - if (!js && glob_script_mem.glob_error) { - - lp=GetNumericResult(slp,OPER_EQU,&fvar,0); - dtostrfd(fvar,6,str); - glob_script_mem.glob_error=0; - } - - if (!glob_script_mem.var_not_found) { - - glob_script_mem.type[globvindex].bits.changed=1; - if (lastop==OPER_EQU) { - strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize); - } else if (lastop==OPER_PLSEQU) { - strncat(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize); - } - } - } - - } - SCRIPT_SKIP_SPACES - if (*lp=='{' && if_state[ifstck]==3) { - lp+=1; - - } - goto next_line; - } - } else { - - if (*lp=='>' && tlen==1) { - - lp++; - section=1; - fromscriptcmd=1; - goto startline; - } - if (!strncmp(lp,type,tlen)) { - - section=1; - glob_script_mem.section_ptr=lp; - if (check) { - return 99; - } - - char *ctype=(char*)type; - if (*ctype=='#') { - - ctype+=tlen; - if (*ctype=='(' && *(lp+tlen)=='(') { - float fparam; - numeric=1; - glob_script_mem.glob_error=0; - GetNumericResult((char*)ctype,OPER_EQU,&fparam,0); - if (glob_script_mem.glob_error==1) { - - numeric=0; - - GetStringResult((char*)ctype+1,OPER_EQU,cmpstr,0); - } - lp+=tlen; - if (*lp=='(') { - - lp++; - lp=isvar(lp,&vtype,&ind,0,0,0); - if (vtype!=VAR_NV) { - - uint8_t index=glob_script_mem.type[ind.index].index; - if ((vtype&STYPE)==0) { - - dfvar=&glob_script_mem.fvars[index]; - if (numeric) { - *dfvar=fparam; - } else { - - *dfvar=CharToFloat(cmpstr); - } - } else { - - sindex=index; - if (!numeric) { - strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),cmpstr,glob_script_mem.max_ssize); - } else { - - dtostrfd(fparam,6,glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize)); - } - } - } - } - } else { - lp+=tlen; - if (*ctype=='(' || (*lp!=SCRIPT_EOL && *lp!='?')) { - - section=0; - } - } - } - } - } - - next_line: - if (*lp==SCRIPT_EOL) { - lp++; - } else { - lp = strchr(lp, SCRIPT_EOL); - if (!lp) { - if (section) { - return 0; - } else { - return -1; - } - } - lp++; - } - } - return -1; -} - -uint8_t script_xsns_index = 0; - - -void ScripterEvery100ms(void) { - - if (Settings.rule_enabled && (uptime > 4)) { - mqtt_data[0] = '\0'; - uint16_t script_tele_period_save = tele_period; - tele_period = 2; - XsnsNextCall(FUNC_JSON_APPEND, script_xsns_index); - tele_period = script_tele_period_save; - if (strlen(mqtt_data)) { - mqtt_data[0] = '{'; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - Run_Scripter(">T",2, mqtt_data); - } - } - if (fast_script==99) Run_Scripter(">F",2,0); -} - - - - -void Scripter_save_pvars(void) { - int16_t mlen=0; - float *fp=(float*)glob_script_mem.script_pram; - mlen+=sizeof(float); - struct T_INDEX *vtp=glob_script_mem.type; - for (uint8_t count=0; countPMEM_SIZE) { - vtp[count].bits.is_permanent=0; - return; - } - *fp++=glob_script_mem.fvars[index]; - } - } - char *cp=(char*)fp; - for (uint8_t count=0; countPMEM_SIZE) { - vtp[count].bits.is_permanent=0; - return; - } - strcpy(cp,sp); - cp+=slen+1; - } - } -} - - -#ifdef USE_WEBSERVER - -#define WEB_HANDLE_SCRIPT "s10" - -const char S_CONFIGURE_SCRIPT[] PROGMEM = D_CONFIGURE_SCRIPT; - -const char HTTP_BTN_MENU_RULES[] PROGMEM = - "

"; - - -const char HTTP_FORM_SCRIPT[] PROGMEM = - "
 " D_SCRIPT " " - "
"; - -const char HTTP_FORM_SCRIPT1[] PROGMEM = - "
" - "
" - "
" - ""; - -const char HTTP_SCRIPT_FORM_END[] PROGMEM = - "
" - "" - "
"; - -#ifdef USE_SCRIPT_FATFS -const char HTTP_FORM_SCRIPT1c[] PROGMEM = - ""; -#ifdef SDCARD_DIR -const char HTTP_FORM_SCRIPT1d[] PROGMEM = - ""; -#else -const char HTTP_FORM_SCRIPT1d[] PROGMEM = - ""; -#endif - -#ifdef SDCARD_DIR -const char S_SCRIPT_FILE_UPLOAD[] PROGMEM = D_SDCARD_DIR; -#else -const char S_SCRIPT_FILE_UPLOAD[] PROGMEM = D_SDCARD_UPLOAD; -#endif - -const char HTTP_FORM_FILE_UPLOAD[] PROGMEM = -"
" -"
 %s" " "; -const char HTTP_FORM_FILE_UPG[] PROGMEM = -"
" -"

" -"
"; - -const char HTTP_FORM_FILE_UPGb[] PROGMEM = -"
" -"
" -""; - -const char HTTP_FORM_SDC_DIRa[] PROGMEM = -"
"; -const char HTTP_FORM_SDC_DIRb[] PROGMEM = - "
%s    %d
"; -const char HTTP_FORM_SDC_DIRd[] PROGMEM = -"
%s
"; -const char HTTP_FORM_SDC_DIRc[] PROGMEM = -"
"; -const char HTTP_FORM_SDC_HREF[] PROGMEM = -"http://%s/upl?download=%s/%s"; -#endif - - - -#ifdef USE_SCRIPT_FATFS - -#if USE_LONG_FILE_NAMES>0 -#undef REJCMPL -#define REJCMPL 6 -#else -#undef REJCMPL -#define REJCMPL 8 -#endif - -uint8_t reject(char *name) { - - if (*name=='_') return 1; - if (*name=='.') return 1; - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 - if (!strncasecmp(name,"SPOTLI~1",REJCMPL)) return 1; - if (!strncasecmp(name,"TRASHE~1",REJCMPL)) return 1; - if (!strncasecmp(name,"FSEVEN~1",REJCMPL)) return 1; - if (!strncasecmp(name,"SYSTEM~1",REJCMPL)) return 1; -#else - if (!strcasecmp(name,"SPOTLI~1")) return 1; - if (!strcasecmp(name,"TRASHE~1")) return 1; - if (!strcasecmp(name,"FSEVEN~1")) return 1; - if (!strcasecmp(name,"SYSTEM~1")) return 1; -#endif - return 0; -} - -void ListDir(char *path, uint8_t depth) { - char name[32]; - char npath[128]; - char format[12]; - sprintf(format,"%%-%ds",24-depth); - - File dir=SD.open(path); - if (dir) { - dir.rewindDirectory(); - if (strlen(path)>1) { - snprintf_P(npath,sizeof(npath),PSTR("http://%s/upl?download=%s"),WiFi.localIP().toString().c_str(),path); - for (uint8_t cnt=strlen(npath)-1;cnt>0;cnt--) { - if (npath[cnt]=='/') { - if (npath[cnt-1]=='=') npath[cnt+1]=0; - else npath[cnt]=0; - break; - } - } - WSContentSend_P(HTTP_FORM_SDC_DIRd,npath,path,".."); - } - while (true) { - File entry=dir.openNextFile(); - if (!entry) { - break; - } - char *pp=path; - if (!*(pp+1)) pp++; - char *cp=name; - - if (reject((char*)entry.name())) goto fclose; - - for (uint8_t cnt=0;cnt1) { - strcat(path,"/"); - } - strcat(path,entry.name()); - ListDir(path,depth+4); - path[plen]=0; - } else { - snprintf_P(npath,sizeof(npath),HTTP_FORM_SDC_HREF,WiFi.localIP().toString().c_str(),pp,entry.name()); - WSContentSend_P(HTTP_FORM_SDC_DIRb,npath,entry.name(),name,entry.size()); - } - fclose: - entry.close(); - } - dir.close(); - } -} - -char path[48]; - -void Script_FileUploadConfiguration(void) -{ - uint8_t depth=0; - strcpy(path,"/"); - - if (!HttpCheckPriviledgedAccess()) { return; } - - if (Webserver->hasArg("download")) { - String stmp = Webserver->arg("download"); - char *cp=(char*)stmp.c_str(); - if (DownloadFile(cp)) { - - strcpy(path,cp); - } - } - - WSContentStart_P(S_SCRIPT_FILE_UPLOAD); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR); - WSContentSend_P(HTTP_FORM_FILE_UPG, D_SCRIPT_UPLOAD); -#ifdef SDCARD_DIR - WSContentSend_P(HTTP_FORM_SDC_DIRa); - if (glob_script_mem.script_sd_found) { - ListDir(path,depth); - } - WSContentSend_P(HTTP_FORM_SDC_DIRc); -#endif - WSContentSend_P(HTTP_FORM_FILE_UPGb); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); - Web.upload_error = 0; -} - -File upload_file; - -void ScriptFileUploadSuccess(void) { - WSContentStart_P(S_INFORMATION); - WSContentSendStyle(); - WSContentSend_P(PSTR("
" D_UPLOAD " " D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS)); - WSContentSend_P(PSTR("

")); - WSContentSend_P(PSTR("

"),"/upl",D_UPL_DONE); - - WSContentStop(); -} - - - -void script_upload(void) { - - - - HTTPUpload& upload = Webserver->upload(); - if (upload.status == UPLOAD_FILE_START) { - char npath[48]; - sprintf(npath,"%s/%s",path,upload.filename.c_str()); - SD.remove(npath); - upload_file=SD.open(npath,FILE_WRITE); - if (!upload_file) Web.upload_error=1; - } else if(upload.status == UPLOAD_FILE_WRITE) { - if (upload_file) upload_file.write(upload.buf,upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END) { - if (upload_file) upload_file.close(); - if (Web.upload_error) { - AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: upload error")); - } - } else { - Web.upload_error=1; - Webserver->send(500, "text/plain", "500: couldn't create file"); - } -} - -uint8_t DownloadFile(char *file) { - File download_file; - WiFiClient download_Client; - - if (!SD.exists(file)) { - AddLog_P(LOG_LEVEL_INFO,PSTR("file not found")); - return 0; - } - - download_file=SD.open(file,FILE_READ); - if (!download_file) { - AddLog_P(LOG_LEVEL_INFO,PSTR("could not open file")); - return 0; - } - - if (download_file.isDirectory()) { - download_file.close(); - return 1; - } - - uint32_t flen=download_file.size(); - - download_Client = Webserver->client(); - Webserver->setContentLength(flen); - - char attachment[100]; - char *cp; - for (uint8_t cnt=strlen(file); cnt>=0; cnt--) { - if (file[cnt]=='/') { - cp=&file[cnt+1]; - break; - } - } - snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"),cp); - Webserver->sendHeader(F("Content-Disposition"), attachment); - WSSend(200, CT_STREAM, ""); - - uint8_t buff[512]; - uint16_t bread; - - - uint8_t cnt=0; - while (download_file.available()) { - bread=download_file.read(buff,sizeof(buff)); - uint16_t bw=download_Client.write((const char*)buff,bread); - if (!bw) break; - cnt++; - if (cnt>7) { - cnt=0; - if (glob_script_mem.script_loglevel&0x80) { - - loop(); - } - } - } - download_file.close(); - download_Client.stop(); - return 0; -} - -#endif - - -void HandleScriptTextareaConfiguration(void) { - if (!HttpCheckPriviledgedAccess()) { return; } - - if (Webserver->hasArg("save")) { - ScriptSaveSettings(); - HandleConfiguration(); - return; - } -} - -void HandleScriptConfiguration(void) { - - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_SCRIPT); - -#ifdef USE_SCRIPT_FATFS - if (Webserver->hasArg("d1")) { - DownloadFile(glob_script_mem.flink[0]); - } - if (Webserver->hasArg("d2")) { - DownloadFile(glob_script_mem.flink[1]); - } - if (Webserver->hasArg("upl")) { - Script_FileUploadConfiguration(); - } -#endif - - WSContentStart_P(S_CONFIGURE_SCRIPT); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_SCRIPT); - - -#ifdef xSCRIPT_STRIP_COMMENTS - uint16_t ssize=glob_script_mem.script_size; - if (bitRead(Settings.rule_enabled, 1)) ssize*=2; - WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",ssize); -#else - WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",glob_script_mem.script_size); -#endif - - - if (glob_script_mem.script_ram[0]) { - _WSContentSend(glob_script_mem.script_ram); - } - WSContentSend_P(HTTP_FORM_SCRIPT1b); - -#ifdef USE_SCRIPT_FATFS - if (glob_script_mem.script_sd_found) { - WSContentSend_P(HTTP_FORM_SCRIPT1d); - if (glob_script_mem.flink[0][0]) WSContentSend_P(HTTP_FORM_SCRIPT1c,1,glob_script_mem.flink[0]); - if (glob_script_mem.flink[1][0]) WSContentSend_P(HTTP_FORM_SCRIPT1c,2,glob_script_mem.flink[1]); - } -#endif - - WSContentSend_P(HTTP_SCRIPT_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); - } - - -void ScriptSaveSettings(void) { - - if (Webserver->hasArg("c1")) { - bitWrite(Settings.rule_enabled,0,1); - } else { - bitWrite(Settings.rule_enabled,0,0); - } - - - String str = Webserver->arg("t1"); - - if (*str.c_str()) { - - str.replace("\r\n","\n"); - str.replace("\r","\n"); - -#ifdef xSCRIPT_STRIP_COMMENTS - if (bitRead(Settings.rule_enabled, 1)) { - char *sp=(char*)str.c_str(); - char *sp1=sp; - char *dp=sp; - uint8_t flg=0; - while (*sp) { - while (*sp==' ') sp++; - sp1=sp; - sp=strchr(sp,'\n'); - if (!sp) { - flg=1; - } else { - *sp=0; - } - if (*sp1!=';') { - uint8_t slen=strlen(sp1); - if (slen) { - strcpy(dp,sp1); - dp+=slen; - *dp++='\n'; - } - } - if (flg) { - *dp=0; - break; - } - sp++; - } - } -#endif - - strlcpy(glob_script_mem.script_ram,str.c_str(), glob_script_mem.script_size); - -#ifdef USE_24C256 -#ifndef USE_SCRIPT_FATFS - if (glob_script_mem.flags&1) { - EEP_WRITE(0,EEP_SCRIPT_SIZE,glob_script_mem.script_ram); - } -#endif -#endif - -#ifdef USE_SCRIPT_FATFS - if (glob_script_mem.flags&1) { - SD.remove(FAT_SCRIPT_NAME); - File file=SD.open(FAT_SCRIPT_NAME,FILE_WRITE); - file.write(glob_script_mem.script_ram,FAT_SCRIPT_SIZE); - file.close(); - } -#endif - -#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS) - if (glob_script_mem.flags&1) { - SaveFile("/script.txt",(uint8_t*)glob_script_mem.script_ram,ESP32_SCRIPT_SIZE); - } -#endif - } - - if (glob_script_mem.script_mem) { - Scripter_save_pvars(); - free(glob_script_mem.script_mem); - glob_script_mem.script_mem=0; - glob_script_mem.script_mem_size=0; - } - - if (bitRead(Settings.rule_enabled, 0)) { - int16_t res=Init_Scripter(); - if (res) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("script init error: %d"), res); - return; - } - Run_Scripter(">B",2,0); - fast_script=Run_Scripter(">F",-2,0); - } -} - -#endif - - -#if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) - - -#define HUE_DEV_MVNUM 5 -#define HUE_DEV_NSIZE 16 -struct HUE_SCRIPT { - char name[HUE_DEV_NSIZE]; - uint8_t type; - uint8_t index[HUE_DEV_MVNUM]; - uint8_t vindex[HUE_DEV_MVNUM]; -} hue_script[32]; - - -const char SCRIPT_HUE_LIGHTS_STATUS_JSON1[] PROGMEM = - "{\"state\":" - "{\"on\":{state}," - "{light_status}" - "\"alert\":\"none\"," - "\"effect\":\"none\"," - "\"reachable\":true}" - ",\"type\":\"{type}\"," - "\"name\":\"{j1\"," - "\"modelid\":\"{m1}\"," - "\"uniqueid\":\"{j2\"," - "\"swversion\":\"5.50.1.19085\"}"; -# 3706 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -const char SCRIPT_HUE_LIGHTS_STATUS_JSON2[] PROGMEM = -"{\"state\":{" -"\"presence\":{state}," -"\"lastupdated\":\"2017-10-01T12:37:30\"" -"}," -"\"swupdate\":{" -"\"state\":\"noupdates\"," -"\"lastinstall\": null" -"}," -"\"config\":{" -"\"on\":true," -"\"battery\":100," -"\"reachable\":true," -"\"alert\":\"none\"," -"\"ledindication\":false," -"\"usertest\":false," -"\"sensitivity\":2," -"\"sensitivitymax\":2," -"\"pending\":[]" -"}," -"\"name\":\"{j1\"," -"\"type\":\"ZLLPresence\"," -"\"modelid\":\"SML001\"," -"\"manufacturername\":\"Philips\"," -"\"swversion\":\"6.1.0.18912\"," -"\"uniqueid\":\"{j2\"" -"}"; -# 3787 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -void Script_HueStatus(String *response, uint16_t hue_devs) { - - if (hue_script[hue_devs].type=='p') { - *response+=FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON2); - response->replace("{j1",hue_script[hue_devs].name); - response->replace("{j2", GetHueDeviceId(hue_devs)); - uint8_t pwr=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1]; - response->replace("{state}", (pwr ? "true" : "false")); - return; - } - - *response+=FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON1); - uint8_t pwr=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1]; - response->replace("{state}", (pwr ? "true" : "false")); - String light_status = ""; - if (hue_script[hue_devs].index[1]>0) { - - light_status += "\"bri\":"; - uint32_t bri=glob_script_mem.fvars[hue_script[hue_devs].index[1]-1]; - if (bri > 254) bri = 254; - if (bri < 1) bri = 1; - light_status += String(bri); - light_status += ","; - } - if (hue_script[hue_devs].index[2]>0) { - - uint32_t hue=glob_script_mem.fvars[hue_script[hue_devs].index[2]-1]; - - light_status += "\"hue\":"; - light_status += String(hue); - light_status += ","; - } - if (hue_script[hue_devs].index[3]>0) { - - uint32_t sat=glob_script_mem.fvars[hue_script[hue_devs].index[3]-1] ; - if (sat > 254) sat = 254; - if (sat < 1) sat = 1; - light_status += "\"sat\":"; - light_status += String(sat); - light_status += ","; - } - if (hue_script[hue_devs].index[4]>0) { - - uint32_t ct=glob_script_mem.fvars[hue_script[hue_devs].index[4]-1]; - light_status += "\"ct\":"; - light_status += String(ct); - light_status += ","; - } - - float temp; - switch (hue_script[hue_devs].type) { - case 'C': - response->replace("{type}","Color Ligh"); - response->replace("{m1","LST001"); - break; - case 'D': - response->replace("{type}","Dimmable Light"); - response->replace("{m1","LWB004"); - break; - case 'T': - response->replace("{type}","Color Temperature Light"); - response->replace("{m1","LTW011"); - break; - case 'E': - response->replace("{type}","Extended color light"); - response->replace("{m1","LCT007"); - break; - case 'S': - response->replace("{type}","On/Off light"); - response->replace("{m1","LCT007"); - break; - default: - response->replace("{type}","color light"); - response->replace("{m1","LST001"); - break; - } - - response->replace("{light_status}", light_status); - response->replace("{j1",hue_script[hue_devs].name); - response->replace("{j2", GetHueDeviceId(hue_devs)); - -} - -void Script_Check_Hue(String *response) { - if (!bitRead(Settings.rule_enabled, 0)) return; - - uint8_t hue_script_found=Run_Scripter(">H",-2,0); - if (hue_script_found!=99) return; - - char line[128]; - char tmp[128]; - uint8_t hue_devs=0; - uint8_t vindex=0; - char *cp; - char *lp=glob_script_mem.section_ptr+2; - while (lp) { - SCRIPT_SKIP_SPACES - while (*lp==SCRIPT_EOL) { - lp++; - } - if (!*lp || *lp=='#' || *lp=='>') { - break; - } - if (*lp!=';') { - - memcpy(line,lp,sizeof(line)); - line[sizeof(line)-1]=0; - cp=line; - for (uint32_t i=0; i0) *response+=",\""; - } - *response+=String(EncodeLightId(hue_devs+devices_present+1))+"\":"; - Script_HueStatus(response,hue_devs); - } - - hue_devs++; - } - if (*lp==SCRIPT_EOL) { - lp++; - } else { - lp = strchr(lp, SCRIPT_EOL); - if (!lp) break; - lp++; - } - } -#if 0 - if (response) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Hue: %d"), hue_devs); - toLog(">>>>"); - toLog(response->c_str()); - toLog(response->c_str()+LOGSZ); - } -#endif -} - -const char sHUE_LIGHT_RESPONSE_JSON[] PROGMEM = - "{\"success\":{\"/lights/{id/state/{cm\":{re}}"; - -const char sHUE_SENSOR_RESPONSE_JSON[] PROGMEM = - "{\"success\":{\"/lights/{id/state/{cm\":{re}}"; - -const char sHUE_ERROR_JSON[] PROGMEM = - "[{\"error\":{\"type\":901,\"address\":\"/\",\"description\":\"Internal Error\"}}]"; - - - -void Script_Handle_Hue(String *path) { - String response; - int code = 200; - uint16_t tmp = 0; - uint16_t hue = 0; - uint8_t sat = 0; - uint8_t bri = 254; - uint16_t ct = 0; - bool resp = false; - - uint8_t device = DecodeLightId(atoi(path->c_str())); - uint8_t index = device-devices_present-1; - - if (Webserver->args()) { - response = "["; - - StaticJsonBuffer<400> jsonBuffer; - JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1)); - if (hue_json.containsKey("on")) { - - response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); - response.replace("{id", String(EncodeLightId(device))); - response.replace("{cm", "on"); - - bool on = hue_json["on"]; - switch(on) - { - case false : glob_script_mem.fvars[hue_script[index].index[0]-1]=0; - response.replace("{re", "false"); - break; - case true : glob_script_mem.fvars[hue_script[index].index[0]-1]=1; - response.replace("{re", "true"); - break; - } - glob_script_mem.type[hue_script[index].vindex[0]].bits.changed=1; - resp = true; - } - if (hue_json.containsKey("bri")) { - tmp = hue_json["bri"]; - bri=tmp; - if (254 <= bri) { bri = 255; } - if (resp) { response += ","; } - response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); - response.replace("{id", String(EncodeLightId(device))); - response.replace("{cm", "bri"); - response.replace("{re", String(tmp)); - glob_script_mem.fvars[hue_script[index].index[1]-1]=bri; - glob_script_mem.type[hue_script[index].vindex[1]].bits.changed=1; - resp = true; - } - if (hue_json.containsKey("xy")) { - float x, y; - x = hue_json["xy"][0]; - y = hue_json["xy"][1]; - const String &x_str = hue_json["xy"][0]; - const String &y_str = hue_json["xy"][1]; - uint8_t rr,gg,bb; - LightStateClass::XyToRgb(x, y, &rr, &gg, &bb); - LightStateClass::RgbToHsb(rr, gg, bb, &hue, &sat, nullptr); - if (resp) { response += ","; } - response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); - response.replace("{id", String(device)); - response.replace("{cm", "xy"); - response.replace("{re", "[" + x_str + "," + y_str + "]"); - glob_script_mem.fvars[hue_script[index].index[2]-1]=hue; - glob_script_mem.type[hue_script[index].vindex[2]].bits.changed=1; - glob_script_mem.fvars[hue_script[index].index[3]-1]=sat; - glob_script_mem.type[hue_script[index].vindex[3]].bits.changed=1; - resp = true; - } - - if (hue_json.containsKey("hue")) { - tmp = hue_json["hue"]; - - - hue=tmp; - if (resp) { response += ","; } - response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); - response.replace("{id", String(EncodeLightId(device))); - response.replace("{cm", "hue"); - response.replace("{re", String(tmp)); - glob_script_mem.fvars[hue_script[index].index[2]-1]=hue; - glob_script_mem.type[hue_script[index].vindex[2]].bits.changed=1; - resp = true; - } - if (hue_json.containsKey("sat")) { - tmp = hue_json["sat"]; - sat=tmp; - if (254 <= sat) { sat = 255; } - if (resp) { response += ","; } - response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); - response.replace("{id", String(EncodeLightId(device))); - response.replace("{cm", "sat"); - response.replace("{re", String(tmp)); - glob_script_mem.fvars[hue_script[index].index[3]-1]=sat; - glob_script_mem.type[hue_script[index].vindex[3]].bits.changed=1; - resp = true; - } - if (hue_json.containsKey("ct")) { - ct = hue_json["ct"]; - if (resp) { response += ","; } - response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); - response.replace("{id", String(EncodeLightId(device))); - response.replace("{cm", "ct"); - response.replace("{re", String(ct)); - glob_script_mem.fvars[hue_script[index].index[4]-1]=ct; - glob_script_mem.type[hue_script[index].vindex[4]].bits.changed=1; - resp = true; - } - response += "]"; - - } else { - response = FPSTR(sHUE_ERROR_JSON); - } - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " Result (%s)"), response.c_str()); - WSSend(code, CT_JSON, response); - if (resp) { - Run_Scripter(">E",2,0); - } -} -#endif - - -#ifdef USE_SCRIPT_SUB_COMMAND -bool Script_SubCmd(void) { - if (!bitRead(Settings.rule_enabled, 0)) return false; - - if (tasm_cmd_activ) return false; - - char command[CMDSZ]; - strlcpy(command,XdrvMailbox.topic,CMDSZ); - uint32_t pl=XdrvMailbox.payload; - char pld[64]; - strlcpy(pld,XdrvMailbox.data,sizeof(pld)); - - char cmdbuff[128]; - char *cp=cmdbuff; - *cp++='#'; - strcpy(cp,XdrvMailbox.topic); - uint8_t tlen=strlen(XdrvMailbox.topic); - cp+=tlen; - if (XdrvMailbox.index > 0) { - *cp++=XdrvMailbox.index|0x30; - tlen++; - } - if ((XdrvMailbox.payload>0) || (XdrvMailbox.data_len>0)) { - *cp++='('; - strncpy(cp,XdrvMailbox.data,XdrvMailbox.data_len); - cp+=XdrvMailbox.data_len; - *cp++=')'; - *cp=0; - } - - uint32_t res=Run_Scripter(cmdbuff,tlen+1,0); - - if (res) return false; - else { - if (pl>=0) { - Response_P(S_JSON_COMMAND_NVALUE, command, pl); - } else { - Response_P(S_JSON_COMMAND_SVALUE, command, pld); - } - } - return true; -} -#endif - -void execute_script(char *script) { - char *svd_sp=glob_script_mem.scriptptr; - strcat(script,"\n#"); - glob_script_mem.scriptptr=script; - Run_Scripter(">",1,0); - glob_script_mem.scriptptr=svd_sp; -} -#define D_CMND_SCRIPT "Script" -#define D_CMND_SUBSCRIBE "Subscribe" -#define D_CMND_UNSUBSCRIBE "Unsubscribe" - -enum ScriptCommands { CMND_SCRIPT,CMND_SUBSCRIBE, CMND_UNSUBSCRIBE }; -const char kScriptCommands[] PROGMEM = D_CMND_SCRIPT "|" D_CMND_SUBSCRIBE "|" D_CMND_UNSUBSCRIBE; - -bool ScriptCommand(void) { - char command[CMDSZ]; - bool serviced = true; - uint8_t index = XdrvMailbox.index; - - if (tasm_cmd_activ) return false; - - int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kScriptCommands); - if (-1 == command_code) { - serviced = false; - } - else if ((CMND_SCRIPT == command_code) && (index > 0)) { - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 4)) { - switch (XdrvMailbox.payload) { - case 0: - case 1: - bitWrite(Settings.rule_enabled, index -1, XdrvMailbox.payload); - break; -#ifdef xSCRIPT_STRIP_COMMENTS - case 2: - bitWrite(Settings.rule_enabled, 1,0); - break; - case 3: - bitWrite(Settings.rule_enabled, 1,1); - break; -#endif - } - } else { - if ('>' == XdrvMailbox.data[0]) { - - snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\"}"),command,XdrvMailbox.data); - if (bitRead(Settings.rule_enabled, 0)) { - for (uint8_t count=0; count> 1; -} - -void dateTime(uint16_t* date, uint16_t* time) { - - *date = xFAT_DATE(RtcTime.year,RtcTime.month, RtcTime.day_of_month); - - *time = xFAT_TIME(RtcTime.hour,RtcTime.minute,RtcTime.second); -} - -#endif - - - -#ifdef SUPPORT_MQTT_EVENT -# 4281 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -bool ScriptMqttData(void) -{ - bool serviced = false; - - toLog(XdrvMailbox.data); - if (XdrvMailbox.data_len < 1 || XdrvMailbox.data_len > 256) { - return false; - } - String sTopic = XdrvMailbox.topic; - String sData = XdrvMailbox.data; - - MQTT_Subscription event_item; - - for (uint32_t index = 0; index < subscriptions.size(); index++) { - event_item = subscriptions.get(index); - - - if (sTopic.startsWith(event_item.Topic)) { - - serviced = true; - String value; - String lkey; - if (event_item.Key.length() == 0) { - value = sData; - } else { - StaticJsonBuffer<400> jsonBuf; - JsonObject& jsonData = jsonBuf.parseObject(sData); - String key1 = event_item.Key; - String key2; - if (!jsonData.success()) break; - int dot; - if ((dot = key1.indexOf('.')) > 0) { - key2 = key1.substring(dot+1); - key1 = key1.substring(0, dot); - lkey=key2; - if (!jsonData[key1][key2].success()) break; - value = (const char *)jsonData[key1][key2]; - } else { - if (!jsonData[key1].success()) break; - value = (const char *)jsonData[key1]; - lkey=key1; - } - } - value.trim(); - char sbuffer[128]; - - if (!strncmp(lkey.c_str(),"Epoch",5)) { - uint32_t ep=atoi(value.c_str())-(uint32_t)EPOCH_OFFSET; - snprintf_P(sbuffer, sizeof(sbuffer), PSTR(">%s=%d\n"), event_item.Event.c_str(),ep); - } else { - snprintf_P(sbuffer, sizeof(sbuffer), PSTR(">%s=\"%s\"\n"), event_item.Event.c_str(), value.c_str()); - } - - execute_script(sbuffer); - } - } - return serviced; -} -# 4356 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -String ScriptSubscribe(const char *data, int data_len) -{ - MQTT_Subscription subscription_item; - String events; - if (data_len > 0) { - char parameters[data_len+1]; - memcpy(parameters, data, data_len); - parameters[data_len] = '\0'; - String event_name, topic, key; - - char * pos = strtok(parameters, ","); - if (pos) { - event_name = Trim(pos); - pos = strtok(nullptr, ","); - if (pos) { - topic = Trim(pos); - pos = strtok(nullptr, ","); - if (pos) { - key = Trim(pos); - } - } - } - - - if (event_name.length() > 0 && topic.length() > 0) { - - for (uint32_t index=0; index < subscriptions.size(); index++) { - if (subscriptions.get(index).Event.equals(event_name)) { - - String stopic = subscriptions.get(index).Topic + "/#"; - MqttUnsubscribe(stopic.c_str()); - subscriptions.remove(index); - break; - } - } - - if (!topic.endsWith("#")) { - if (topic.endsWith("/")) { - topic.concat("#"); - } else { - topic.concat("/#"); - } - } - - - subscription_item.Event = event_name; - subscription_item.Topic = topic.substring(0, topic.length() - 2); - subscription_item.Key = key; - subscriptions.add(subscription_item); - - MqttSubscribe(topic.c_str()); - events.concat(event_name + "," + topic - + (key.length()>0 ? "," : "") - + key); - } else { - events = D_JSON_WRONG_PARAMETERS; - } - } else { - - for (uint32_t index=0; index < subscriptions.size(); index++) { - subscription_item = subscriptions.get(index); - events.concat(subscription_item.Event + "," + subscription_item.Topic - + (subscription_item.Key.length()>0 ? "," : "") - + subscription_item.Key + "; "); - } - } - return events; -} -# 4436 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_10_scripter.ino" -String ScriptUnsubscribe(const char * data, int data_len) -{ - MQTT_Subscription subscription_item; - String events; - if (data_len > 0) { - for (uint32_t index = 0; index < subscriptions.size(); index++) { - subscription_item = subscriptions.get(index); - if (subscription_item.Event.equalsIgnoreCase(data)) { - String stopic = subscription_item.Topic + "/#"; - MqttUnsubscribe(stopic.c_str()); - events = subscription_item.Event; - subscriptions.remove(index); - break; - } - } - } else { - - String stopic; - while (subscriptions.size() > 0) { - events.concat(subscriptions.get(0).Event + "; "); - stopic = subscriptions.get(0).Topic + "/#"; - MqttUnsubscribe(stopic.c_str()); - subscriptions.remove(0); - } - } - return events; -} -#endif - - - -#ifdef USE_SCRIPT_WEB_DISPLAY - -void Script_Check_HTML_Setvars(void) { - - if (!HttpCheckPriviledgedAccess()) { return; } - - if (Webserver->hasArg("sv")) { - String stmp = Webserver->arg("sv"); - char cmdbuf[64]; - memset(cmdbuf,0,sizeof(cmdbuf)); - char *cp=cmdbuf; - *cp++='>'; - strncpy(cp,stmp.c_str(),sizeof(cmdbuf)-1); - char *cp1=strchr(cp,'_'); - if (!cp1) return; - *cp1=0; - char vname[32]; - strncpy(vname,cp,sizeof(vname)); - *cp1='='; - cp1++; - - struct T_INDEX ind; - uint8_t vtype; - isvar(vname,&vtype,&ind,0,0,0); - if (vtype!=NUM_RES && vtype&STYPE) { - - uint8_t tlen=strlen(cp1); - memmove(cp1+1,cp1,tlen); - *cp1='\"'; - *(cp1+tlen+1)='\"'; - } - - - execute_script(cmdbuf); - Run_Scripter(">E",2,0); - } -} - - -const char SCRIPT_MSG_BUTTONa[] PROGMEM = - ""; - -const char SCRIPT_MSG_BUTTONa_TBL[] PROGMEM = - ""; - -const char SCRIPT_MSG_BUTTONb[] PROGMEM = - ""; - -const char SCRIPT_MSG_BUT_START[] PROGMEM = - "
"; -const char SCRIPT_MSG_BUT_START_TBL[] PROGMEM = - ""; - -const char SCRIPT_MSG_BUT_STOP[] PROGMEM = - ""; -const char SCRIPT_MSG_BUT_STOP_TBL[] PROGMEM = - "
"; - -const char SCRIPT_MSG_SLIDER[] PROGMEM = - "
%s
%s%s
" - "
"; - -const char SCRIPT_MSG_CHKBOX[] PROGMEM = - "
"; - -const char SCRIPT_MSG_TEXTINP[] PROGMEM = - "
"; - -const char SCRIPT_MSG_NUMINP[] PROGMEM = - "
"; - - -void ScriptGetVarname(char *nbuf,char *sp, uint32_t blen) { -uint32_t cnt; - for (cnt=0;cntW",-2,0); - if (web_script==99) { - char line[128]; - char tmp[128]; - uint8_t optflg=0; - char *lp=glob_script_mem.section_ptr+2; - while (lp) { - while (*lp==SCRIPT_EOL) { - lp++; - } - if (!*lp || *lp=='#' || *lp=='>') { - break; - } - if (*lp!=';') { - - memcpy(line,lp,sizeof(line)); - line[sizeof(line)-1]=0; - char *cp=line; - for (uint32_t i=0; i0) { - cp="checked='checked'"; - uval=0; - } else { - cp=""; - uval=1; - } - WSContentSend_PD(SCRIPT_MSG_CHKBOX,label,(char*)cp,uval,vname); - - } else if (!strncmp(lin,"bu(",3)) { - char *lp=lin+3; - uint8_t bcnt=0; - char *found=lin; - while (bcnt<4) { - found=strstr(found,"bu("); - if (!found) break; - found+=3; - bcnt++; - } - uint8_t proz=100/bcnt; - if (!optflg && bcnt>1) proz-=2; - if (optflg) WSContentSend_PD(SCRIPT_MSG_BUT_START_TBL); - else WSContentSend_PD(SCRIPT_MSG_BUT_START); - for (uint32_t cnt=0;cnt0) { - cp=ontxt; - uval=0; - } else { - cp=offtxt; - uval=1; - } - if (bcnt>1 && cnt==bcnt-1) { - if (!optflg) proz+=2; - } - if (!optflg) { - WSContentSend_PD(SCRIPT_MSG_BUTTONa,proz,uval,vname,cp); - } else { - WSContentSend_PD(SCRIPT_MSG_BUTTONa_TBL,proz,uval,vname,cp); - } - if (bcnt>1 && cnt%s
"),tmp); - } else { - WSContentSend_PD(PSTR("{s}%s{e}"),tmp); - } - } - } - if (*lp==SCRIPT_EOL) { - lp++; - } else { - lp = strchr(lp, SCRIPT_EOL); - if (!lp) break; - lp++; - } - } - } -} -#endif - - -#ifdef USE_SENDMAIL - -#ifdef ESP8266 -void script_send_email_body(BearSSL::WiFiClientSecure_light *client) { -#else -void script_send_email_body(WiFiClient *client) { -#endif - -uint8_t msect=Run_Scripter(">m",-2,0); - if (msect==99) { - char line[128]; - char tmp[128]; - char *lp=glob_script_mem.section_ptr+2; - while (lp) { - while (*lp==SCRIPT_EOL) { - lp++; - } - if (!*lp || *lp=='#' || *lp=='>') { - break; - } - if (*lp!=';') { - - memcpy(line,lp,sizeof(line)); - line[sizeof(line)-1]=0; - char *cp=line; - for (uint32_t i=0; iprintln(tmp); - } - if (*lp==SCRIPT_EOL) { - lp++; - } else { - lp = strchr(lp, SCRIPT_EOL); - if (!lp) break; - lp++; - } - } - } else { - client->println("*"); - } -} -#endif - -#ifdef USE_SCRIPT_JSON_EXPORT -void ScriptJsonAppend(void) { - uint8_t web_script=Run_Scripter(">J",-2,0); - if (web_script==99) { - char line[128]; - char tmp[128]; - char *lp=glob_script_mem.section_ptr+2; - while (lp) { - while (*lp==SCRIPT_EOL) { - lp++; - } - if (!*lp || *lp=='#' || *lp=='>') { - break; - } - if (*lp!=';') { - - memcpy(line,lp,sizeof(line)); - line[sizeof(line)-1]=0; - char *cp=line; - for (uint32_t i=0; iB",2,0); - fast_script=Run_Scripter(">F",-2,0); -#if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) - Script_Check_Hue(0); -#endif - } - break; - case FUNC_EVERY_100_MSECOND: - ScripterEvery100ms(); - break; - case FUNC_EVERY_SECOND: - ScriptEverySecond(); - break; - case FUNC_COMMAND: - result = ScriptCommand(); - break; - case FUNC_SET_POWER: -#ifdef SCRIPT_POWER_SECTION - if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">P",2,0); -#else - if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">E",2,0); -#endif - break; - case FUNC_RULES_PROCESS: - if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">E",2,mqtt_data); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_RULES); - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/" WEB_HANDLE_SCRIPT, HandleScriptConfiguration); - Webserver->on("/ta",HTTP_POST, HandleScriptTextareaConfiguration); - -#ifdef USE_SCRIPT_FATFS - Webserver->on("/u3", HTTP_POST,[]() { Webserver->sendHeader("Location","/u3");Webserver->send(303);},script_upload); - Webserver->on("/u3", HTTP_GET,ScriptFileUploadSuccess); - Webserver->on("/upl", HTTP_GET,Script_FileUploadConfiguration); -#endif - break; -#endif - case FUNC_SAVE_BEFORE_RESTART: - if (bitRead(Settings.rule_enabled, 0)) { - Run_Scripter(">R",2,0); - Scripter_save_pvars(); - } - break; -#ifdef SUPPORT_MQTT_EVENT - case FUNC_MQTT_DATA: - if (bitRead(Settings.rule_enabled, 0)) { - result = ScriptMqttData(); - } - break; -#endif -#ifdef USE_SCRIPT_WEB_DISPLAY - case FUNC_WEB_SENSOR: - if (bitRead(Settings.rule_enabled, 0)) { - ScriptWebShow(); - } - break; -#endif - -#ifdef USE_SCRIPT_JSON_EXPORT - case FUNC_JSON_APPEND: - if (bitRead(Settings.rule_enabled, 0)) { - ScriptJsonAppend(); - } - break; -#endif - -#ifdef USE_BUTTON_EVENT - case FUNC_BUTTON_PRESSED: - if (bitRead(Settings.rule_enabled, 0)) { - if ((script_button[XdrvMailbox.index]&1)!=(XdrvMailbox.payload&1)) { - script_button[XdrvMailbox.index]=XdrvMailbox.payload; - Run_Scripter(">b",2,0); - } - } - break; -#endif - - } - return result; -} - - - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_11_knx.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_11_knx.ino" -#ifdef USE_KNX -# 51 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_11_knx.ino" -#define XDRV_11 11 - -#include - -address_t KNX_physs_addr; -address_t KNX_addr; - -#define KNX_Empty 255 - -#define TOGGLE_INHIBIT_TIME 15 - -float last_temp; -float last_hum; -uint8_t toggle_inhibit; - -typedef struct __device_parameters -{ - uint8_t type; - - - - - bool show; - - bool last_state; - - callback_id_t CB_id; - - - - - -} device_parameters_t; - - -device_parameters_t device_param[] = { - { 1, false, false, KNX_Empty }, - { 2, false, false, KNX_Empty }, - { 3, false, false, KNX_Empty }, - { 4, false, false, KNX_Empty }, - { 5, false, false, KNX_Empty }, - { 6, false, false, KNX_Empty }, - { 7, false, false, KNX_Empty }, - { 8, false, false, KNX_Empty }, - { 9, false, false, KNX_Empty }, - { 10, false, false, KNX_Empty }, - { 11, false, false, KNX_Empty }, - { 12, false, false, KNX_Empty }, - { 13, false, false, KNX_Empty }, - { 14, false, false, KNX_Empty }, - { 15, false, false, KNX_Empty }, - { 16, false, false, KNX_Empty }, - { KNX_TEMPERATURE, false, false, KNX_Empty }, - { KNX_HUMIDITY , false, false, KNX_Empty }, - { KNX_ENERGY_VOLTAGE , false, false, KNX_Empty }, - { KNX_ENERGY_CURRENT , false, false, KNX_Empty }, - { KNX_ENERGY_POWER , false, false, KNX_Empty }, - { KNX_ENERGY_POWERFACTOR , false, false, KNX_Empty }, - { KNX_ENERGY_DAILY , false, false, KNX_Empty }, - { KNX_ENERGY_START , false, false, KNX_Empty }, - { KNX_ENERGY_TOTAL , false, false, KNX_Empty }, - { KNX_SLOT1 , false, false, KNX_Empty }, - { KNX_SLOT2 , false, false, KNX_Empty }, - { KNX_SLOT3 , false, false, KNX_Empty }, - { KNX_SLOT4 , false, false, KNX_Empty }, - { KNX_SLOT5 , false, false, KNX_Empty }, - { KNX_Empty, false, false, KNX_Empty} -}; - - -const char * device_param_ga[] = { - D_TIMER_OUTPUT " 1", - D_TIMER_OUTPUT " 2", - D_TIMER_OUTPUT " 3", - D_TIMER_OUTPUT " 4", - D_TIMER_OUTPUT " 5", - D_TIMER_OUTPUT " 6", - D_TIMER_OUTPUT " 7", - D_TIMER_OUTPUT " 8", - D_SENSOR_BUTTON " 1", - D_SENSOR_BUTTON " 2", - D_SENSOR_BUTTON " 3", - D_SENSOR_BUTTON " 4", - D_SENSOR_BUTTON " 5", - D_SENSOR_BUTTON " 6", - D_SENSOR_BUTTON " 7", - D_SENSOR_BUTTON " 8", - D_TEMPERATURE , - D_HUMIDITY , - D_VOLTAGE , - D_CURRENT , - D_POWERUSAGE , - D_POWER_FACTOR , - D_ENERGY_TODAY , - D_ENERGY_YESTERDAY , - D_ENERGY_TOTAL , - D_KNX_TX_SLOT " 1", - D_KNX_TX_SLOT " 2", - D_KNX_TX_SLOT " 3", - D_KNX_TX_SLOT " 4", - D_KNX_TX_SLOT " 5", - nullptr -}; - - -const char *device_param_cb[] = { - D_TIMER_OUTPUT " 1", - D_TIMER_OUTPUT " 2", - D_TIMER_OUTPUT " 3", - D_TIMER_OUTPUT " 4", - D_TIMER_OUTPUT " 5", - D_TIMER_OUTPUT " 6", - D_TIMER_OUTPUT " 7", - D_TIMER_OUTPUT " 8", - D_TIMER_OUTPUT " 1 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 2 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 3 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 4 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 5 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 6 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 7 " D_BUTTON_TOGGLE, - D_TIMER_OUTPUT " 8 " D_BUTTON_TOGGLE, - D_REPLY " " D_TEMPERATURE, - D_REPLY " " D_HUMIDITY, - D_REPLY " " D_VOLTAGE , - D_REPLY " " D_CURRENT , - D_REPLY " " D_POWERUSAGE , - D_REPLY " " D_POWER_FACTOR , - D_REPLY " " D_ENERGY_TODAY , - D_REPLY " " D_ENERGY_YESTERDAY , - D_REPLY " " D_ENERGY_TOTAL , - D_KNX_RX_SLOT " 1", - D_KNX_RX_SLOT " 2", - D_KNX_RX_SLOT " 3", - D_KNX_RX_SLOT " 4", - D_KNX_RX_SLOT " 5", - nullptr -}; - - -#define D_PRFX_KNX "Knx" -#define D_CMND_KNXTXCMND "Tx_Cmnd" -#define D_CMND_KNXTXVAL "Tx_Val" -#define D_CMND_KNX_ENABLED "_Enabled" -#define D_CMND_KNX_ENHANCED "_Enhanced" -#define D_CMND_KNX_PA "_PA" -#define D_CMND_KNX_GA "_GA" -#define D_CMND_KNX_CB "_CB" - -const char kKnxCommands[] PROGMEM = D_PRFX_KNX "|" - D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB ; - -void (* const KnxCommand[])(void) PROGMEM = { - &CmndKnxTxCmnd, &CmndKnxTxVal, &CmndKnxEnabled, &CmndKnxEnhanced, &CmndKnxPa, &CmndKnxGa, &CmndKnxCb }; - -uint8_t KNX_GA_Search( uint8_t param, uint8_t start = 0 ) -{ - for (uint32_t i = start; i < Settings.knx_GA_registered; ++i) - { - if ( Settings.knx_GA_param[i] == param ) - { - if ( Settings.knx_GA_addr[i] != 0 ) - { - if ( i >= start ) { return i; } - } - } - } - return KNX_Empty; -} - - -uint8_t KNX_CB_Search( uint8_t param, uint8_t start = 0 ) -{ - for (uint32_t i = start; i < Settings.knx_CB_registered; ++i) - { - if ( Settings.knx_CB_param[i] == param ) - { - if ( Settings.knx_CB_addr[i] != 0 ) - { - if ( i >= start ) { return i; } - } - } - } - return KNX_Empty; -} - - -void KNX_ADD_GA( uint8_t GAop, uint8_t GA_FNUM, uint8_t GA_AREA, uint8_t GA_FDEF ) -{ - - if ( Settings.knx_GA_registered >= MAX_KNX_GA ) { return; } - if ( GA_FNUM == 0 && GA_AREA == 0 && GA_FDEF == 0 ) { return; } - - - Settings.knx_GA_param[Settings.knx_GA_registered] = GAop; - KNX_addr.ga.area = GA_FNUM; - KNX_addr.ga.line = GA_AREA; - KNX_addr.ga.member = GA_FDEF; - Settings.knx_GA_addr[Settings.knx_GA_registered] = KNX_addr.value; - - Settings.knx_GA_registered++; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ADD " GA #%d: %s " D_TO " %d/%d/%d"), - Settings.knx_GA_registered, - device_param_ga[GAop-1], - GA_FNUM, GA_AREA, GA_FDEF ); -} - - -void KNX_DEL_GA( uint8_t GAnum ) -{ - - uint8_t dest_offset = 0; - uint8_t src_offset = 0; - uint8_t len = 0; - - - Settings.knx_GA_param[GAnum-1] = 0; - - if (GAnum == 1) - { - - src_offset = 1; - - - - len = (Settings.knx_GA_registered - 1); - } - else if (GAnum == Settings.knx_GA_registered) - { - - } - else - { - - - - - dest_offset = GAnum -1 ; - src_offset = dest_offset + 1; - len = (Settings.knx_GA_registered - GAnum); - } - - if (len > 0) - { - memmove(Settings.knx_GA_param + dest_offset, Settings.knx_GA_param + src_offset, len * sizeof(uint8_t)); - memmove(Settings.knx_GA_addr + dest_offset, Settings.knx_GA_addr + src_offset, len * sizeof(uint16_t)); - } - - Settings.knx_GA_registered--; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_DELETE " GA #%d"), - GAnum ); -} - - -void KNX_ADD_CB( uint8_t CBop, uint8_t CB_FNUM, uint8_t CB_AREA, uint8_t CB_FDEF ) -{ - - if ( Settings.knx_CB_registered >= MAX_KNX_CB ) { return; } - if ( CB_FNUM == 0 && CB_AREA == 0 && CB_FDEF == 0 ) { return; } - - - if ( device_param[CBop-1].CB_id == KNX_Empty ) - { - - device_param[CBop-1].CB_id = knx.callback_register("", KNX_CB_Action, &device_param[CBop-1]); - - - - - } - - Settings.knx_CB_param[Settings.knx_CB_registered] = CBop; - KNX_addr.ga.area = CB_FNUM; - KNX_addr.ga.line = CB_AREA; - KNX_addr.ga.member = CB_FDEF; - Settings.knx_CB_addr[Settings.knx_CB_registered] = KNX_addr.value; - - knx.callback_assign( device_param[CBop-1].CB_id, KNX_addr ); - - Settings.knx_CB_registered++; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ADD " CB #%d: %d/%d/%d " D_TO " %s"), - Settings.knx_CB_registered, - CB_FNUM, CB_AREA, CB_FDEF, - device_param_cb[CBop-1] ); -} - - -void KNX_DEL_CB( uint8_t CBnum ) -{ - uint8_t oldparam = Settings.knx_CB_param[CBnum-1]; - uint8_t dest_offset = 0; - uint8_t src_offset = 0; - uint8_t len = 0; - - - knx.callback_unassign(CBnum-1); - Settings.knx_CB_param[CBnum-1] = 0; - - if (CBnum == 1) - { - - src_offset = 1; - - - - len = (Settings.knx_CB_registered - 1); - } - else if (CBnum == Settings.knx_CB_registered) - { - - } - else - { - - - - - dest_offset = CBnum -1 ; - src_offset = dest_offset + 1; - len = (Settings.knx_CB_registered - CBnum); - } - - if (len > 0) - { - memmove(Settings.knx_CB_param + dest_offset, Settings.knx_CB_param + src_offset, len * sizeof(uint8_t)); - memmove(Settings.knx_CB_addr + dest_offset, Settings.knx_CB_addr + src_offset, len * sizeof(uint16_t)); - } - - Settings.knx_CB_registered--; - - - if ( KNX_CB_Search( oldparam ) == KNX_Empty ) { - knx.callback_deregister( device_param[oldparam-1].CB_id ); - device_param[oldparam-1].CB_id = KNX_Empty; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_DELETE " CB #%d"), CBnum ); -} - - -bool KNX_CONFIG_NOT_MATCH(void) -{ - - for (uint32_t i = 0; i < KNX_MAX_device_param; ++i) - { - if ( !device_param[i].show ) { - - - - if ( KNX_GA_Search(i+1) != KNX_Empty ) { return true; } - - if ( i < 8 ) - { - if ( KNX_CB_Search(i+1) != KNX_Empty ) { return true; } - if ( KNX_CB_Search(i+9) != KNX_Empty ) { return true; } - } - - if ( i > 15 ) - { - if ( KNX_CB_Search(i+1) != KNX_Empty ) { return true; } - } - } - } - - - for (uint32_t i = 0; i < Settings.knx_GA_registered; ++i) - { - if ( Settings.knx_GA_param[i] != 0 ) - { - if ( Settings.knx_GA_addr[i] == 0 ) - { - return true; - } - } - } - for (uint32_t i = 0; i < Settings.knx_CB_registered; ++i) - { - if ( Settings.knx_CB_param[i] != 0 ) - { - if ( Settings.knx_CB_addr[i] == 0 ) - { - return true; - } - } - } - - return false; -} - - -void KNXStart(void) -{ - knx.start(nullptr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_START)); -} - - -void KNX_INIT(void) -{ - - if (Settings.knx_GA_registered > MAX_KNX_GA) { Settings.knx_GA_registered = MAX_KNX_GA; } - if (Settings.knx_CB_registered > MAX_KNX_CB) { Settings.knx_CB_registered = MAX_KNX_CB; } - - - KNX_physs_addr.value = Settings.knx_physsical_addr; - knx.physical_address_set( KNX_physs_addr ); -# 472 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_11_knx.ino" - for (uint32_t i = 0; i < devices_present; ++i) - { - device_param[i].show = true; - } - for (uint32_t i = GPIO_SWT1; i < GPIO_SWT4 + 1; ++i) - { - if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_SWT1 + 8].show = true; } - } - for (uint32_t i = GPIO_KEY1; i < GPIO_KEY4 + 1; ++i) - { - if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_KEY1 + 8].show = true; } - } - for (uint32_t i = GPIO_SWT1_NP; i < GPIO_SWT4_NP + 1; ++i) - { - if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_SWT1_NP + 8].show = true; } - } - for (uint32_t i = GPIO_KEY1_NP; i < GPIO_KEY4_NP + 1; ++i) - { - if (GetUsedInModule(i, my_module.io)) { device_param[i - GPIO_KEY1_NP + 8].show = true; } - } - if (GetUsedInModule(GPIO_DHT11, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } - if (GetUsedInModule(GPIO_DHT22, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } - if (GetUsedInModule(GPIO_SI7021, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } -#ifdef USE_DS18x20 - if (GetUsedInModule(GPIO_DSB, my_module.io)) { device_param[KNX_TEMPERATURE-1].show = true; } -#endif - if (GetUsedInModule(GPIO_DHT11, my_module.io)) { device_param[KNX_HUMIDITY-1].show = true; } - if (GetUsedInModule(GPIO_DHT22, my_module.io)) { device_param[KNX_HUMIDITY-1].show = true; } - if (GetUsedInModule(GPIO_SI7021, my_module.io)) { device_param[KNX_HUMIDITY-1].show = true; } - -#if defined(USE_ENERGY_SENSOR) - - if ( energy_flg != ENERGY_NONE ) { - device_param[KNX_ENERGY_POWER-1].show = true; - device_param[KNX_ENERGY_DAILY-1].show = true; - device_param[KNX_ENERGY_START-1].show = true; - device_param[KNX_ENERGY_TOTAL-1].show = true; - device_param[KNX_ENERGY_VOLTAGE-1].show = true; - device_param[KNX_ENERGY_CURRENT-1].show = true; - device_param[KNX_ENERGY_POWERFACTOR-1].show = true; - } -#endif - -#ifdef USE_RULES - device_param[KNX_SLOT1-1].show = true; - device_param[KNX_SLOT2-1].show = true; - device_param[KNX_SLOT3-1].show = true; - device_param[KNX_SLOT4-1].show = true; - device_param[KNX_SLOT5-1].show = true; -#endif - - - if (KNX_CONFIG_NOT_MATCH()) { - Settings.knx_GA_registered = 0; - Settings.knx_CB_registered = 0; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_DELETE " " D_KNX_PARAMETERS)); - } - - - - - uint8_t j; - for (uint32_t i = 0; i < Settings.knx_CB_registered; ++i) - { - j = Settings.knx_CB_param[i]; - if ( j > 0 ) - { - device_param[j-1].CB_id = knx.callback_register("", KNX_CB_Action, &device_param[j-1]); - - - - KNX_addr.value = Settings.knx_CB_addr[i]; - knx.callback_assign( device_param[j-1].CB_id, KNX_addr ); - } - } -} - - -void KNX_CB_Action(message_t const &msg, void *arg) -{ - device_parameters_t *chan = (device_parameters_t *)arg; - if (!(Settings.flag.knx_enabled)) { return; } - - char tempchar[33]; - - if (msg.data_len == 1) { - - sprintf(tempchar,"%d",msg.data[0]); - } else { - - float tempvar = knx.data_to_2byte_float(msg.data); - dtostrfd(tempvar,2,tempchar); - } - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %s " D_TO " %s"), - msg.received_on.ga.area, msg.received_on.ga.line, msg.received_on.ga.member, - (msg.ct == KNX_CT_WRITE) ? D_KNX_COMMAND_WRITE : (msg.ct == KNX_CT_READ) ? D_KNX_COMMAND_READ : D_KNX_COMMAND_OTHER, - tempchar, - device_param_cb[(chan->type)-1]); - - switch (msg.ct) - { - case KNX_CT_WRITE: - if (chan->type < 9) - { - ExecuteCommandPower(chan->type, msg.data[0], SRC_KNX); - } - else if (chan->type < 17) - { - if (!toggle_inhibit) { - ExecuteCommandPower((chan->type) -8, POWER_TOGGLE, SRC_KNX); - if (Settings.flag.knx_enable_enhancement) { - toggle_inhibit = TOGGLE_INHIBIT_TIME; - } - } - } -#ifdef USE_RULES - else if ((chan->type >= KNX_SLOT1) && (chan->type <= KNX_SLOT5)) - { - if (!toggle_inhibit) { - char command[25]; - if (msg.data_len == 1) { - - snprintf_P(command, sizeof(command), PSTR("event KNXRX_CMND%d=%d"), ((chan->type) - KNX_SLOT1 + 1 ), msg.data[0]); - } else { - - snprintf_P(command, sizeof(command), PSTR("event KNXRX_VAL%d=%s"), ((chan->type) - KNX_SLOT1 + 1 ), tempchar); - } - ExecuteCommand(command, SRC_KNX); - if (Settings.flag.knx_enable_enhancement) { - toggle_inhibit = TOGGLE_INHIBIT_TIME; - } - } - } -#endif - break; - - case KNX_CT_READ: - if (chan->type < 9) - { - knx.answer_1bit(msg.received_on, chan->last_state); - if (Settings.flag.knx_enable_enhancement) { - knx.answer_1bit(msg.received_on, chan->last_state); - knx.answer_1bit(msg.received_on, chan->last_state); - } - } - else if (chan->type == KNX_TEMPERATURE) - { - knx.answer_2byte_float(msg.received_on, last_temp); - if (Settings.flag.knx_enable_enhancement) { - knx.answer_2byte_float(msg.received_on, last_temp); - knx.answer_2byte_float(msg.received_on, last_temp); - } - } - else if (chan->type == KNX_HUMIDITY) - { - knx.answer_2byte_float(msg.received_on, last_hum); - if (Settings.flag.knx_enable_enhancement) { - knx.answer_2byte_float(msg.received_on, last_hum); - knx.answer_2byte_float(msg.received_on, last_hum); - } - } -#ifdef USE_RULES - else if ((chan->type >= KNX_SLOT1) && (chan->type <= KNX_SLOT5)) - { - if (!toggle_inhibit) { - char command[25]; - snprintf_P(command, sizeof(command), PSTR("event KNXRX_REQ%d"), ((chan->type) - KNX_SLOT1 + 1 ) ); - ExecuteCommand(command, SRC_KNX); - if (Settings.flag.knx_enable_enhancement) { - toggle_inhibit = TOGGLE_INHIBIT_TIME; - } - } - } -#endif - break; - } -} - - -void KnxUpdatePowerState(uint8_t device, power_t state) -{ - if (!(Settings.flag.knx_enabled)) { return; } - - device_param[device -1].last_state = bitRead(state, device -1); - - - uint8_t i = KNX_GA_Search(device); - while ( i != KNX_Empty ) { - KNX_addr.value = Settings.knx_GA_addr[i]; - knx.write_1bit(KNX_addr, device_param[device -1].last_state); - if (Settings.flag.knx_enable_enhancement) { - knx.write_1bit(KNX_addr, device_param[device -1].last_state); - knx.write_1bit(KNX_addr, device_param[device -1].last_state); - } - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), - device_param_ga[device -1], device_param[device -1].last_state, - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - - i = KNX_GA_Search(device, i + 1); - } -} - - -void KnxSendButtonPower(void) -{ - if (!(Settings.flag.knx_enabled)) { return; } - - uint32_t key = (XdrvMailbox.payload >> 16) & 0xFF; - uint32_t device = XdrvMailbox.payload & 0xFF; - uint32_t state = (XdrvMailbox.payload >> 8) & 0xFF; -# 692 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_11_knx.ino" - uint8_t i = KNX_GA_Search(device + 8); - while ( i != KNX_Empty ) { - KNX_addr.value = Settings.knx_GA_addr[i]; - knx.write_1bit(KNX_addr, !(state == 0)); - if (Settings.flag.knx_enable_enhancement) { - knx.write_1bit(KNX_addr, !(state == 0)); - knx.write_1bit(KNX_addr, !(state == 0)); - } - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), - device_param_ga[device + 7], !(state == 0), - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - - i = KNX_GA_Search(device + 8, i + 1); - } - -} - - -void KnxSensor(uint8_t sensor_type, float value) -{ - if (sensor_type == KNX_TEMPERATURE) - { - last_temp = value; - } else if (sensor_type == KNX_HUMIDITY) - { - last_hum = value; - } - - if (!(Settings.flag.knx_enabled)) { return; } - - uint8_t i = KNX_GA_Search(sensor_type); - while ( i != KNX_Empty ) { - KNX_addr.value = Settings.knx_GA_addr[i]; - knx.write_2byte_float(KNX_addr, value); - if (Settings.flag.knx_enable_enhancement) { - knx.write_2byte_float(KNX_addr, value); - knx.write_2byte_float(KNX_addr, value); - } - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s " D_SENT_TO " %d.%d.%d "), - device_param_ga[sensor_type -1], - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - - i = KNX_GA_Search(sensor_type, i+1); - } -} - - - - - - -#ifdef USE_WEBSERVER -#ifdef USE_KNX_WEB_MENU -const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; - -const char HTTP_BTN_MENU_KNX[] PROGMEM = - "

"; - -const char HTTP_FORM_KNX[] PROGMEM = - "
" - " " D_KNX_PARAMETERS " " - "
" - "
" - "" D_KNX_PHYSICAL_ADDRESS " " - " . " - " . " - "" - "

" D_KNX_PHYSICAL_ADDRESS_NOTE "

" - "

" - - "
" - "" D_KNX_GROUP_ADDRESS_TO_WRITE "
" - - " / " - " / " - " "; - -const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM = - "

" - ""; - -const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM = - "" - ""; - -const char HTTP_FORM_KNX3[] PROGMEM = - "
%s -> %d / %d / %d

" - "
" - "" D_KNX_GROUP_ADDRESS_TO_READ "
"; - -const char HTTP_FORM_KNX4[] PROGMEM = - "-> -> ")); - WSContentSend_P(HTTP_FORM_KNX_GA, "GA_FNUM", "GA_AREA", "GA_FDEF"); - WSContentSend_P(HTTP_FORM_KNX_ADD_BTN, "GAwarning", (Settings.knx_GA_registered < MAX_KNX_GA) ? "" : "disabled", 1); - for (uint32_t i = 0; i < Settings.knx_GA_registered ; ++i) - { - if ( Settings.knx_GA_param[i] ) - { - KNX_addr.value = Settings.knx_GA_addr[i]; - WSContentSend_P(HTTP_FORM_KNX_ADD_TABLE_ROW, device_param_ga[Settings.knx_GA_param[i]-1], KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, i +1); - } - } - - WSContentSend_P(HTTP_FORM_KNX3); - WSContentSend_P(HTTP_FORM_KNX_GA, "CB_FNUM", "CB_AREA", "CB_FDEF"); - WSContentSend_P(HTTP_FORM_KNX4); - - uint8_t j; - for (uint32_t i = 0; i < KNX_MAX_device_param ; i++) - { - - if ( (i > 8) && (i < 16) ) { j=i-8; } else { j=i; } - if ( i == 8 ) { j = 0; } - if ( device_param[j].show ) - { - WSContentSend_P(HTTP_FORM_KNX_OPT, device_param[i].type, device_param_cb[i]); - } - } - WSContentSend_P(PSTR(" ")); - WSContentSend_P(HTTP_FORM_KNX_ADD_BTN, "CBwarning", (Settings.knx_CB_registered < MAX_KNX_CB) ? "" : "disabled", 2); - - for (uint32_t i = 0; i < Settings.knx_CB_registered ; ++i) - { - if ( Settings.knx_CB_param[i] ) - { - KNX_addr.value = Settings.knx_CB_addr[i]; - WSContentSend_P(HTTP_FORM_KNX_ADD_TABLE_ROW2, KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, device_param_cb[Settings.knx_CB_param[i]-1], i +1); - } - } - WSContentSend_P(PSTR("
")); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); - } - -} - - -void KNX_Save_Settings(void) -{ - String stmp; - address_t KNX_addr; - - Settings.flag.knx_enabled = Webserver->hasArg("b1"); - Settings.flag.knx_enable_enhancement = Webserver->hasArg("b2"); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ENABLED ": %d, " D_KNX_ENHANCEMENT ": %d"), - Settings.flag.knx_enabled, Settings.flag.knx_enable_enhancement ); - - stmp = Webserver->arg("area"); - KNX_addr.pa.area = stmp.toInt(); - stmp = Webserver->arg("line"); - KNX_addr.pa.line = stmp.toInt(); - stmp = Webserver->arg("member"); - KNX_addr.pa.member = stmp.toInt(); - Settings.knx_physsical_addr = KNX_addr.value; - knx.physical_address_set( KNX_addr ); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_KNX_PHYSICAL_ADDRESS ": %d.%d.%d "), - KNX_addr.pa.area, KNX_addr.pa.line, KNX_addr.pa.member ); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "GA: %d"), - Settings.knx_GA_registered ); - for (uint32_t i = 0; i < Settings.knx_GA_registered ; ++i) - { - KNX_addr.value = Settings.knx_GA_addr[i]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "GA #%d: %s " D_TO " %d/%d/%d"), - i+1, device_param_ga[Settings.knx_GA_param[i]-1], - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member ); - - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "CB: %d"), - Settings.knx_CB_registered ); - for (uint32_t i = 0; i < Settings.knx_CB_registered ; ++i) - { - KNX_addr.value = Settings.knx_CB_addr[i]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX "CB #%d: %d/%d/%d " D_TO " %s"), - i+1, - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, - device_param_cb[Settings.knx_CB_param[i]-1] ); - } -} - -#endif -#endif - - - - - -void CmndKnxTxCmnd(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNXTX_CMNDS) && (XdrvMailbox.data_len > 0) && Settings.flag.knx_enabled) { - - - - uint8_t i = KNX_GA_Search(XdrvMailbox.index + KNX_SLOT1 -1); - while ( i != KNX_Empty ) { - KNX_addr.value = Settings.knx_GA_addr[i]; - knx.write_1bit(KNX_addr, !(XdrvMailbox.payload == 0)); - if (Settings.flag.knx_enable_enhancement) { - knx.write_1bit(KNX_addr, !(XdrvMailbox.payload == 0)); - knx.write_1bit(KNX_addr, !(XdrvMailbox.payload == 0)); - } - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %d " D_SENT_TO " %d.%d.%d"), - device_param_ga[XdrvMailbox.index + KNX_SLOT1 -2], !(XdrvMailbox.payload == 0), - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - - i = KNX_GA_Search(XdrvMailbox.index + KNX_SLOT1 -1, i + 1); - } - ResponseCmndIdxChar (XdrvMailbox.data ); - } -} - -void CmndKnxTxVal(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNXTX_CMNDS) && (XdrvMailbox.data_len > 0) && Settings.flag.knx_enabled) { - - - - uint8_t i = KNX_GA_Search(XdrvMailbox.index + KNX_SLOT1 -1); - while ( i != KNX_Empty ) { - KNX_addr.value = Settings.knx_GA_addr[i]; - - float tempvar = CharToFloat(XdrvMailbox.data); - dtostrfd(tempvar,2,XdrvMailbox.data); - - knx.write_2byte_float(KNX_addr, tempvar); - if (Settings.flag.knx_enable_enhancement) { - knx.write_2byte_float(KNX_addr, tempvar); - knx.write_2byte_float(KNX_addr, tempvar); - } - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %s " D_SENT_TO " %d.%d.%d"), - device_param_ga[XdrvMailbox.index + KNX_SLOT1 -2], XdrvMailbox.data, - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); - - i = KNX_GA_Search(XdrvMailbox.index + KNX_SLOT1 -1, i + 1); - } - ResponseCmndIdxChar (XdrvMailbox.data ); - } -} - -void CmndKnxEnabled(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - Settings.flag.knx_enabled = XdrvMailbox.payload; - } - ResponseCmndChar (GetStateText(Settings.flag.knx_enabled) ); -} - -void CmndKnxEnhanced(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - Settings.flag.knx_enable_enhancement = XdrvMailbox.payload; - } - ResponseCmndChar (GetStateText(Settings.flag.knx_enable_enhancement) ); -} - -void CmndKnxPa(void) -{ - if (XdrvMailbox.data_len) { - if (strstr(XdrvMailbox.data, ".") != nullptr) { - char sub_string[XdrvMailbox.data_len]; - - int pa_area = atoi(subStr(sub_string, XdrvMailbox.data, ".", 1)); - int pa_line = atoi(subStr(sub_string, XdrvMailbox.data, ".", 2)); - int pa_member = atoi(subStr(sub_string, XdrvMailbox.data, ".", 3)); - - if ( ((pa_area == 0) && (pa_line == 0) && (pa_member == 0)) - || (pa_area > 15) || (pa_line > 15) || (pa_member > 255) ) { - Response_P (PSTR("{\"%s\":\"" D_ERROR "\"}"), XdrvMailbox.command ); - return; - } - - KNX_addr.pa.area = pa_area; - KNX_addr.pa.line = pa_line; - KNX_addr.pa.member = pa_member; - Settings.knx_physsical_addr = KNX_addr.value; - } - } - KNX_addr.value = Settings.knx_physsical_addr; - Response_P (PSTR("{\"%s\":\"%d.%d.%d\"}"), - XdrvMailbox.command, KNX_addr.pa.area, KNX_addr.pa.line, KNX_addr.pa.member ); -} - -void CmndKnxGa(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNX_GA)) { - if (XdrvMailbox.data_len) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { - char sub_string[XdrvMailbox.data_len]; - - int ga_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); - int ga_area = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - int ga_line = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - int ga_member = atoi(subStr(sub_string, XdrvMailbox.data, ",", 4)); - - if ( ((ga_area == 0) && (ga_line == 0) && (ga_member == 0)) - || (ga_area > 31) || (ga_line > 7) || (ga_member > 255) - || (ga_option < 0) || ((ga_option > KNX_MAX_device_param ) && (ga_option != KNX_Empty)) - || (!device_param[ga_option-1].show) ) { - Response_P (PSTR("{\"%s\":\"" D_ERROR "\"}"), XdrvMailbox.command ); - return; - } - - KNX_addr.ga.area = ga_area; - KNX_addr.ga.line = ga_line; - KNX_addr.ga.member = ga_member; - - if ( XdrvMailbox.index > Settings.knx_GA_registered ) { - Settings.knx_GA_registered ++; - XdrvMailbox.index = Settings.knx_GA_registered; - } - - Settings.knx_GA_addr[XdrvMailbox.index -1] = KNX_addr.value; - Settings.knx_GA_param[XdrvMailbox.index -1] = ga_option; - } else { - if ( (XdrvMailbox.payload <= Settings.knx_GA_registered) && (XdrvMailbox.payload > 0) ) { - XdrvMailbox.index = XdrvMailbox.payload; - } else { - Response_P (PSTR("{\"%s\":\"" D_ERROR "\"}"), XdrvMailbox.command ); - return; - } - } - if ( XdrvMailbox.index <= Settings.knx_GA_registered ) { - KNX_addr.value = Settings.knx_GA_addr[XdrvMailbox.index -1]; - Response_P (PSTR("{\"%s%d\":\"%s, %d/%d/%d\"}"), - XdrvMailbox.command, XdrvMailbox.index, device_param_ga[Settings.knx_GA_param[XdrvMailbox.index-1]-1], - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member ); - } - } else { - ResponseCmndNumber (Settings.knx_GA_registered ); - } - } -} - -void CmndKnxCb(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNX_CB)) { - if (XdrvMailbox.data_len) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { - char sub_string[XdrvMailbox.data_len]; - - int cb_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); - int cb_area = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - int cb_line = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - int cb_member = atoi(subStr(sub_string, XdrvMailbox.data, ",", 4)); - - if ( ((cb_area == 0) && (cb_line == 0) && (cb_member == 0)) - || (cb_area > 31) || (cb_line > 7) || (cb_member > 255) - || (cb_option < 0) || ((cb_option > KNX_MAX_device_param ) && (cb_option != KNX_Empty)) - || (!device_param[cb_option-1].show) ) { - Response_P (PSTR("{\"%s\":\"" D_ERROR "\"}"), XdrvMailbox.command ); - return; - } - - KNX_addr.ga.area = cb_area; - KNX_addr.ga.line = cb_line; - KNX_addr.ga.member = cb_member; - - if ( XdrvMailbox.index > Settings.knx_CB_registered ) { - Settings.knx_CB_registered ++; - XdrvMailbox.index = Settings.knx_CB_registered; - } - - Settings.knx_CB_addr[XdrvMailbox.index -1] = KNX_addr.value; - Settings.knx_CB_param[XdrvMailbox.index -1] = cb_option; - } else { - if ( (XdrvMailbox.payload <= Settings.knx_CB_registered) && (XdrvMailbox.payload > 0) ) { - XdrvMailbox.index = XdrvMailbox.payload; - } else { - Response_P (PSTR("{\"%s\":\"" D_ERROR "\"}"), XdrvMailbox.command ); - return; - } - } - if ( XdrvMailbox.index <= Settings.knx_CB_registered ) { - KNX_addr.value = Settings.knx_CB_addr[XdrvMailbox.index -1]; - Response_P (PSTR("{\"%s%d\":\"%s, %d/%d/%d\"}"), - XdrvMailbox.command, XdrvMailbox.index, device_param_cb[Settings.knx_CB_param[XdrvMailbox.index-1]-1], - KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member ); - } - } else { - ResponseCmndNumber (Settings.knx_CB_registered ); - } - } -} - - - - - -bool Xdrv11(uint8_t function) -{ - bool result = false; - switch (function) { - case FUNC_LOOP: - if (!global_state.wifi_down) { knx.loop(); } - break; - case FUNC_EVERY_50_MSECOND: - if (toggle_inhibit) { - toggle_inhibit--; - } - break; - case FUNC_ANY_KEY: - KnxSendButtonPower(); - break; -#ifdef USE_WEBSERVER -#ifdef USE_KNX_WEB_MENU - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_KNX); - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/kn", HandleKNXConfiguration); - break; -#endif -#endif - case FUNC_COMMAND: - result = DecodeCommand(kKnxCommands, KnxCommand); - break; - case FUNC_PRE_INIT: - KNX_INIT(); - break; - - - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_12_home_assistant.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_12_home_assistant.ino" -#ifdef USE_HOME_ASSISTANT - -#define XDRV_12 12 - - -const char kHAssJsonSensorTypes[] PROGMEM = - D_JSON_TEMPERATURE "|" D_JSON_DEWPOINT "|" D_JSON_PRESSURE "|" D_JSON_PRESSUREATSEALEVEL "|" - D_JSON_APPARENT_POWERUSAGE "|Battery|" D_JSON_CURRENT "|" D_JSON_DISTANCE "|" D_JSON_FREQUENCY "|" D_JSON_HUMIDITY "|" D_JSON_ILLUMINANCE "|" - D_JSON_MOISTURE "|PB0.3|PB0.5|PB1|PB2.5|PB5|PB10|PM1|PM2.5|PM10|" D_JSON_POWERFACTOR "|" D_JSON_POWERUSAGE "|" - D_JSON_REACTIVE_POWERUSAGE "|" D_JSON_TODAY "|" D_JSON_TOTAL "|" D_JSON_VOLTAGE "|" D_JSON_WEIGHT "|" D_JSON_YESTERDAY "|" - D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC "|"; -const char kHAssJsonSensorUnits[] PROGMEM = - "||||" - "VA|%|A|Cm|Hz|%|LX|" - "%|ppd|ppd|ppd|ppd|ppd|ppd|µg/m³|µg/m³|µg/m³|Cos φ|W|" - "VAr|kWh|kWh|V|Kg|kWh|" - "ppm|ppm|ppb|"; -const char kHAssJsonSensorDevCla[] PROGMEM = - "dev_cla\":\"temperature|ic\":\"mdi:weather-rainy|dev_cla\":\"pressure|dev_cla\":\"pressure|" - "dev_cla\":\"power|dev_cla\":\"battery|ic\":\"mdi:alpha-a-circle-outline|ic\":\"mdi:leak|ic\":\"mdi:current-ac|dev_cla\":\"humidity|dev_cla\":\"illuminance|" - "ic\":\"mdi:cup-water|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|" - "ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:alpha-f-circle-outline|dev_cla\":\"power|" - "dev_cla\":\"power|dev_cla\":\"power|dev_cla\":\"power|ic\":\"mdi:alpha-v-circle-outline|ic\":\"mdi:scale|dev_cla\":\"power|" - "ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2|"; - - - -const char HASS_DISCOVER_SENSOR[] PROGMEM = - ",\"unit_of_meas\":\"%s\",\"%s\"," - "\"frc_upd\":true," - "\"val_tpl\":\"{{value_json['%s']['%s']"; - -const char HASS_DISCOVER_BASE[] PROGMEM = - "{\"name\":\"%s\"," - "\"stat_t\":\"%s\"," - "\"avty_t\":\"%s\"," - "\"pl_avail\":\"" D_ONLINE "\"," - "\"pl_not_avail\":\"" D_OFFLINE "\""; - -const char HASS_DISCOVER_RELAY[] PROGMEM = - ",\"cmd_t\":\"%s\"," - "\"val_tpl\":\"{{value_json.%s}}\"," - "\"pl_off\":\"%s\"," - "\"pl_on\":\"%s\""; - -const char HASS_DISCOVER_BIN_SWITCH[] PROGMEM = - ",\"val_tpl\":\"{{value_json.%s}}\"," - "\"frc_upd\":true," - "\"pl_on\":\"%s\"," - "\"pl_off\":\"%s\""; - -const char HASS_DISCOVER_BIN_PIR[] PROGMEM = - ",\"val_tpl\":\"{{value_json.%s}}\"," - "\"frc_upd\":true," - "\"pl_on\":\"%s\"," - "\"off_dly\":1"; - -const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM = - ",\"bri_cmd_t\":\"%s\"," - "\"bri_stat_t\":\"%s\"," - "\"bri_scl\":100," - "\"on_cmd_type\":\"%s\"," - "\"bri_val_tpl\":\"{{value_json." D_CMND_DIMMER "}}\""; - -const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM = - ",\"rgb_cmd_t\":\"%s2\"," - "\"rgb_stat_t\":\"%s\"," - "\"rgb_val_tpl\":\"{{value_json." D_CMND_COLOR ".split(',')[0:3]|join(',')}}\""; - -const char HASS_DISCOVER_LIGHT_WHITE[] PROGMEM = - ",\"whit_val_cmd_t\":\"%s\"," - "\"whit_val_stat_t\":\"%s\"," - "\"whit_val_scl\":100," - "\"whit_val_tpl\":\"{{value_json.Channel[3]}}\""; - -const char HASS_DISCOVER_LIGHT_CT[] PROGMEM = - ",\"clr_temp_cmd_t\":\"%s\"," - "\"clr_temp_stat_t\":\"%s\"," - "\"clr_temp_val_tpl\":\"{{value_json." D_CMND_COLORTEMPERATURE "}}\""; - -const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM = - ",\"fx_cmd_t\":\"%s\"," - "\"fx_stat_t\":\"%s\"," - "\"fx_val_tpl\":\"{{value_json." D_CMND_SCHEME "}}\"," - "\"fx_list\":[\"0\",\"1\",\"2\",\"3\",\"4\"]"; - -const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM = - ",\"json_attr_t\":\"%s\"," - "\"unit_of_meas\":\"%%\"," - "\"val_tpl\":\"{{value_json['" D_JSON_RSSI "']}}\"," - "\"ic\":\"mdi:information-outline\""; - -const char HASS_DISCOVER_DEVICE_INFO[] PROGMEM = - ",\"uniq_id\":\"%s\"," - "\"dev\":{\"ids\":[\"%06X\"]," - "\"name\":\"%s\"," - "\"mdl\":\"%s\"," - "\"sw\":\"%s%s\"," - "\"mf\":\"Tasmota\"}"; - -const char HASS_DISCOVER_DEVICE_INFO_SHORT[] PROGMEM = - ",\"uniq_id\":\"%s\"," - "\"dev\":{\"ids\":[\"%06X\"]}"; - -const char HASS_TRIGGER_TYPE[] PROGMEM = - "{\"atype\":\"trigger\"," - "\"t\":\"%sT\"," - "\"pl\":\"{\\\"TRIG\\\":\\\"%s\\\"}\"," - "\"type\":\"%s\"," - "\"stype\":\"%s\"," - "\"dev\":{\"ids\":[\"%06X\"]}}"; - -const char kHAssTriggerType[] PROGMEM = - "none|button_short_press|button_long_press|button_double_press"; - -uint8_t hass_init_step = 0; -uint8_t hass_mode = 0; -int hass_tele_period = 0; - -void TryResponseAppend_P(const char *format, ...) -{ - va_list args; - va_start(args, format); - char dummy[2]; - int dlen = vsnprintf_P(dummy, 1, format, args); - - int mlen = strlen(mqtt_data); - int slen = sizeof(mqtt_data) - 1 - mlen; - if (dlen >= slen) - { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: MQTT discovery failed due to too long topic or friendly name. " - "Please shorten topic and friendly name. Failed to format(%u/%u):"), - dlen, slen); - va_start(args, format); - vsnprintf_P(log_data, sizeof(log_data), format, args); - AddLog(LOG_LEVEL_ERROR); - } - else - { - va_start(args, format); - vsnprintf_P(mqtt_data + mlen, slen, format, args); - } - va_end(args); -} - -void HAssAnnounceRelayLight(void) -{ - char stopic[TOPSZ]; - char stemp1[TOPSZ]; - char stemp2[TOPSZ]; - char stemp3[TOPSZ]; - char unique_id[30]; - bool is_light = false; - bool is_topic_light = false; - - for (uint32_t i = 1; i <= MAX_RELAYS; i++) - { - is_light = ((i == devices_present) && (light_type)); - is_topic_light = Settings.flag.hass_light || is_light; - - mqtt_data[0] = '\0'; - - - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP_getChipId(), (is_topic_light) ? "RL" : "LI", i); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), - (is_topic_light) ? "switch" : "light", unique_id); - MqttPublish(stopic, true); - - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d"), ESP_getChipId(), (is_topic_light) ? "LI" : "RL", i); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), - (is_topic_light) ? "light" : "switch", unique_id); - - if (Settings.flag.hass_discovery && (i <= devices_present)) - { - char name[33 + 2]; - char value_template[33]; - char prefix[TOPSZ]; - char *command_topic = stemp1; - char *state_topic = stemp2; - char *availability_topic = stemp3; - - if (i > MAX_FRIENDLYNAMES) { - snprintf_P(name, sizeof(name), PSTR("%s %d"), SettingsText(SET_FRIENDLYNAME1), i); - } else { - snprintf_P(name, sizeof(name), SettingsText(SET_FRIENDLYNAME1 + i - 1)); - } - GetPowerDevice(value_template, i, sizeof(value_template), Settings.flag.device_index_enable); - GetTopic_P(command_topic, CMND, mqtt_topic, value_template); - GetTopic_P(state_topic, TELE, mqtt_topic, D_RSLT_STATE); - GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - - Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); - TryResponseAppend_P(HASS_DISCOVER_RELAY, command_topic, value_template, SettingsText(SET_STATE_TXT1), SettingsText(SET_STATE_TXT2)); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId()); - -#ifdef USE_LIGHT - if (is_light -#ifdef ESP8266 - || PWM_DIMMER == my_module_type -#endif - ) - { - char *brightness_command_topic = stemp1; - - GetTopic_P(brightness_command_topic, CMND, mqtt_topic, D_CMND_DIMMER); - strncpy_P(stemp3, Settings.flag.not_power_linked ? PSTR("last") : PSTR("brightness"), sizeof(stemp3)); - TryResponseAppend_P(HASS_DISCOVER_LIGHT_DIMMER, brightness_command_topic, state_topic, stemp3); - - if (Light.subtype >= LST_RGB) - { - char *rgb_command_topic = stemp1; - - GetTopic_P(rgb_command_topic, CMND, mqtt_topic, D_CMND_COLOR); - TryResponseAppend_P(HASS_DISCOVER_LIGHT_COLOR, rgb_command_topic, state_topic); - - char *effect_command_topic = stemp1; - GetTopic_P(effect_command_topic, CMND, mqtt_topic, D_CMND_SCHEME); - TryResponseAppend_P(HASS_DISCOVER_LIGHT_SCHEME, effect_command_topic, state_topic); - } - if (LST_RGBW == Light.subtype) - { - char *white_temp_command_topic = stemp1; - - GetTopic_P(white_temp_command_topic, CMND, mqtt_topic, D_CMND_WHITE); - TryResponseAppend_P(HASS_DISCOVER_LIGHT_WHITE, white_temp_command_topic, state_topic); - } - if ((LST_COLDWARM == Light.subtype) || (LST_RGBCW == Light.subtype)) - { - char *color_temp_command_topic = stemp1; - - GetTopic_P(color_temp_command_topic, CMND, mqtt_topic, D_CMND_COLORTEMPERATURE); - TryResponseAppend_P(HASS_DISCOVER_LIGHT_CT, color_temp_command_topic, state_topic); - } - } -#endif - TryResponseAppend_P(PSTR("}")); - } - MqttPublish(stopic, true); - } -} - -void HAssAnnouncerTriggers(uint8_t device, uint8_t present, uint8_t key, uint8_t toggle, uint8_t hold) -{ - - - char stopic[TOPSZ]; - char stemp1[TOPSZ]; - char stemp2[TOPSZ]; - char unique_id[30]; - - mqtt_data[0] = '\0'; - - for (uint8_t i = 2; i <= 3; i++) { - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%d_%s"), ESP_getChipId(), key ? "SW" : "BTN", device + 1, GetStateText(i)); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/device_automation/%s/config"), unique_id); - - if (Settings.flag.hass_discovery && present) { - char name[33 + 6]; - char value_template[33]; - char prefix[TOPSZ]; - char *state_topic = stemp1; - char *availability_topic = stemp2; - char jsoname[8]; - - GetPowerDevice(value_template, device + 1, sizeof(value_template), key + Settings.flag.device_index_enable); - snprintf_P(jsoname, sizeof(jsoname), PSTR("%s%d"), key ? "SWITCH" : "BUTTON", device + 1); - GetTopic_P(state_topic, STAT, mqtt_topic, jsoname); - GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - - char param[21]; - char subtype[9]; - uint8_t pload = toggle; - - if ((i == 2 && toggle != 0) || (i == 3 && hold != 0)) { - if (i == 3) { pload = hold; } - GetTextIndexed(param, sizeof(param), pload, kHAssTriggerType); - snprintf_P(subtype, sizeof(subtype), PSTR("%s_%d"), key ? "switch" : "button", device + 1); - Response_P(HASS_TRIGGER_TYPE, state_topic, GetStateText(i), param, subtype, ESP_getChipId()); - } else { mqtt_data[0] = '\0'; } - } - MqttPublish(stopic, true); - } -} - -void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint8_t toggle, uint8_t pir) -{ - char stopic[TOPSZ]; - char stemp1[TOPSZ]; - char stemp2[TOPSZ]; - char unique_id[30]; - - mqtt_data[0] = '\0'; - - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_SW_%d"), ESP_getChipId(), device + 1); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/binary_sensor/%s/config"), unique_id); - - - if (Settings.flag.hass_discovery && present ) { - if (!toggle || dual) { - char name[33 + 6]; - char value_template[33]; - char prefix[TOPSZ]; - char *state_topic = stemp1; - char *availability_topic = stemp2; - char jsoname[8]; - - GetPowerDevice(value_template, device + 1, sizeof(value_template), 1 + Settings.flag.device_index_enable); - snprintf_P(jsoname, sizeof(jsoname), PSTR("SWITCH%d"), device + 1); - GetTopic_P(state_topic, STAT, mqtt_topic, jsoname); - GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - - snprintf_P(name, sizeof(name), PSTR("%s Switch%d"), SettingsText(SET_FRIENDLYNAME1), device + 1); - Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); - if (!pir) { - TryResponseAppend_P(HASS_DISCOVER_BIN_SWITCH, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2), SettingsText(SET_STATE_TXT1)); - } else { - TryResponseAppend_P(HASS_DISCOVER_BIN_PIR, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2)); - } - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId()); - TryResponseAppend_P(PSTR("}")); - } - } - MqttPublish(stopic, true); -} - -void HAssAnnounceSwitches(void) -{ - for (uint32_t switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) - { - uint8_t switch_present = 0; - uint8_t dual = 0; - uint8_t toggle = 1; - uint8_t hold = 0; - uint8_t pir = 0; - - if (pin[GPIO_SWT1 + switch_index] < 99) { switch_present = 1; } - - if (KeyTopicActive(1) && strcmp(SettingsText(SET_MQTT_SWITCH_TOPIC), mqtt_topic)) - { -# 383 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_12_home_assistant.ino" - uint8_t swmode = Settings.switchmode[switch_index]; - - switch (swmode) { - case FOLLOW: - case FOLLOW_INV: - toggle = 0; - break; - case PUSHBUTTON: - case PUSHBUTTON_INV: - dual = 1; - break; - case PUSHBUTTONHOLD: - case PUSHBUTTONHOLD_INV: - dual = 1; - hold = 2; - break; - case TOGGLEMULTI: - hold = 3; - break; - case FOLLOWMULTI: - case FOLLOWMULTI_INV: - dual = 1; - toggle = 0; - hold = 3; - break; - case PUSHON: - case PUSHON_INV: - toggle = 0; - pir = 1; - } - - } else { switch_present = 0;} - - HAssAnnouncerTriggers(switch_index, switch_present, 1, toggle, hold); - HAssAnnouncerBinSensors(switch_index, switch_present, dual, toggle, pir); - } -} - - -void HAssAnnounceButtons(void) -{ - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) - { - uint8_t button_present = 0; - uint8_t toggle = 1; - uint8_t hold = 0; - -#ifdef ESP8266 - if (!button_index && ((SONOFF_DUAL == my_module_type) || (CH4 == my_module_type))) - { - button_present = 1; - } else -#endif - { - if (pin[GPIO_KEY1 + button_index] < 99) { - button_present = 1; - } - } -# 455 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_12_home_assistant.ino" - if (Settings.flag.button_restrict) { - if (!Settings.flag.button_single) { - hold = 2; - } - } - - if (Settings.flag.button_swap) { - if (!Settings.flag.button_single) { - if (!Settings.flag.button_restrict) { - hold = 0; - } - toggle = 3; - } else {toggle = 0; hold = 0;} - } - - if (KeyTopicActive(0)) { - - if (!strcmp(SettingsText(SET_MQTT_BUTTON_TOPIC), mqtt_topic)) { - toggle = 0; - } - - } else { button_present = 0; } - - HAssAnnouncerTriggers(button_index, button_present, 0, toggle, hold); - } -} - -void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const char *MultiSubName, uint8_t subqty, uint8_t subidx, uint8_t nested, const char* SubKey) -{ - char stopic[TOPSZ]; - char stemp1[TOPSZ]; - char stemp2[TOPSZ]; - char unique_id[30]; - char subname[20]; - - mqtt_data[0] = '\0'; - - - NoAlNumToUnderscore(subname, MultiSubName); - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_%s_%s"), ESP_getChipId(), sensorname, subname); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); - - if (Settings.flag.hass_discovery) - { - char name[33 + 42]; - char prefix[TOPSZ]; - char *state_topic = stemp1; - char *availability_topic = stemp2; - - GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR)); - snprintf_P(name, sizeof(name), PSTR("%s %s %s"), SettingsText(SET_FRIENDLYNAME1), sensorname, MultiSubName); - GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - - Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId()); - - - char jname[32]; - int sensor_index = GetCommandCode(jname, sizeof(jname), SubKey, kHAssJsonSensorTypes); - if (sensor_index > -1) { - - char param1[20]; - GetTextIndexed(param1, sizeof(param1), sensor_index, kHAssJsonSensorUnits); - switch (sensor_index) { - case 0: - case 1: - snprintf_P(param1, sizeof(param1), PSTR("°%c"),TempUnit()); - break; - case 2: - case 3: - snprintf_P(param1, sizeof(param1), PSTR("%s"), PressureUnit().c_str()); - break; -# 537 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_12_home_assistant.ino" - } - char param2[50]; - GetTextIndexed(param2, sizeof(param2), sensor_index, kHAssJsonSensorDevCla); - TryResponseAppend_P(HASS_DISCOVER_SENSOR, param1, param2, sensorname, subsensortype); - - if (subidx) { - TryResponseAppend_P(PSTR("[%d]"), subqty -1); - } - } else { - TryResponseAppend_P(HASS_DISCOVER_SENSOR, " ", "ic\":\"mdi:eye", sensorname, subsensortype); - } - if (nested) { - TryResponseAppend_P(PSTR("['%s']"), SubKey); - } - TryResponseAppend_P(PSTR("}}\"}")); - } - MqttPublish(stopic, true); -} - -void HAssAnnounceSensors(void) -{ - uint8_t hass_xsns_index = 0; - do - { - mqtt_data[0] = '\0'; - int tele_period_save = tele_period; - tele_period = 2; - XsnsNextCall(FUNC_JSON_APPEND, hass_xsns_index); - tele_period = tele_period_save; - - char sensordata[512]; - strlcpy(sensordata, mqtt_data, sizeof(sensordata)); - - if (strlen(sensordata)) - { - sensordata[0] = '{'; - snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata); - - - - - StaticJsonBuffer<500> jsonBuffer; - JsonObject &root = jsonBuffer.parseObject(sensordata); - if (!root.success()) - { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: jsonBuffer failed to parse '%s'"), sensordata); - continue; - } - for (auto sensor : root) - { - const char *sensorname = sensor.key; - JsonObject &sensors = sensor.value.as(); - if (!sensors.success()) - { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("HASS: JsonObject failed to parse '%s'"), sensordata); - continue; - } - - for (auto subsensor : sensors) - { - if (subsensor.value.is()) { - - char NestedName[20]; - char NewSensorName[20]; - snprintf_P(NestedName, sizeof(NestedName), PSTR("%s"), subsensor.key); - JsonObject& subsensors = subsensor.value.as(); - for (auto subsensor : subsensors) { - snprintf_P(NewSensorName, sizeof(NewSensorName), PSTR("%s %s"), NestedName, subsensor.key); - HAssAnnounceSensor(sensorname, NestedName, NewSensorName, 0, 0, 1, subsensor.key); - } - } else if (subsensor.value.is()) { - - JsonArray& subsensors = subsensor.value.as(); - uint8_t subqty = subsensors.size(); - char MultiSubName[20]; - for (int i = 1; i <= subqty; i++) { - snprintf_P(MultiSubName, sizeof(MultiSubName), PSTR("%s %d"), subsensor.key, i); - HAssAnnounceSensor(sensorname, subsensor.key, MultiSubName, i, 1, 0, subsensor.key); - } - } else { HAssAnnounceSensor(sensorname, subsensor.key, subsensor.key, 0, 0, 0, subsensor.key);} - } - } - } - yield(); - } while (hass_xsns_index != 0); -} - -void HAssAnnounceStatusSensor(void) -{ - char stopic[TOPSZ]; - char stemp1[TOPSZ]; - char stemp2[TOPSZ]; - char unique_id[30]; - - - mqtt_data[0] = '\0'; - - - snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_status"), ESP_getChipId()); - snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/sensor/%s/config"), unique_id); - - if (Settings.flag.hass_discovery) - { - char name[33 + 7]; - char prefix[TOPSZ]; - char *state_topic = stemp1; - char *availability_topic = stemp2; - - snprintf_P(name, sizeof(name), PSTR("%s status"), SettingsText(SET_FRIENDLYNAME1)); - GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE)); - GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - - Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic); - TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic); - TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP_getChipId(), SettingsText(SET_FRIENDLYNAME1), - ModuleName().c_str(), my_version, my_image); - TryResponseAppend_P(PSTR("}")); - } - MqttPublish(stopic, true); -} - -void HAssPublishStatus(void) -{ - Response_P(PSTR("{\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_BUILDDATETIME "\":\"%s\"," - "\"" D_JSON_COREVERSION "\":\"" ARDUINO_CORE_RELEASE "\",\"" D_JSON_SDKVERSION "\":\"%s\"," - "\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_RESTARTREASON "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\"," - "\"WiFi " D_JSON_LINK_COUNT "\":%d,\"WiFi " D_JSON_DOWNTIME "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d," - "\"" D_JSON_BOOTCOUNT "\":%d,\"" D_JSON_SAVECOUNT "\":%d,\"" D_CMND_IPADDRESS "\":\"%s\"," - "\"" D_JSON_RSSI "\":\"%d\",\"LoadAvg\":%lu}"), - my_version, my_image, GetBuildDateAndTime().c_str(), ESP.getSdkVersion(), ModuleName().c_str(), - GetResetReason().c_str(), GetUptime().c_str(), WifiLinkCount(), WifiDowntime().c_str(), MqttConnectCount(), - Settings.bootcount, Settings.save_flag, WiFi.localIP().toString().c_str(), - WifiGetRssiAsQuality(WiFi.RSSI()), loop_load_avg); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_HASS_STATE)); -} - -void HAssDiscovery(void) -{ - - if (Settings.flag.hass_discovery) - { - Settings.flag.mqtt_response = 0; - Settings.flag.decimal_text = 1; - Settings.flag3.hass_tele_on_power = 1; - - - Settings.light_scheme = 0; - } - - if (Settings.flag.hass_discovery || (1 == hass_mode)) - { - - HAssAnnounceRelayLight(); - - - HAssAnnounceButtons(); - - - HAssAnnounceSwitches(); - - - HAssAnnounceSensors(); - - - HAssAnnounceStatusSensor(); - } -} - -void HAssDiscover(void) -{ - hass_mode = 1; - hass_init_step = 1; -} - -void HAssAnyKey(void) -{ - if (!Settings.flag.hass_discovery) - { - return; - } - - uint32_t key = (XdrvMailbox.payload >> 16) & 0xFF; - uint32_t device = XdrvMailbox.payload & 0xFF; - uint32_t state = (XdrvMailbox.payload >> 8) & 0xFF; - - if (!key && KeyTopicActive(0)) { - device = (XdrvMailbox.payload >> 24) & 0xFF; - } - - char scommand[CMDSZ]; - char sw_topic[TOPSZ]; - char key_topic[TOPSZ]; - char *tmpbtn = SettingsText(SET_MQTT_BUTTON_TOPIC); - char *tmpsw = SettingsText(SET_MQTT_SWITCH_TOPIC); - uint8_t evkey = 0; - Format(sw_topic, tmpsw, sizeof(sw_topic)); - Format(key_topic, tmpbtn, sizeof(key_topic)); - - if (state == 2 || state == 3 ) { evkey = 1;} - snprintf_P(scommand, sizeof(scommand), PSTR("%s%d%s"), (key) ? "SWITCH" : "BUTTON", device, (evkey) ? "T" : ""); - - char stopic[TOPSZ]; - - GetTopic_P(stopic, STAT, mqtt_topic, scommand); - Response_P(S_JSON_COMMAND_SVALUE, (evkey) ? "TRIG" : PSTR(D_RSLT_STATE), GetStateText(state)); - MqttPublish(stopic); -} - - - - - -bool Xdrv12(uint8_t function) -{ - bool result = false; - - if (Settings.flag.mqtt_enabled) - { - switch (function) - { - case FUNC_EVERY_SECOND: - if (hass_init_step) - { - hass_init_step--; - if (!hass_init_step) - { - HAssDiscovery(); - } - } - else if (Settings.flag.hass_discovery && Settings.tele_period) - { - hass_tele_period++; - if (hass_tele_period >= Settings.tele_period) - { - hass_tele_period = 0; - - mqtt_data[0] = '\0'; - HAssPublishStatus(); - } - } - break; - case FUNC_ANY_KEY: - HAssAnyKey(); - break; - case FUNC_MQTT_INIT: - hass_mode = 0; - hass_init_step = 2; - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_13_display.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_13_display.ino" -#if defined(USE_I2C) || defined(USE_SPI) -#ifdef USE_DISPLAY - -#define XDRV_13 13 - -#include -#include - -Renderer *renderer; - -enum ColorType { COLOR_BW, COLOR_COLOR }; - -#ifndef MAXBUTTONS -#define MAXBUTTONS 16 -#endif - -#ifdef USE_TOUCH_BUTTONS -VButton *buttons[MAXBUTTONS]; -#endif - - - -uint16_t fg_color = 1; -uint16_t bg_color = 0; -uint8_t color_type = COLOR_BW; -uint8_t auto_draw=1; - -const uint8_t DISPLAY_MAX_DRIVERS = 16; -const uint8_t DISPLAY_MAX_COLS = 44; -const uint8_t DISPLAY_MAX_ROWS = 32; - -const uint8_t DISPLAY_LOG_ROWS = 32; - -#define D_PRFX_DISPLAY "Display" -#define D_CMND_DISP_ADDRESS "Address" -#define D_CMND_DISP_COLS "Cols" -#define D_CMND_DISP_DIMMER "Dimmer" -#define D_CMND_DISP_MODE "Mode" -#define D_CMND_DISP_MODEL "Model" -#define D_CMND_DISP_REFRESH "Refresh" -#define D_CMND_DISP_ROWS "Rows" -#define D_CMND_DISP_SIZE "Size" -#define D_CMND_DISP_FONT "Font" -#define D_CMND_DISP_ROTATE "Rotate" -#define D_CMND_DISP_TEXT "Text" -#define D_CMND_DISP_WIDTH "Width" -#define D_CMND_DISP_HEIGHT "Height" - -enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_EVERY_50_MSECOND, FUNC_DISPLAY_EVERY_SECOND, - FUNC_DISPLAY_MODEL, FUNC_DISPLAY_MODE, FUNC_DISPLAY_POWER, - FUNC_DISPLAY_CLEAR, FUNC_DISPLAY_DRAW_FRAME, - FUNC_DISPLAY_DRAW_HLINE, FUNC_DISPLAY_DRAW_VLINE, FUNC_DISPLAY_DRAW_LINE, - FUNC_DISPLAY_DRAW_CIRCLE, FUNC_DISPLAY_FILL_CIRCLE, - FUNC_DISPLAY_DRAW_RECTANGLE, FUNC_DISPLAY_FILL_RECTANGLE, - FUNC_DISPLAY_TEXT_SIZE, FUNC_DISPLAY_FONT_SIZE, FUNC_DISPLAY_ROTATION, FUNC_DISPLAY_DRAW_STRING, FUNC_DISPLAY_ONOFF }; - -enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL }; - -const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" - "|" D_CMND_DISP_MODEL "|" D_CMND_DISP_WIDTH "|" D_CMND_DISP_HEIGHT "|" D_CMND_DISP_MODE "|" D_CMND_DISP_REFRESH "|" - D_CMND_DISP_DIMMER "|" D_CMND_DISP_COLS "|" D_CMND_DISP_ROWS "|" D_CMND_DISP_SIZE "|" D_CMND_DISP_FONT "|" - D_CMND_DISP_ROTATE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS ; - -void (* const DisplayCommand[])(void) PROGMEM = { - &CmndDisplay, &CmndDisplayModel, &CmndDisplayWidth, &CmndDisplayHeight, &CmndDisplayMode, &CmndDisplayRefresh, - &CmndDisplayDimmer, &CmndDisplayColumns, &CmndDisplayRows, &CmndDisplaySize, &CmndDisplayFont, - &CmndDisplayRotate, &CmndDisplayText, &CmndDisplayAddress }; - -char *dsp_str; - -uint16_t dsp_x; -uint16_t dsp_y; -uint16_t dsp_x2; -uint16_t dsp_y2; -uint16_t dsp_rad; -uint16_t dsp_color; -int16_t dsp_len; -int16_t disp_xpos = 0; -int16_t disp_ypos = 0; - -uint8_t disp_power = 0; -uint8_t disp_device = 0; -uint8_t disp_refresh = 1; -uint8_t disp_autodraw = 1; -uint8_t dsp_init; -uint8_t dsp_font; -uint8_t dsp_flag; -uint8_t dsp_on; - -#ifdef USE_DISPLAY_MODES1TO5 - -char **disp_log_buffer; -char **disp_screen_buffer; -char disp_temp[2]; -char disp_pres[5]; - -uint8_t disp_log_buffer_cols = 0; -uint8_t disp_log_buffer_idx = 0; -uint8_t disp_log_buffer_ptr = 0; -uint8_t disp_screen_buffer_cols = 0; -uint8_t disp_screen_buffer_rows = 0; -bool disp_subscribed = false; - -#endif - - - -void DisplayInit(uint8_t mode) -{ - if (renderer) { - renderer->DisplayInit(mode, Settings.display_size, Settings.display_rotate, Settings.display_font); - } - else { - dsp_init = mode; - XdspCall(FUNC_DISPLAY_INIT); - } -} - -void DisplayClear(void) -{ - XdspCall(FUNC_DISPLAY_CLEAR); -} - -void DisplayDrawHLine(uint16_t x, uint16_t y, int16_t len, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_len = len; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_HLINE); -} - -void DisplayDrawVLine(uint16_t x, uint16_t y, int16_t len, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_len = len; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_VLINE); -} - -void DisplayDrawLine(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_x2 = x2; - dsp_y2 = y2; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_LINE); -} - -void DisplayDrawCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_rad = rad; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_CIRCLE); -} - -void DisplayDrawFilledCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_rad = rad; - dsp_color = color; - XdspCall(FUNC_DISPLAY_FILL_CIRCLE); -} - -void DisplayDrawRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_x2 = x2; - dsp_y2 = y2; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_RECTANGLE); -} - -void DisplayDrawFilledRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_x2 = x2; - dsp_y2 = y2; - dsp_color = color; - XdspCall(FUNC_DISPLAY_FILL_RECTANGLE); -} - -void DisplayDrawFrame(void) -{ - XdspCall(FUNC_DISPLAY_DRAW_FRAME); -} - -void DisplaySetSize(uint8_t size) -{ - Settings.display_size = size &3; - XdspCall(FUNC_DISPLAY_TEXT_SIZE); -} - -void DisplaySetFont(uint8_t font) -{ - Settings.display_font = font &3; - XdspCall(FUNC_DISPLAY_FONT_SIZE); -} - -void DisplaySetRotation(uint8_t rotation) -{ - Settings.display_rotate = rotation &3; - XdspCall(FUNC_DISPLAY_ROTATION); -} - -void DisplayDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag) -{ - dsp_x = x; - dsp_y = y; - dsp_str = str; - dsp_color = color; - dsp_flag = flag; - XdspCall(FUNC_DISPLAY_DRAW_STRING); -} - -void DisplayOnOff(uint8_t on) -{ - dsp_on = on; - XdspCall(FUNC_DISPLAY_ONOFF); -} - - - - -uint8_t fatoiv(char *cp,float *res) { - uint8_t index=0; - *res=CharToFloat(cp); - while (*cp) { - if ((*cp>='0' && *cp<='9') || (*cp=='-') || (*cp=='.')) { - cp++; - index++; - } else { - break; - } - } - return index; -} - - -uint8_t atoiv(char *cp, int16_t *res) -{ - uint8_t index = 0; - *res = atoi(cp); - while (*cp) { - if ((*cp>='0' && *cp<='9') || (*cp=='-')) { - cp++; - index++; - } else { - break; - } - } - return index; -} - - -uint8_t atoiV(char *cp, uint16_t *res) -{ - uint8_t index = 0; - *res = atoi(cp); - while (*cp) { - if (*cp>='0' && *cp<='9') { - cp++; - index++; - } else { - break; - } - } - return index; -} - - -void alignright(char *string) { - uint16_t slen=strlen(string); - uint16_t len=slen; - while (len) { - - if (string[len-1]!=' ') { - break; - } - len--; - } - uint16_t diff=slen-len; - if (diff>0) { - - memmove(&string[diff],string,len); - memset(string,' ',diff); - } -} - -char *get_string(char *buff,uint8_t len,char *cp) { -uint8_t index=0; - while (*cp!=':') { - buff[index]=*cp++; - index++; - if (index>=len) break; - } - buff[index]=0; - cp++; - return cp; -} - -#define ESCAPE_CHAR '~' - - -uint32_t decode_te(char *line) { - uint32_t skip = 0; - char sbuf[3],*cp; - while (*line) { - if (*line==ESCAPE_CHAR) { - cp=line+1; - if (*cp!=0 && *cp==ESCAPE_CHAR) { - - memmove(cp,cp+1,strlen(cp)); - skip++; - } else { - - if (strlen(cp)<2) { - - return skip; - } - - sbuf[0]=*(cp); - sbuf[1]=*(cp+1); - sbuf[2]=0; - *line=strtol(sbuf,0,16); - - memmove(cp,cp+2,strlen(cp)-1); - skip += 2; - } - } - line++; - } - return skip; -} - - - -#define DISPLAY_BUFFER_COLS 128 - -void DisplayText(void) -{ - uint8_t lpos; - uint8_t escape = 0; - uint8_t var; - int16_t lin = 0; - int16_t col = 0; - int16_t fill = 0; - int16_t temp; - int16_t temp1; - float ftemp; - - char linebuf[DISPLAY_BUFFER_COLS]; - char *dp = linebuf; - char *cp = XdrvMailbox.data; - - memset(linebuf, ' ', sizeof(linebuf)); - linebuf[sizeof(linebuf)-1] = 0; - *dp = 0; - - while (*cp) { - if (!escape) { - - if (*cp == '[') { - escape = 1; - cp++; - - if ((uint32_t)dp - (uint32_t)linebuf) { - if (!fill) { *dp = 0; } - if (col > 0 && lin > 0) { - - if (!renderer) DisplayDrawStringAt(col, lin, linebuf, fg_color, 1); - else renderer->DrawStringAt(col, lin, linebuf, fg_color, 1); - } else { - - if (!renderer) DisplayDrawStringAt(disp_xpos, disp_ypos, linebuf, fg_color, 0); - else renderer->DrawStringAt(disp_xpos, disp_ypos, linebuf, fg_color, 0); - } - memset(linebuf, ' ', sizeof(linebuf)); - linebuf[sizeof(linebuf)-1] = 0; - dp = linebuf; - } - } else { - - if (dp < (linebuf + DISPLAY_BUFFER_COLS)) { *dp++ = *cp++; } - } - } else { - - if (*cp == ']') { - escape = 0; - cp++; - } else { - - switch (*cp++) { - case 'z': - - if (!renderer) DisplayClear(); - else renderer->fillScreen(bg_color); - disp_xpos = 0; - disp_ypos = 0; - col = 0; - lin = 0; - break; - case 'i': - - DisplayInit(DISPLAY_INIT_PARTIAL); - break; - case 'I': - - DisplayInit(DISPLAY_INIT_FULL); - break; - case 'o': - if (!renderer) { - DisplayOnOff(0); - } else { - renderer->DisplayOnff(0); - } - break; - case 'O': - if (!renderer) { - DisplayOnOff(1); - } else { - renderer->DisplayOnff(1); - } - break; - case 'x': - - var = atoiv(cp, &disp_xpos); - cp += var; - break; - case 'y': - - var = atoiv(cp, &disp_ypos); - cp += var; - break; - case 'l': - - var = atoiv(cp, &lin); - cp += var; - - break; - case 'c': - - var = atoiv(cp, &col); - cp += var; - - break; - case 'C': - - if (*cp=='i') { - - cp++; - var = atoiv(cp, &temp); - if (renderer) ftemp=renderer->GetColorFromIndex(temp); - } else { - - var = fatoiv(cp,&ftemp); - } - fg_color=ftemp; - cp += var; - if (renderer) renderer->setTextColor(fg_color,bg_color); - break; - case 'B': - - if (*cp=='i') { - - cp++; - var = atoiv(cp, &temp); - if (renderer) ftemp=renderer->GetColorFromIndex(temp); - } else { - var = fatoiv(cp,&ftemp); - } - bg_color=ftemp; - cp += var; - if (renderer) renderer->setTextColor(fg_color,bg_color); - break; - case 'p': - - var = atoiv(cp, &fill); - cp += var; - linebuf[fill] = 0; - break; -#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) - case 'P': - { char *ep=strchr(cp,':'); - if (ep) { - *ep=0; - ep++; - Draw_RGB_Bitmap(cp,disp_xpos,disp_ypos); - cp=ep; - } - } - break; -#endif - case 'h': - - var = atoiv(cp, &temp); - cp += var; - if (temp < 0) { - if (renderer) renderer->writeFastHLine(disp_xpos + temp, disp_ypos, -temp, fg_color); - else DisplayDrawHLine(disp_xpos + temp, disp_ypos, -temp, fg_color); - } else { - if (renderer) renderer->writeFastHLine(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawHLine(disp_xpos, disp_ypos, temp, fg_color); - } - disp_xpos += temp; - break; - case 'v': - - var = atoiv(cp, &temp); - cp += var; - if (temp < 0) { - if (renderer) renderer->writeFastVLine(disp_xpos, disp_ypos + temp, -temp, fg_color); - else DisplayDrawVLine(disp_xpos, disp_ypos + temp, -temp, fg_color); - } else { - if (renderer) renderer->writeFastVLine(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawVLine(disp_xpos, disp_ypos, temp, fg_color); - } - disp_ypos += temp; - break; - case 'L': - - var = atoiv(cp, &temp); - cp += var; - cp++; - var = atoiv(cp, &temp1); - cp += var; - if (renderer) renderer->writeLine(disp_xpos, disp_ypos, temp, temp1, fg_color); - else DisplayDrawLine(disp_xpos, disp_ypos, temp, temp1, fg_color); - disp_xpos += temp; - disp_ypos += temp1; - break; - case 'k': - - var = atoiv(cp, &temp); - cp += var; - if (renderer) renderer->drawCircle(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawCircle(disp_xpos, disp_ypos, temp, fg_color); - break; - case 'K': - - var = atoiv(cp, &temp); - cp += var; - if (renderer) renderer->fillCircle(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawFilledCircle(disp_xpos, disp_ypos, temp, fg_color); - break; - case 'r': - - var = atoiv(cp, &temp); - cp += var; - cp++; - var = atoiv(cp, &temp1); - cp += var; - if (renderer) renderer->drawRect(disp_xpos, disp_ypos, temp, temp1, fg_color); - else DisplayDrawRectangle(disp_xpos, disp_ypos, temp, temp1, fg_color); - break; - case 'R': - - var = atoiv(cp, &temp); - cp += var; - cp++; - var = atoiv(cp, &temp1); - cp += var; - if (renderer) renderer->fillRect(disp_xpos, disp_ypos, temp, temp1, fg_color); - else DisplayDrawFilledRectangle(disp_xpos, disp_ypos, temp, temp1, fg_color); - break; - case 'u': - - { int16_t rad; - var = atoiv(cp, &temp); - cp += var; - cp++; - var = atoiv(cp, &temp1); - cp += var; - cp++; - var = atoiv(cp, &rad); - cp += var; - if (renderer) renderer->drawRoundRect(disp_xpos, disp_ypos, temp, temp1, rad, fg_color); - - } - break; - case 'U': - - { int16_t rad; - var = atoiv(cp, &temp); - cp += var; - cp++; - var = atoiv(cp, &temp1); - cp += var; - cp++; - var = atoiv(cp, &rad); - cp += var; - if (renderer) renderer->fillRoundRect(disp_xpos, disp_ypos, temp, temp1, rad, fg_color); - - } - break; - - case 't': - if (*cp=='S') { - cp++; - if (dp < (linebuf + DISPLAY_BUFFER_COLS) -8) { - snprintf_P(dp, 9, PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - dp += 8; - } - } else { - if (dp < (linebuf + DISPLAY_BUFFER_COLS) -5) { - snprintf_P(dp, 6, PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute); - dp += 5; - } - } - break; - case 'T': - if (dp < (linebuf + DISPLAY_BUFFER_COLS) -8) { - snprintf_P(dp, 9, PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year%2000); - dp += 8; - } - break; - case 'd': - - if (renderer) renderer->Updateframe(); - else DisplayDrawFrame(); - break; - case 'D': - - auto_draw=*cp&3; - if (renderer) renderer->setDrawMode(auto_draw>>1); - cp += 1; - break; - case 's': - - if (renderer) renderer->setTextSize(*cp&7); - else DisplaySetSize(*cp&3); - cp += 1; - break; - case 'f': - - if (renderer) renderer->setTextFont(*cp&7); - else DisplaySetFont(*cp&7); - cp += 1; - break; - case 'a': - - if (renderer) renderer->setRotation(*cp&3); - else DisplaySetRotation(*cp&3); - cp+=1; - break; - -#ifdef USE_GRAPH - case 'G': - - if (*cp=='d') { - cp++; - var=atoiv(cp,&temp); - cp+=var; - cp++; - var=atoiv(cp,&temp1); - cp+=var; - RedrawGraph(temp,temp1); - break; - } -#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) - if (*cp=='s') { - cp++; - var=atoiv(cp,&temp); - cp+=var; - cp++; - - char bbuff[128]; - cp=get_string(bbuff,sizeof(bbuff),cp); - Save_graph(temp,bbuff); - break; - } - if (*cp=='r') { - cp++; - var=atoiv(cp,&temp); - cp+=var; - cp++; - - char bbuff[128]; - cp=get_string(bbuff,sizeof(bbuff),cp); - Restore_graph(temp,bbuff); - break; - } -#endif - { int16_t num,gxp,gyp,gxs,gys,dec,icol; - float ymin,ymax; - var=atoiv(cp,&num); - cp+=var; - cp++; - var=atoiv(cp,&gxp); - cp+=var; - cp++; - var=atoiv(cp,&gyp); - cp+=var; - cp++; - var=atoiv(cp,&gxs); - cp+=var; - cp++; - var=atoiv(cp,&gys); - cp+=var; - cp++; - var=atoiv(cp,&dec); - cp+=var; - cp++; - var=fatoiv(cp,&ymin); - cp+=var; - cp++; - var=fatoiv(cp,&ymax); - cp+=var; - if (color_type==COLOR_COLOR) { - - cp++; - var=atoiv(cp,&icol); - cp+=var; - } else { - icol=0; - } - DefineGraph(num,gxp,gyp,gxs,gys,dec,ymin,ymax,icol); - } - break; - case 'g': - { float temp; - int16_t num; - var=atoiv(cp,&num); - cp+=var; - cp++; - var=fatoiv(cp,&temp); - cp+=var; - AddValue(num,temp); - } - break; -#endif - -#ifdef USE_AWATCH - case 'w': - var = atoiv(cp, &temp); - cp += var; - DrawAClock(temp); - break; -#endif - -#ifdef USE_TOUCH_BUTTONS - case 'b': - { int16_t num,gxp,gyp,gxs,gys,outline,fill,textcolor,textsize; - var=atoiv(cp,&num); - cp+=var; - cp++; - uint8_t bflags=num>>8; - num=num%MAXBUTTONS; - var=atoiv(cp,&gxp); - cp+=var; - cp++; - var=atoiv(cp,&gyp); - cp+=var; - cp++; - var=atoiv(cp,&gxs); - cp+=var; - cp++; - var=atoiv(cp,&gys); - cp+=var; - cp++; - var=atoiv(cp,&outline); - cp+=var; - cp++; - var=atoiv(cp,&fill); - cp+=var; - cp++; - var=atoiv(cp,&textcolor); - cp+=var; - cp++; - var=atoiv(cp,&textsize); - cp+=var; - cp++; - - char bbuff[32]; - cp=get_string(bbuff,sizeof(bbuff),cp); - - if (buttons[num]) { - delete buttons[num]; - } - if (renderer) { - buttons[num]= new VButton(); - if (buttons[num]) { - buttons[num]->vpower=bflags; - buttons[num]->initButtonUL(renderer,gxp,gyp,gxs,gys,renderer->GetColorFromIndex(outline),\ - renderer->GetColorFromIndex(fill),renderer->GetColorFromIndex(textcolor),bbuff,textsize); - if (!bflags) { - - buttons[num]->xdrawButton(bitRead(power,num)); - } else { - - buttons[num]->vpower&=0x7f; - buttons[num]->xdrawButton(buttons[num]->vpower&0x80); - } - } - } - } - break; -#endif - default: - - Response_P(PSTR("Unknown Escape")); - goto exit; - break; - } - } - } - } - exit: - - dp -= decode_te(linebuf); - if ((uint32_t)dp - (uint32_t)linebuf) { - if (!fill) { - *dp = 0; - } else { - linebuf[abs(int(fill))] = 0; - } - if (fill<0) { - - alignright(linebuf); - } - if (col > 0 && lin > 0) { - - if (!renderer) DisplayDrawStringAt(col, lin, linebuf, fg_color, 1); - else renderer->DrawStringAt(col, lin, linebuf, fg_color, 1); - } else { - - if (!renderer) DisplayDrawStringAt(disp_xpos, disp_ypos, linebuf, fg_color, 0); - else renderer->DrawStringAt(disp_xpos, disp_ypos, linebuf, fg_color, 0); - } - } - - if (auto_draw&1) { - if (renderer) renderer->Updateframe(); - else DisplayDrawFrame(); - } -} - - - -#ifdef USE_DISPLAY_MODES1TO5 - -void DisplayClearScreenBuffer(void) -{ - if (disp_screen_buffer_cols) { - for (uint32_t i = 0; i < disp_screen_buffer_rows; i++) { - memset(disp_screen_buffer[i], 0, disp_screen_buffer_cols); - } - } -} - -void DisplayFreeScreenBuffer(void) -{ - if (disp_screen_buffer != nullptr) { - for (uint32_t i = 0; i < disp_screen_buffer_rows; i++) { - if (disp_screen_buffer[i] != nullptr) { free(disp_screen_buffer[i]); } - } - free(disp_screen_buffer); - disp_screen_buffer_cols = 0; - disp_screen_buffer_rows = 0; - } -} - -void DisplayAllocScreenBuffer(void) -{ - if (!disp_screen_buffer_cols) { - disp_screen_buffer_rows = Settings.display_rows; - disp_screen_buffer = (char**)malloc(sizeof(*disp_screen_buffer) * disp_screen_buffer_rows); - if (disp_screen_buffer != nullptr) { - for (uint32_t i = 0; i < disp_screen_buffer_rows; i++) { - disp_screen_buffer[i] = (char*)malloc(sizeof(*disp_screen_buffer[i]) * (Settings.display_cols[0] +1)); - if (disp_screen_buffer[i] == nullptr) { - DisplayFreeScreenBuffer(); - break; - } - } - } - if (disp_screen_buffer != nullptr) { - disp_screen_buffer_cols = Settings.display_cols[0] +1; - DisplayClearScreenBuffer(); - } - } -} - -void DisplayReAllocScreenBuffer(void) -{ - DisplayFreeScreenBuffer(); - DisplayAllocScreenBuffer(); -} - -void DisplayFillScreen(uint32_t line) -{ - uint32_t len = disp_screen_buffer_cols - strlen(disp_screen_buffer[line]); - if (len) { - memset(disp_screen_buffer[line] + strlen(disp_screen_buffer[line]), 0x20, len); - disp_screen_buffer[line][disp_screen_buffer_cols -1] = 0; - } -} - - - -void DisplayClearLogBuffer(void) -{ - if (disp_log_buffer_cols) { - for (uint32_t i = 0; i < DISPLAY_LOG_ROWS; i++) { - memset(disp_log_buffer[i], 0, disp_log_buffer_cols); - } - } -} - -void DisplayFreeLogBuffer(void) -{ - if (disp_log_buffer != nullptr) { - for (uint32_t i = 0; i < DISPLAY_LOG_ROWS; i++) { - if (disp_log_buffer[i] != nullptr) { free(disp_log_buffer[i]); } - } - free(disp_log_buffer); - disp_log_buffer_cols = 0; - } -} - -void DisplayAllocLogBuffer(void) -{ - if (!disp_log_buffer_cols) { - disp_log_buffer = (char**)malloc(sizeof(*disp_log_buffer) * DISPLAY_LOG_ROWS); - if (disp_log_buffer != nullptr) { - for (uint32_t i = 0; i < DISPLAY_LOG_ROWS; i++) { - disp_log_buffer[i] = (char*)malloc(sizeof(*disp_log_buffer[i]) * (Settings.display_cols[0] +1)); - if (disp_log_buffer[i] == nullptr) { - DisplayFreeLogBuffer(); - break; - } - } - } - if (disp_log_buffer != nullptr) { - disp_log_buffer_cols = Settings.display_cols[0] +1; - DisplayClearLogBuffer(); - } - } -} - -void DisplayReAllocLogBuffer(void) -{ - DisplayFreeLogBuffer(); - DisplayAllocLogBuffer(); -} - -void DisplayLogBufferAdd(char* txt) -{ - if (disp_log_buffer_cols) { - strlcpy(disp_log_buffer[disp_log_buffer_idx], txt, disp_log_buffer_cols); - disp_log_buffer_idx++; - if (DISPLAY_LOG_ROWS == disp_log_buffer_idx) { disp_log_buffer_idx = 0; } - } -} - -char* DisplayLogBuffer(char temp_code) -{ - char* result = nullptr; - if (disp_log_buffer_cols) { - if (disp_log_buffer_idx != disp_log_buffer_ptr) { - result = disp_log_buffer[disp_log_buffer_ptr]; - disp_log_buffer_ptr++; - if (DISPLAY_LOG_ROWS == disp_log_buffer_ptr) { disp_log_buffer_ptr = 0; } - - char *pch = strchr(result, '~'); - if (pch != nullptr) { result[pch - result] = temp_code; } - } - } - return result; -} - -void DisplayLogBufferInit(void) -{ - if (Settings.display_mode) { - disp_log_buffer_idx = 0; - disp_log_buffer_ptr = 0; - disp_refresh = Settings.display_refresh; - - snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%c"), TempUnit()); - snprintf_P(disp_pres, sizeof(disp_pres), PressureUnit().c_str()); - - DisplayReAllocLogBuffer(); - - char buffer[40]; - snprintf_P(buffer, sizeof(buffer), PSTR(D_VERSION " %s%s"), my_version, my_image); - DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("Display mode %d"), Settings.display_mode); - DisplayLogBufferAdd(buffer); - - snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), my_hostname); - DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active)); - DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), WiFi.macAddress().c_str()); - DisplayLogBufferAdd(buffer); - if (!global_state.wifi_down) { - snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), WiFi.localIP().toString().c_str()); - DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_RSSI " %d%%"), WifiGetRssiAsQuality(WiFi.RSSI())); - DisplayLogBufferAdd(buffer); - } - } -} - - - - - -enum SensorQuantity { - JSON_TEMPERATURE, - JSON_HUMIDITY, JSON_LIGHT, JSON_NOISE, JSON_AIRQUALITY, - JSON_PRESSURE, JSON_PRESSUREATSEALEVEL, - JSON_ILLUMINANCE, - JSON_GAS, - JSON_YESTERDAY, JSON_TOTAL, JSON_TODAY, - JSON_PERIOD, - JSON_POWERFACTOR, JSON_COUNTER, JSON_ANALOG_INPUT, JSON_UV_LEVEL, - JSON_CURRENT, - JSON_VOLTAGE, - JSON_POWERUSAGE, - JSON_CO2, - JSON_FREQUENCY }; -const char kSensorQuantity[] PROGMEM = - D_JSON_TEMPERATURE "|" - D_JSON_HUMIDITY "|" D_JSON_LIGHT "|" D_JSON_NOISE "|" D_JSON_AIRQUALITY "|" - D_JSON_PRESSURE "|" D_JSON_PRESSUREATSEALEVEL "|" - D_JSON_ILLUMINANCE "|" - D_JSON_GAS "|" - D_JSON_YESTERDAY "|" D_JSON_TOTAL "|" D_JSON_TODAY "|" - D_JSON_PERIOD "|" - D_JSON_POWERFACTOR "|" D_JSON_COUNTER "|" D_JSON_ANALOG_INPUT "|" D_JSON_UV_LEVEL "|" - D_JSON_CURRENT "|" - D_JSON_VOLTAGE "|" - D_JSON_POWERUSAGE "|" - D_JSON_CO2 "|" - D_JSON_FREQUENCY ; - -void DisplayJsonValue(const char* topic, const char* device, const char* mkey, const char* value) -{ - char quantity[TOPSZ]; - char buffer[Settings.display_cols[0] +1]; - char spaces[Settings.display_cols[0]]; - char source[Settings.display_cols[0] - Settings.display_cols[1]]; - char svalue[Settings.display_cols[1] +1]; - -#ifdef USE_DEBUG_DRIVER - ShowFreeMem(PSTR("DisplayJsonValue")); -#endif - - memset(spaces, 0x20, sizeof(spaces)); - spaces[sizeof(spaces) -1] = '\0'; - snprintf_P(source, sizeof(source), PSTR("%s%s%s%s"), topic, (strlen(topic))?"/":"", mkey, spaces); - - int quantity_code = GetCommandCode(quantity, sizeof(quantity), mkey, kSensorQuantity); - if ((-1 == quantity_code) || !strcmp_P(mkey, S_RSLT_POWER)) { - return; - } - if (JSON_TEMPERATURE == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s~%s"), value, disp_temp); - } - else if ((quantity_code >= JSON_HUMIDITY) && (quantity_code <= JSON_AIRQUALITY)) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s%%"), value); - } - else if ((quantity_code >= JSON_PRESSURE) && (quantity_code <= JSON_PRESSUREATSEALEVEL)) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s"), value, disp_pres); - } - else if (JSON_ILLUMINANCE == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_LUX), value); - } - else if (JSON_GAS == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_KILOOHM), value); - } - else if ((quantity_code >= JSON_YESTERDAY) && (quantity_code <= JSON_TODAY)) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_KILOWATTHOUR), value); - } - else if (JSON_PERIOD == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_WATTHOUR), value); - } - else if ((quantity_code >= JSON_POWERFACTOR) && (quantity_code <= JSON_UV_LEVEL)) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s"), value); - } - else if (JSON_CURRENT == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_AMPERE), value); - } - else if (JSON_VOLTAGE == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_VOLT), value); - } - else if (JSON_POWERUSAGE == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_WATT), value); - } - else if (JSON_CO2 == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_PARTS_PER_MILLION), value); - } - else if (JSON_FREQUENCY == quantity_code) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_HERTZ), value); - } - snprintf_P(buffer, sizeof(buffer), PSTR("%s %s"), source, svalue); - - - - DisplayLogBufferAdd(buffer); -} - -void DisplayAnalyzeJson(char *topic, char *json) -{ -# 1145 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_13_display.ino" - String jsonStr = json; - - StaticJsonBuffer<1024> jsonBuf; - JsonObject &root = jsonBuf.parseObject(jsonStr); - if (root.success()) { - - const char *unit; - unit = root[D_JSON_TEMPERATURE_UNIT]; - if (unit) { - snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%s"), unit); - } - unit = root[D_JSON_PRESSURE_UNIT]; - if (unit) { - snprintf_P(disp_pres, sizeof(disp_pres), PSTR("%s"), unit); - } - - for (JsonObject::iterator it = root.begin(); it != root.end(); ++it) { - JsonVariant value = it->value; - if (value.is()) { - JsonObject& Object2 = value; - for (JsonObject::iterator it2 = Object2.begin(); it2 != Object2.end(); ++it2) { - JsonVariant value2 = it2->value; - if (value2.is()) { - JsonObject& Object3 = value2; - for (JsonObject::iterator it3 = Object3.begin(); it3 != Object3.end(); ++it3) { - const char* value = it3->value; - if (value != nullptr) { - DisplayJsonValue(topic, it->key, it3->key, value); - } - } - } else { - const char* value = it2->value; - if (value != nullptr) { - DisplayJsonValue(topic, it->key, it2->key, value); - } - } - } - } else { - const char* value = it->value; - if (value != nullptr) { - DisplayJsonValue(topic, it->key, it->key, value); - } - } - } - } -} - -void DisplayMqttSubscribe(void) -{ - - - - - - - if (Settings.display_model && (Settings.display_mode &0x04)) { - - char stopic[TOPSZ]; - char ntopic[TOPSZ]; - - ntopic[0] = '\0'; - strlcpy(stopic, SettingsText(SET_MQTT_FULLTOPIC), sizeof(stopic)); - char *tp = strtok(stopic, "/"); - while (tp != nullptr) { - if (!strcmp_P(tp, MQTT_TOKEN_PREFIX)) { - break; - } - strncat_P(ntopic, PSTR("+/"), sizeof(ntopic) - strlen(ntopic) -1); - tp = strtok(nullptr, "/"); - } - strncat(ntopic, SettingsText(SET_MQTTPREFIX3), sizeof(ntopic) - strlen(ntopic) -1); - strncat_P(ntopic, PSTR("/#"), sizeof(ntopic) - strlen(ntopic) -1); - MqttSubscribe(ntopic); - disp_subscribed = true; - } else { - disp_subscribed = false; - } -} - -bool DisplayMqttData(void) -{ - if (disp_subscribed) { - char stopic[TOPSZ]; - - snprintf_P(stopic, sizeof(stopic) , PSTR("%s/"), SettingsText(SET_MQTTPREFIX3)); - char *tp = strstr(XdrvMailbox.topic, stopic); - if (tp) { - if (Settings.display_mode &0x04) { - tp = tp + strlen(stopic); - char *topic = strtok(tp, "/"); - DisplayAnalyzeJson(topic, XdrvMailbox.data); - } - return true; - } - } - return false; -} - -void DisplayLocalSensor(void) -{ - if ((Settings.display_mode &0x02) && (0 == tele_period)) { - char no_topic[1] = { 0 }; - - DisplayAnalyzeJson(no_topic, mqtt_data); - } -} - -#endif - - - - - -void DisplayInitDriver(void) -{ - XdspCall(FUNC_DISPLAY_INIT_DRIVER); - - if (renderer) { - renderer->setTextFont(Settings.display_font); - renderer->setTextSize(Settings.display_size); - } - - - - - if (Settings.display_model) { - devices_present++; - disp_device = devices_present; - -#ifndef USE_DISPLAY_MODES1TO5 - Settings.display_mode = 0; -#else - DisplayLogBufferInit(); -#endif - } -} - -void DisplaySetPower(void) -{ - disp_power = bitRead(XdrvMailbox.index, disp_device -1); - - - - if (Settings.display_model) { - if (!renderer) { - XdspCall(FUNC_DISPLAY_POWER); - } else { - renderer->DisplayOnff(disp_power); - } - } -} - - - - - -void CmndDisplay(void) -{ - Response_P(PSTR("{\"" D_PRFX_DISPLAY "\":{\"" D_CMND_DISP_MODEL "\":%d,\"" D_CMND_DISP_WIDTH "\":%d,\"" D_CMND_DISP_HEIGHT "\":%d,\"" - D_CMND_DISP_MODE "\":%d,\"" D_CMND_DISP_DIMMER "\":%d,\"" D_CMND_DISP_SIZE "\":%d,\"" D_CMND_DISP_FONT "\":%d,\"" - D_CMND_DISP_ROTATE "\":%d,\"" D_CMND_DISP_REFRESH "\":%d,\"" D_CMND_DISP_COLS "\":[%d,%d],\"" D_CMND_DISP_ROWS "\":%d}}"), - Settings.display_model, Settings.display_width, Settings.display_height, - Settings.display_mode, Settings.display_dimmer, Settings.display_size, Settings.display_font, - Settings.display_rotate, Settings.display_refresh, Settings.display_cols[0], Settings.display_cols[1], Settings.display_rows); -} - -void CmndDisplayModel(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < DISPLAY_MAX_DRIVERS)) { - uint32_t last_display_model = Settings.display_model; - Settings.display_model = XdrvMailbox.payload; - if (XdspCall(FUNC_DISPLAY_MODEL)) { - restart_flag = 2; - } else { - Settings.display_model = last_display_model; - } - } - ResponseCmndNumber(Settings.display_model); -} - -void CmndDisplayWidth(void) -{ - if (XdrvMailbox.payload > 0) { - if (XdrvMailbox.payload != Settings.display_width) { - Settings.display_width = XdrvMailbox.payload; - restart_flag = 2; - } - } - ResponseCmndNumber(Settings.display_width); -} - -void CmndDisplayHeight(void) -{ - if (XdrvMailbox.payload > 0) { - if (XdrvMailbox.payload != Settings.display_height) { - Settings.display_height = XdrvMailbox.payload; - restart_flag = 2; - } - } - ResponseCmndNumber(Settings.display_height); -} - -void CmndDisplayMode(void) -{ -#ifdef USE_DISPLAY_MODES1TO5 - - - - - - - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) { - uint32_t last_display_mode = Settings.display_mode; - Settings.display_mode = XdrvMailbox.payload; - - if (disp_subscribed != (Settings.display_mode &0x04)) { - restart_flag = 2; - } else { - if (last_display_mode && !Settings.display_mode) { - DisplayInit(DISPLAY_INIT_MODE); - if (renderer) renderer->fillScreen(bg_color); - else DisplayClear(); - } else { - DisplayLogBufferInit(); - DisplayInit(DISPLAY_INIT_MODE); - } - } - } -#endif - ResponseCmndNumber(Settings.display_mode); -} - -void CmndDisplayDimmer(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - Settings.display_dimmer = ((XdrvMailbox.payload +1) * 100) / 666; - if (Settings.display_dimmer && !(disp_power)) { - ExecuteCommandPower(disp_device, POWER_ON, SRC_DISPLAY); - } - else if (!Settings.display_dimmer && disp_power) { - ExecuteCommandPower(disp_device, POWER_OFF, SRC_DISPLAY); - } - if (renderer) renderer->dim(Settings.display_dimmer); - } - ResponseCmndNumber(Settings.display_dimmer); -} - -void CmndDisplaySize(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) { - Settings.display_size = XdrvMailbox.payload; - if (renderer) renderer->setTextSize(Settings.display_size); - else DisplaySetSize(Settings.display_size); - } - ResponseCmndNumber(Settings.display_size); -} - -void CmndDisplayFont(void) -{ - if ((XdrvMailbox.payload >=0) && (XdrvMailbox.payload <= 4)) { - Settings.display_font = XdrvMailbox.payload; - if (renderer) renderer->setTextFont(Settings.display_font); - else DisplaySetFont(Settings.display_font); - } - ResponseCmndNumber(Settings.display_font); -} - -void CmndDisplayRotate(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 4)) { - if (Settings.display_rotate != XdrvMailbox.payload) { -# 1428 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_13_display.ino" - Settings.display_rotate = XdrvMailbox.payload; - DisplayInit(DISPLAY_INIT_MODE); -#ifdef USE_DISPLAY_MODES1TO5 - DisplayLogBufferInit(); -#endif - } - } - ResponseCmndNumber(Settings.display_rotate); -} - -void CmndDisplayText(void) -{ - if (disp_device && XdrvMailbox.data_len > 0) { -#ifndef USE_DISPLAY_MODES1TO5 - DisplayText(); -#else - if (!Settings.display_mode) { - DisplayText(); - } else { - DisplayLogBufferAdd(XdrvMailbox.data); - } -#endif - ResponseCmndChar(XdrvMailbox.data); - } -} - -void CmndDisplayAddress(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) { - Settings.display_address[XdrvMailbox.index -1] = XdrvMailbox.payload; - } - ResponseCmndIdxNumber(Settings.display_address[XdrvMailbox.index -1]); - } -} - -void CmndDisplayRefresh(void) -{ - if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) { - Settings.display_refresh = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.display_refresh); -} - -void CmndDisplayColumns(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_COLS)) { - Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload; -#ifdef USE_DISPLAY_MODES1TO5 - if (1 == XdrvMailbox.index) { - DisplayLogBufferInit(); - DisplayReAllocScreenBuffer(); - } -#endif - } - ResponseCmndIdxNumber(Settings.display_cols[XdrvMailbox.index -1]); - } -} - -void CmndDisplayRows(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_ROWS)) { - Settings.display_rows = XdrvMailbox.payload; -#ifdef USE_DISPLAY_MODES1TO5 - DisplayLogBufferInit(); - DisplayReAllocScreenBuffer(); -#endif - } - ResponseCmndNumber(Settings.display_rows); -} - - - - - -#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) -void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp) { - if (!renderer) return; - - - File fp; - fp=SD.open(file,FILE_READ); - if (!fp) return; - uint16_t xsize; - fp.read((uint8_t*)&xsize,2); - uint16_t ysize; - fp.read((uint8_t*)&ysize,2); - -#if 1 -#define XBUFF 128 - uint16_t xdiv=xsize/XBUFF; - renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize); - for(int16_t j=0; j=2) renderer->pushColors(rgb,len/2,true); - } - OsWatchLoop(); - } - renderer->setAddrWindow(0,0,0,0); -#else - for(int16_t j=0; jwritePixel(xp+i,yp,rgb); - } - delay(0); - OsWatchLoop(); - yp++; - } -#endif - fp.close(); -} -#endif - -#ifdef USE_AWATCH -#define MINUTE_REDUCT 4 - -#ifndef pi -#define pi 3.14159265359 -#endif - - -void DrawAClock(uint16_t rad) { - if (!renderer) return; - float frad=rad; - uint16_t hred=frad/3.0; - renderer->fillCircle(disp_xpos, disp_ypos, rad, bg_color); - renderer->drawCircle(disp_xpos, disp_ypos, rad, fg_color); - renderer->fillCircle(disp_xpos, disp_ypos, 4, fg_color); - for (uint8_t count=0; count<60; count+=5) { - float p1=((float)count*(pi/30)-(pi/2)); - uint8_t len; - if ((count%15)==0) { - len=4; - } else { - len=2; - } - renderer->writeLine(disp_xpos+((float)(rad-len)*cosf(p1)), disp_ypos+((float)(rad-len)*sinf(p1)), disp_xpos+(frad*cosf(p1)), disp_ypos+(frad*sinf(p1)), fg_color); - } - - - float hour=((float)RtcTime.hour*60.0+(float)RtcTime.minute)/60.0; - float temp=(hour*(pi/6.0)-(pi/2.0)); - renderer->writeLine(disp_xpos, disp_ypos,disp_xpos+(frad-hred)*cosf(temp),disp_ypos+(frad-hred)*sinf(temp), fg_color); - - - temp=((float)RtcTime.minute*(pi/30.0)-(pi/2.0)); - renderer->writeLine(disp_xpos, disp_ypos,disp_xpos+(frad-MINUTE_REDUCT)*cosf(temp),disp_ypos+(frad-MINUTE_REDUCT)*sinf(temp), fg_color); -} -#endif - - -#ifdef USE_GRAPH - -typedef union { - uint8_t data; - struct { - uint8_t overlay : 1; - uint8_t draw : 1; - uint8_t nu3 : 1; - uint8_t nu4 : 1; - uint8_t nu5 : 1; - uint8_t nu6 : 1; - uint8_t nu7 : 1; - uint8_t nu8 : 1; - }; -} GFLAGS; - -struct GRAPH { - uint16_t xp; - uint16_t yp; - uint16_t xs; - uint16_t ys; - float ymin; - float ymax; - float range; - uint32_t x_time; - uint32_t last_ms; - uint32_t last_ms_redrawn; - int16_t decimation; - uint16_t dcnt; - uint32_t summ; - uint16_t xcnt; - uint8_t *values; - uint8_t xticks; - uint8_t yticks; - uint8_t last_val; - uint8_t color_index; - GFLAGS flags; -}; - - -struct GRAPH *graph[NUM_GRAPHS]; - -#define TICKLEN 4 -void ClrGraph(uint16_t num) { - struct GRAPH *gp=graph[num]; - - uint16_t xticks=gp->xticks; - uint16_t yticks=gp->yticks; - uint16_t count; - - - if (gp->flags.overlay) return; - - renderer->fillRect(gp->xp+1,gp->yp+1,gp->xs-2,gp->ys-2,bg_color); - - if (xticks) { - float cxp=gp->xp,xd=(float)gp->xs/(float)xticks; - for (count=0; countwriteFastVLine(cxp,gp->yp+gp->ys-TICKLEN,TICKLEN,fg_color); - cxp+=xd; - } - } - if (yticks) { - if (gp->ymin<0 && gp->ymax>0) { - - float cxp=0; - float czp=gp->yp+(gp->ymax/gp->range); - while (cxpxs) { - renderer->writeFastHLine(gp->xp+cxp,czp,2,fg_color); - cxp+=6.0; - } - - float cyp=0,yd=gp->ys/yticks; - for (count=0; countgp->yp) { - renderer->writeFastHLine(gp->xp,czp-cyp,TICKLEN,fg_color); - renderer->writeFastHLine(gp->xp+gp->xs-TICKLEN,czp-cyp,TICKLEN,fg_color); - } - if ((czp+cyp)<(gp->yp+gp->ys)) { - renderer->writeFastHLine(gp->xp,czp+cyp,TICKLEN,fg_color); - renderer->writeFastHLine(gp->xp+gp->xs-TICKLEN,czp+cyp,TICKLEN,fg_color); - } - cyp+=yd; - } - } else { - float cyp=gp->yp,yd=gp->ys/yticks; - for (count=0; countwriteFastHLine(gp->xp,cyp,TICKLEN,fg_color); - renderer->writeFastHLine(gp->xp+gp->xs-TICKLEN,cyp,TICKLEN,fg_color); - cyp+=yd; - } - } - } -} - - -void DefineGraph(uint16_t num,uint16_t xp,uint16_t yp,int16_t xs,uint16_t ys,int16_t dec,float ymin, float ymax,uint8_t icol) { - if (!renderer) return; - uint8_t rflg=0; - if (xs<0) { - rflg=1; - xs=abs(xs); - } - struct GRAPH *gp; - uint16_t count; - uint16_t index=num%NUM_GRAPHS; - if (!graph[index]) { - gp=(struct GRAPH*)calloc(sizeof(struct GRAPH),1); - if (!gp) return; - graph[index]=gp; - } else { - gp=graph[index]; - if (rflg) { - RedrawGraph(index,1); - return; - } - } - - - gp->xticks=(num>>4)&0x3f; - gp->yticks=(num>>10)&0x3f; - gp->xp=xp; - gp->yp=yp; - gp->xs=xs; - gp->ys=ys; - if (!dec) dec=1; - gp->decimation=dec; - if (dec>0) { - - gp->x_time=((float)dec*60000.0)/(float)xs; - gp->last_ms=millis()+gp->x_time; - } - gp->ymin=ymin; - gp->ymax=ymax; - gp->range=(ymax-ymin)/ys; - gp->xcnt=0; - gp->dcnt=0; - gp->summ=0; - if (gp->values) free(gp->values); - gp->values=(uint8_t*) calloc(1,xs+2); - if (!gp->values) { - free(gp); - graph[index]=0; - return; - } - - gp->values[0]=0; - - gp->last_ms_redrawn=millis(); - - if (!icol) icol=1; - gp->color_index=icol; - gp->flags.overlay=0; - gp->flags.draw=1; - - - if (index>0) { - for (uint8_t count=0; countxp==gp1->xp) && (gp->yp==gp1->yp)) { - gp->flags.overlay=1; - break; - } - } - } - } - - - renderer->drawRect(xp,yp,xs,ys,fg_color); - - ClrGraph(index); - -} - - -void DisplayCheckGraph() { - int16_t count; - struct GRAPH *gp; - for (count=0;countdecimation>0) { - - while (millis()>gp->last_ms) { - gp->last_ms+=gp->x_time; - uint8_t val; - if (gp->dcnt) { - val=gp->summ/gp->dcnt; - gp->dcnt=0; - gp->summ=0; - gp->last_val=val; - } else { - val=gp->last_val; - } - AddGraph(count,val); - } - } - } - } -} - - -#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) -#include - -void Save_graph(uint8_t num, char *path) { - if (!renderer) return; - uint16_t index=num%NUM_GRAPHS; - struct GRAPH *gp=graph[index]; - if (!gp) return; - File fp; - SD.remove(path); - fp=SD.open(path,FILE_WRITE); - if (!fp) return; - char str[32]; - sprintf_P(str,PSTR("%d\t%d\t%d\t"),gp->xcnt,gp->xs,gp->ys); - fp.print(str); - dtostrfd(gp->ymin,2,str); - fp.print(str); - fp.print("\t"); - dtostrfd(gp->ymax,2,str); - fp.print(str); - fp.print("\t"); - for (uint32_t count=0;countxs;count++) { - dtostrfd(gp->values[count],0,str); - fp.print(str); - fp.print("\t"); - } - fp.print("\n"); - fp.close(); -} -void Restore_graph(uint8_t num, char *path) { - if (!renderer) return; - uint16_t index=num%NUM_GRAPHS; - struct GRAPH *gp=graph[index]; - if (!gp) return; - File fp; - fp=SD.open(path,FILE_READ); - if (!fp) return; - char vbuff[32]; - char *cp=vbuff; - uint8_t buf[2]; - uint8_t findex=0; - - for (uint32_t count=0;count<=gp->xs+4;count++) { - cp=vbuff; - findex=0; - while (fp.available()) { - fp.read(buf,1); - if (buf[0]=='\t' || buf[0]==',' || buf[0]=='\n' || buf[0]=='\r') { - break; - } else { - *cp++=buf[0]; - findex++; - if (findex>=sizeof(vbuff)-1) break; - } - } - *cp=0; - if (count<=4) { - if (count==0) gp->xcnt=atoi(vbuff); - } else { - gp->values[count-5]=atoi(vbuff); - } - } - fp.close(); - RedrawGraph(num,1); -} -#endif - -void RedrawGraph(uint8_t num, uint8_t flags) { - uint16_t index=num%NUM_GRAPHS; - struct GRAPH *gp=graph[index]; - if (!gp) return; - if (!flags) { - gp->flags.draw=0; - return; - } - if (!renderer) return; - - gp->flags.draw=1; - uint16_t linecol=fg_color; - - if (color_type==COLOR_COLOR) { - linecol=renderer->GetColorFromIndex(gp->color_index); - } - - if (!gp->flags.overlay) { - - renderer->drawRect(gp->xp,gp->yp,gp->xs,gp->ys,fg_color); - - ClrGraph(index); - } - - for (uint16_t count=0;countxs-1;count++) { - renderer->writeLine(gp->xp+count,gp->yp+gp->ys-gp->values[count]-1,gp->xp+count+1,gp->yp+gp->ys-gp->values[count+1]-1,linecol); - } -} - - -void AddGraph(uint8_t num,uint8_t val) { - struct GRAPH *gp=graph[num]; - if (!renderer) return; - - uint16_t linecol=fg_color; - if (color_type==COLOR_COLOR) { - linecol=renderer->GetColorFromIndex(gp->color_index); - } - gp->xcnt++; - if (gp->xcnt>gp->xs) { - gp->xcnt=gp->xs; - int16_t count; - - for (count=0;countxs-1;count++) { - gp->values[count]=gp->values[count+1]; - } - gp->values[gp->xcnt-1]=val; - - if (!gp->flags.draw) return; - - - if (millis()-gp->last_ms_redrawn>1000) { - gp->last_ms_redrawn=millis(); - - if (!gp->flags.overlay) { - - renderer->drawRect(gp->xp,gp->yp,gp->xs,gp->ys,fg_color); - - ClrGraph(num); - } - - for (count=0;countxs-1;count++) { - renderer->writeLine(gp->xp+count,gp->yp+gp->ys-gp->values[count]-1,gp->xp+count+1,gp->yp+gp->ys-gp->values[count+1]-1,linecol); - } - } - } else { - - gp->values[gp->xcnt]=val; - if (!gp->flags.draw) return; - renderer->writeLine(gp->xp+gp->xcnt-1,gp->yp+gp->ys-gp->values[gp->xcnt-1]-1,gp->xp+gp->xcnt,gp->yp+gp->ys-gp->values[gp->xcnt]-1,linecol); - } -} - - - -void AddValue(uint8_t num,float fval) { - - num=num%NUM_GRAPHS; - struct GRAPH *gp=graph[num]; - if (!gp) return; - - if (fval>gp->ymax) fval=gp->ymax; - if (fvalymin) fval=gp->ymin; - - int16_t val; - val=(fval-gp->ymin)/gp->range; - - if (val>gp->ys-1) val=gp->ys-1; - if (val<0) val=0; - - - gp->summ+=val; - gp->dcnt++; - - - if (gp->decimation<0) { - if (gp->dcnt>=-gp->decimation) { - gp->dcnt=0; - - val=gp->summ/-gp->decimation; - gp->summ=0; - - AddGraph(num,val); - } - } -} -#endif - - - - - -bool Xdrv13(uint8_t function) -{ - bool result = false; - - if ((i2c_flg || spi_flg || soft_spi_flg) && XdspPresent()) { - switch (function) { - case FUNC_PRE_INIT: - DisplayInitDriver(); -#ifdef USE_GRAPH - for (uint8_t count=0;count - -TasmotaSerial *MP3Player; - - - - - -#define D_CMND_MP3 "MP3" - -const char S_JSON_MP3_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_MP3 "%s\":%d}"; -const char S_JSON_MP3_COMMAND[] PROGMEM = "{\"" D_CMND_MP3 "%s\"}"; -const char kMP3_Commands[] PROGMEM = "Track|Play|Pause|Stop|Volume|EQ|Device|Reset|DAC"; - - - - - -enum MP3_Commands { - CMND_MP3_TRACK, - CMND_MP3_PLAY, - CMND_MP3_PAUSE, - CMND_MP3_STOP, - CMND_MP3_VOLUME, - CMND_MP3_EQ, - CMND_MP3_DEVICE, - CMND_MP3_RESET, - CMND_MP3_DAC }; - - - - - - -#define MP3_CMD_RESET_VALUE 0 - -#define MP3_CMD_TRACK 0x03 -#define MP3_CMD_PLAY 0x0d -#define MP3_CMD_PAUSE 0x0e -#define MP3_CMD_STOP 0x16 -#define MP3_CMD_VOLUME 0x06 -#define MP3_CMD_EQ 0x07 -#define MP3_CMD_DEVICE 0x09 -#define MP3_CMD_RESET 0x0C -#define MP3_CMD_DAC 0x1A - - - - - - -uint16_t MP3_Checksum(uint8_t *array) -{ - uint16_t checksum = 0; - for (uint32_t i = 0; i < 6; i++) { - checksum += array[i]; - } - checksum = checksum^0xffff; - return (checksum+1); -} - - - - - - -void MP3PlayerInit(void) { - MP3Player = new TasmotaSerial(-1, pin[GPIO_MP3_DFR562]); - - if (MP3Player->begin(9600)) { - MP3Player->flush(); - delay(1000); - MP3_CMD(MP3_CMD_RESET, MP3_CMD_RESET_VALUE); - delay(3000); - MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); - } - return; -} -# 159 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_14_mp3.ino" -void MP3_CMD(uint8_t mp3cmd,uint16_t val) { - uint8_t i = 0; - uint8_t cmd[10] = {0x7e,0xff,6,0,0,0,0,0,0,0xef}; - cmd[3] = mp3cmd; - cmd[4] = 0; - cmd[5] = val>>8; - cmd[6] = val; - uint16_t chks = MP3_Checksum(&cmd[1]); - cmd[7] = chks>>8; - cmd[8] = chks; - MP3Player->write(cmd, sizeof(cmd)); - delay(1000); - if (mp3cmd == MP3_CMD_RESET) { - MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); - } - return; -} - - - - - -bool MP3PlayerCmd(void) { - char command[CMDSZ]; - bool serviced = true; - uint8_t disp_len = strlen(D_CMND_MP3); - - if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_MP3), disp_len)) { - int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kMP3_Commands); - - switch (command_code) { - case CMND_MP3_TRACK: - case CMND_MP3_VOLUME: - case CMND_MP3_EQ: - case CMND_MP3_DEVICE: - case CMND_MP3_DAC: - - if (XdrvMailbox.data_len > 0) { - if (command_code == CMND_MP3_TRACK) { MP3_CMD(MP3_CMD_TRACK, XdrvMailbox.payload); } - if (command_code == CMND_MP3_VOLUME) { MP3_CMD(MP3_CMD_VOLUME, XdrvMailbox.payload * 30 / 100); } - if (command_code == CMND_MP3_EQ) { MP3_CMD(MP3_CMD_EQ, XdrvMailbox.payload); } - if (command_code == CMND_MP3_DEVICE) { MP3_CMD(MP3_CMD_DEVICE, XdrvMailbox.payload); } - if (command_code == CMND_MP3_DAC) { MP3_CMD(MP3_CMD_DAC, XdrvMailbox.payload); } - } - Response_P(S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_MP3_PLAY: - case CMND_MP3_PAUSE: - case CMND_MP3_STOP: - case CMND_MP3_RESET: - - if (command_code == CMND_MP3_PLAY) { MP3_CMD(MP3_CMD_PLAY, 0); } - if (command_code == CMND_MP3_PAUSE) { MP3_CMD(MP3_CMD_PAUSE, 0); } - if (command_code == CMND_MP3_STOP) { MP3_CMD(MP3_CMD_STOP, 0); } - if (command_code == CMND_MP3_RESET) { MP3_CMD(MP3_CMD_RESET, 0); } - Response_P(S_JSON_MP3_COMMAND, command, XdrvMailbox.payload); - break; - default: - - serviced = false; - break; - } - } else { - return false; - } - return serviced; -} - - - - - -bool Xdrv14(uint8_t function) -{ - bool result = false; - - if (pin[GPIO_MP3_DFR562] < 99) { - switch (function) { - case FUNC_PRE_INIT: - MP3PlayerInit(); - break; - case FUNC_COMMAND: - result = MP3PlayerCmd(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_15_pca9685.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_15_pca9685.ino" -#ifdef USE_I2C -#ifdef USE_PCA9685 - - - - - - -#define XDRV_15 15 -#define XI2C_01 1 - -#define PCA9685_REG_MODE1 0x00 -#define PCA9685_REG_LED0_ON_L 0x06 -#define PCA9685_REG_PRE_SCALE 0xFE - -#ifndef USE_PCA9685_ADDR - #define USE_PCA9685_ADDR 0x40 -#endif -#ifndef USE_PCA9685_FREQ - #define USE_PCA9685_FREQ 50 -#endif - -bool pca9685_detected = false; -uint16_t pca9685_freq = USE_PCA9685_FREQ; -uint16_t pca9685_pin_pwm_value[16]; - -void PCA9685_Detect(void) -{ - if (I2cActive(USE_PCA9685_ADDR)) { return; } - - uint8_t buffer; - if (I2cValidRead8(&buffer, USE_PCA9685_ADDR, PCA9685_REG_MODE1)) { - I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x20); - if (I2cValidRead8(&buffer, USE_PCA9685_ADDR, PCA9685_REG_MODE1)) { - if (0x20 == buffer) { - pca9685_detected = true; - I2cSetActiveFound(USE_PCA9685_ADDR, "PCA9685"); - PCA9685_Reset(); - } - } - } -} - -void PCA9685_Reset(void) -{ - I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80); - PCA9685_SetPWMfreq(USE_PCA9685_FREQ); - for (uint32_t pin=0;pin<16;pin++) { - PCA9685_SetPWM(pin,0,false); - pca9685_pin_pwm_value[pin] = 0; - } - Response_P(PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}")); -} - -void PCA9685_SetPWMfreq(double freq) { - - - - - if (freq > 23 && freq < 1527) { - pca9685_freq=freq; - } else { - pca9685_freq=50; - } - uint8_t pre_scale_osc = round(25000000/(4096*pca9685_freq))-1; - if (1526 == pca9685_freq) pre_scale_osc=0xFF; - uint8_t current_mode1 = I2cRead8(USE_PCA9685_ADDR, PCA9685_REG_MODE1); - uint8_t sleep_mode1 = (current_mode1&0x7F) | 0x10; - I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, sleep_mode1); - I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_PRE_SCALE, pre_scale_osc); - I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, current_mode1 | 0xA0); -} - -void PCA9685_SetPWM_Reg(uint8_t pin, uint16_t on, uint16_t off) { - uint8_t led_reg = PCA9685_REG_LED0_ON_L + 4 * pin; - uint32_t led_data = 0; - I2cWrite8(USE_PCA9685_ADDR, led_reg, on); - I2cWrite8(USE_PCA9685_ADDR, led_reg+1, (on >> 8)); - I2cWrite8(USE_PCA9685_ADDR, led_reg+2, off); - I2cWrite8(USE_PCA9685_ADDR, led_reg+3, (off >> 8)); -} - -void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) { - if (4096 == pwm) { - PCA9685_SetPWM_Reg(pin, 4096, 0); - } else { - PCA9685_SetPWM_Reg(pin, 0, pwm); - } - pca9685_pin_pwm_value[pin] = pwm; -} - -bool PCA9685_Command(void) -{ - bool serviced = true; - bool validpin = false; - uint8_t paramcount = 0; - if (XdrvMailbox.data_len > 0) { - paramcount=1; - } else { - serviced = false; - return serviced; - } - char sub_string[XdrvMailbox.data_len]; - for (uint32_t ca=0;ca 1) { - uint16_t new_freq = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if ((new_freq >= 24) && (new_freq <= 1526)) { - PCA9685_SetPWMfreq(new_freq); - Response_P(PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}"),new_freq); - return serviced; - } - } else { - Response_P(PSTR("{\"PCA9685\":{\"PWMF\":%i}}"),pca9685_freq); - return serviced; - } - } - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"PWM")) { - if (paramcount > 1) { - uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if (paramcount > 2) { - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 3), "ON")) { - PCA9685_SetPWM(pin, 4096, false); - Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,4096); - serviced = true; - return serviced; - } - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 3), "OFF")) { - PCA9685_SetPWM(pin, 0, false); - Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,0); - serviced = true; - return serviced; - } - uint16_t pwm = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - if ((pin >= 0 && pin <= 15) && (pwm >= 0 && pwm <= 4096)) { - PCA9685_SetPWM(pin, pwm, false); - Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,pwm); - serviced = true; - return serviced; - } - } - } - } - return serviced; -} - -void PCA9685_OutputTelemetry(bool telemetry) -{ - ResponseTime_P(PSTR(",\"PCA9685\":{\"PWM_FREQ\":%i,"),pca9685_freq); - for (uint32_t pin=0;pin<16;pin++) { - ResponseAppend_P(PSTR("\"PWM%i\":%i,"),pin,pca9685_pin_pwm_value[pin]); - } - ResponseAppend_P(PSTR("\"END\":1}}")); - if (telemetry) { - MqttPublishTeleSensor(); - } -} - -bool Xdrv15(uint8_t function) -{ - if (!I2cEnabled(XI2C_01)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - PCA9685_Detect(); - } - else if (pca9685_detected) { - switch (function) { - case FUNC_EVERY_SECOND: - if (tele_period == 0) { - PCA9685_OutputTelemetry(true); - } - break; - case FUNC_COMMAND_DRIVER: - if (XDRV_15 == XdrvMailbox.index) { - result = PCA9685_Command(); - } - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_16_tuyamcu.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_16_tuyamcu.ino" -#ifdef USE_LIGHT -#ifdef USE_TUYA_MCU - -#define XDRV_16 16 -#define XNRG_16 16 - -#ifndef TUYA_DIMMER_ID -#define TUYA_DIMMER_ID 0 -#endif - -#define TUYA_CMD_HEARTBEAT 0x00 -#define TUYA_CMD_QUERY_PRODUCT 0x01 -#define TUYA_CMD_MCU_CONF 0x02 -#define TUYA_CMD_WIFI_STATE 0x03 -#define TUYA_CMD_WIFI_RESET 0x04 -#define TUYA_CMD_WIFI_SELECT 0x05 -#define TUYA_CMD_SET_DP 0x06 -#define TUYA_CMD_STATE 0x07 -#define TUYA_CMD_QUERY_STATE 0x08 - -#define TUYA_LOW_POWER_CMD_WIFI_STATE 0x02 -#define TUYA_LOW_POWER_CMD_WIFI_RESET 0x03 -#define TUYA_LOW_POWER_CMD_WIFI_CONFIG 0x04 -#define TUYA_LOW_POWER_CMD_STATE 0x05 - -#define TUYA_TYPE_BOOL 0x01 -#define TUYA_TYPE_VALUE 0x02 -#define TUYA_TYPE_STRING 0x03 -#define TUYA_TYPE_ENUM 0x04 - -#define TUYA_BUFFER_SIZE 256 - -#include - -TasmotaSerial *TuyaSerial = nullptr; - -struct TUYA { - uint16_t new_dim = 0; - bool ignore_dim = false; - uint8_t cmd_status = 0; - uint8_t cmd_checksum = 0; - uint8_t data_len = 0; - uint8_t wifi_state = -2; - uint8_t heartbeat_timer = 0; -#ifdef USE_ENERGY_SENSOR - uint32_t lastPowerCheckTime = 0; -#endif - char *buffer = nullptr; - int byte_counter = 0; - bool low_power_mode = false; - bool send_success_next_second = false; - uint32_t ignore_dimmer_cmd_timeout = 0; -} Tuya; - - -enum TuyaSupportedFunctions { - TUYA_MCU_FUNC_NONE, - TUYA_MCU_FUNC_SWT1 = 1, - TUYA_MCU_FUNC_SWT2, - TUYA_MCU_FUNC_SWT3, - TUYA_MCU_FUNC_SWT4, - TUYA_MCU_FUNC_REL1 = 11, - TUYA_MCU_FUNC_REL2, - TUYA_MCU_FUNC_REL3, - TUYA_MCU_FUNC_REL4, - TUYA_MCU_FUNC_REL5, - TUYA_MCU_FUNC_REL6, - TUYA_MCU_FUNC_REL7, - TUYA_MCU_FUNC_REL8, - TUYA_MCU_FUNC_DIMMER = 21, - TUYA_MCU_FUNC_POWER = 31, - TUYA_MCU_FUNC_CURRENT, - TUYA_MCU_FUNC_VOLTAGE, - TUYA_MCU_FUNC_BATTERY_STATE, - TUYA_MCU_FUNC_BATTERY_PERCENTAGE, - TUYA_MCU_FUNC_REL1_INV = 41, - TUYA_MCU_FUNC_REL2_INV, - TUYA_MCU_FUNC_REL3_INV, - TUYA_MCU_FUNC_REL4_INV, - TUYA_MCU_FUNC_REL5_INV, - TUYA_MCU_FUNC_REL6_INV, - TUYA_MCU_FUNC_REL7_INV, - TUYA_MCU_FUNC_REL8_INV, - TUYA_MCU_FUNC_LOWPOWER_MODE = 51, - TUYA_MCU_FUNC_LAST = 255 -}; - -const char kTuyaCommand[] PROGMEM = "|" - D_CMND_TUYA_MCU "|" D_CMND_TUYA_MCU_SEND_STATE; - -void (* const TuyaCommand[])(void) PROGMEM = { - &CmndTuyaMcu, &CmndTuyaSend -}; -# 128 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_16_tuyamcu.ino" -void CmndTuyaSend(void) { - if (XdrvMailbox.index > 4) { - return; - } - if (XdrvMailbox.index == 0) { - TuyaRequestState(); - } else { - if (XdrvMailbox.data_len > 0) { - char *p; - char *data; - uint8_t i = 0; - uint8_t dpId = 0; - for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) { - if ( i == 0) { - dpId = strtoul(str, nullptr, 0); - } else { - data = str; - } - i++; - } - - if (1 == XdrvMailbox.index) { - TuyaSendBool(dpId, strtoul(data, nullptr, 0)); - } else if (2 == XdrvMailbox.index) { - TuyaSendValue(dpId, strtoull(data, nullptr, 0)); - } else if (3 == XdrvMailbox.index) { - TuyaSendString(dpId, data); - } else if (4 == XdrvMailbox.index) { - TuyaSendEnum(dpId, strtoul(data, nullptr, 0)); - } - } - } - ResponseCmndDone(); -} - - - - - - - -void CmndTuyaMcu(void) { - if (XdrvMailbox.data_len > 0) { - char *p; - uint8_t i = 0; - uint8_t parm[3] = { 0 }; - for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) { - parm[i] = strtoul(str, nullptr, 0); - i++; - } - - if (TuyaFuncIdValid(parm[0])) { - TuyaAddMcuFunc(parm[0], parm[1]); - restart_flag = 2; - } else { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("TYA: TuyaMcu Invalid function id=%d"), parm[0]); - } - - } - - Response_P(PSTR("{\"" D_CMND_TUYA_MCU "\":[")); - bool added = false; - for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { - if (Settings.tuya_fnid_map[i].fnid != 0) { - if (added) { - ResponseAppend_P(PSTR(",")); - } - ResponseAppend_P(PSTR("{\"fnId\":%d,\"dpId\":%d}" ), Settings.tuya_fnid_map[i].fnid, Settings.tuya_fnid_map[i].dpid); - added = true; - } - } - ResponseAppend_P(PSTR("]}")); -} - - - - - -void TuyaAddMcuFunc(uint8_t fnId, uint8_t dpId) { - bool added = false; - - if (fnId == 0 || dpId == 0) { - for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { - if ((dpId > 0 && Settings.tuya_fnid_map[i].dpid == dpId) || (fnId > TUYA_MCU_FUNC_NONE && Settings.tuya_fnid_map[i].fnid == fnId)) { - Settings.tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE; - Settings.tuya_fnid_map[i].dpid = 0; - break; - } - } - } else { - for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { - if (Settings.tuya_fnid_map[i].dpid == dpId || Settings.tuya_fnid_map[i].dpid == 0 || Settings.tuya_fnid_map[i].fnid == fnId || Settings.tuya_fnid_map[i].fnid == 0) { - if (!added) { - Settings.tuya_fnid_map[i].fnid = fnId; - Settings.tuya_fnid_map[i].dpid = dpId; - added = true; - } else if (Settings.tuya_fnid_map[i].dpid == dpId || Settings.tuya_fnid_map[i].fnid == fnId) { - Settings.tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE; - Settings.tuya_fnid_map[i].dpid = 0; - } - } - } - } - UpdateDevices(); -} - -void UpdateDevices() { - for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { - uint8_t fnId = Settings.tuya_fnid_map[i].fnid; - if (fnId > TUYA_MCU_FUNC_NONE && Settings.tuya_fnid_map[i].dpid > 0) { - - if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { - bitClear(rel_inverted, fnId - TUYA_MCU_FUNC_REL1); - } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { - bitSet(rel_inverted, fnId - TUYA_MCU_FUNC_REL1_INV); - } - - } - } -} - -inline bool TuyaFuncIdValid(uint8_t fnId) { - return (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) || - (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) || - fnId == TUYA_MCU_FUNC_DIMMER || - (fnId >= TUYA_MCU_FUNC_POWER && fnId <= TUYA_MCU_FUNC_VOLTAGE) || - (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) || - (fnId == TUYA_MCU_FUNC_LOWPOWER_MODE); -} - -uint8_t TuyaGetFuncId(uint8_t dpid) { - for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { - if (Settings.tuya_fnid_map[i].dpid == dpid) { - return Settings.tuya_fnid_map[i].fnid; - } - } - return TUYA_MCU_FUNC_NONE; -} - -uint8_t TuyaGetDpId(uint8_t fnId) { - for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) { - if (Settings.tuya_fnid_map[i].fnid == fnId) { - return Settings.tuya_fnid_map[i].dpid; - } - } - return 0; -} - -void TuyaSendCmd(uint8_t cmd, uint8_t payload[] = nullptr, uint16_t payload_len = 0) -{ - uint8_t checksum = (0xFF + cmd + (payload_len >> 8) + (payload_len & 0xFF)); - TuyaSerial->write(0x55); - TuyaSerial->write(0xAA); - TuyaSerial->write((uint8_t)0x00); - TuyaSerial->write(cmd); - TuyaSerial->write(payload_len >> 8); - TuyaSerial->write(payload_len & 0xFF); - snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send \"55aa00%02x%02x%02x"), cmd, payload_len >> 8, payload_len & 0xFF); - for (uint32_t i = 0; i < payload_len; ++i) { - TuyaSerial->write(payload[i]); - checksum += payload[i]; - snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, payload[i]); - } - TuyaSerial->write(checksum); - TuyaSerial->flush(); - snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x\""), log_data, checksum); - AddLog(LOG_LEVEL_DEBUG); -} - -void TuyaSendState(uint8_t id, uint8_t type, uint8_t* value) -{ - uint16_t payload_len = 4; - uint8_t payload_buffer[8]; - payload_buffer[0] = id; - payload_buffer[1] = type; - switch (type) { - case TUYA_TYPE_BOOL: - case TUYA_TYPE_ENUM: - payload_len += 1; - payload_buffer[2] = 0x00; - payload_buffer[3] = 0x01; - payload_buffer[4] = value[0]; - break; - case TUYA_TYPE_VALUE: - payload_len += 4; - payload_buffer[2] = 0x00; - payload_buffer[3] = 0x04; - payload_buffer[4] = value[3]; - payload_buffer[5] = value[2]; - payload_buffer[6] = value[1]; - payload_buffer[7] = value[0]; - break; - - } - - TuyaSendCmd(TUYA_CMD_SET_DP, payload_buffer, payload_len); -} - -void TuyaSendBool(uint8_t id, bool value) -{ - TuyaSendState(id, TUYA_TYPE_BOOL, (uint8_t*)&value); -} - -void TuyaSendValue(uint8_t id, uint32_t value) -{ - TuyaSendState(id, TUYA_TYPE_VALUE, (uint8_t*)(&value)); -} - -void TuyaSendEnum(uint8_t id, uint32_t value) -{ - TuyaSendState(id, TUYA_TYPE_ENUM, (uint8_t*)(&value)); -} - -void TuyaSendString(uint8_t id, char data[]) { - - uint16_t len = strlen(data); - uint16_t payload_len = 4 + len; - uint8_t payload_buffer[payload_len]; - payload_buffer[0] = id; - payload_buffer[1] = TUYA_TYPE_STRING; - payload_buffer[2] = len >> 8; - payload_buffer[3] = len & 0xFF; - - for (uint16_t i = 0; i < len; i++) { - payload_buffer[4+i] = data[i]; - } - - TuyaSendCmd(TUYA_CMD_SET_DP, payload_buffer, payload_len); -} - -bool TuyaSetPower(void) -{ - bool status = false; - - uint8_t rpower = XdrvMailbox.index; - int16_t source = XdrvMailbox.payload; - - uint8_t dpid = TuyaGetDpId(TUYA_MCU_FUNC_REL1 + active_device - 1); - if (dpid == 0) dpid = TuyaGetDpId(TUYA_MCU_FUNC_REL1_INV + active_device - 1); - - if (source != SRC_SWITCH && TuyaSerial) { - TuyaSendBool(dpid, bitRead(rpower, active_device-1) ^ bitRead(rel_inverted, active_device-1)); - delay(20); - status = true; - } - return status; -} - -bool TuyaSetChannels(void) -{ - LightSerialDuty(((uint8_t*)XdrvMailbox.data)[0]); - - return true; -} - -void LightSerialDuty(uint16_t duty) -{ - uint8_t dpid = TuyaGetDpId(TUYA_MCU_FUNC_DIMMER); - if (duty > 0 && !Tuya.ignore_dim && TuyaSerial && dpid > 0) { - duty = changeUIntScale(duty, 0, 255, 0, Settings.dimmer_hw_max); - if (duty < Settings.dimmer_hw_min) { duty = Settings.dimmer_hw_min; } - if (Tuya.new_dim != duty) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim value=%d (id=%d)"), duty, dpid); - Tuya.ignore_dimmer_cmd_timeout = millis() + 250; - TuyaSendValue(dpid, duty); - } - } else if (dpid > 0) { - Tuya.ignore_dim = false; - duty = changeUIntScale(duty, 0, 255, 0, Settings.dimmer_hw_max); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim skipped value=%d"), duty); - } else { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Cannot set dimmer. Dimmer Id unknown")); - } -} - -void TuyaRequestState(void) -{ - if (TuyaSerial) { - - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Read MCU state")); - - TuyaSendCmd(TUYA_CMD_QUERY_STATE); - } -} - -void TuyaResetWifi(void) -{ - if (!Settings.flag.button_restrict) { - char scmnd[20]; - snprintf_P(scmnd, sizeof(scmnd), D_CMND_WIFICONFIG " %d", 2); - ExecuteCommand(scmnd, SRC_BUTTON); - } -} - -void TuyaProcessStatePacket(void) { - char scmnd[20]; - uint8_t dpidStart = 6; - uint8_t fnId; - uint16_t dpDataLen; - - while (dpidStart + 4 < Tuya.byte_counter) { - dpDataLen = Tuya.buffer[dpidStart + 2] << 8 | Tuya.buffer[dpidStart + 3]; - fnId = TuyaGetFuncId(Tuya.buffer[dpidStart]); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d is set for dpId=%d"), fnId, Tuya.buffer[dpidStart]); - - if (Tuya.buffer[dpidStart + 1] == 1) { - - if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[dpidStart + 4]?"On":"Off",bitRead(power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); - if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[dpidStart + 4] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1))) { - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[dpidStart + 4], SRC_SWITCH); - } - } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d-Inverted --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[dpidStart + 4]?"Off":"On",bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); - if (Tuya.buffer[dpidStart + 4] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[dpidStart + 4] ^ 1, SRC_SWITCH); - } - } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[dpidStart + 4], SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1)); - - if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != Tuya.buffer[dpidStart + 4]) { - SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[dpidStart + 4]); - SwitchHandler(1); - } - } - - } - else if (Tuya.buffer[dpidStart + 1] == 2) { - bool tuya_energy_enabled = (XNRG_16 == energy_flg); - uint16_t packetValue = Tuya.buffer[dpidStart + 6] << 8 | Tuya.buffer[dpidStart + 7]; - if (fnId == TUYA_MCU_FUNC_DIMMER) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), packetValue); - Tuya.new_dim = changeUIntScale(packetValue, 0, Settings.dimmer_hw_max, 0, 100); - if (Tuya.ignore_dimmer_cmd_timeout < millis()) { - if ((power || Settings.flag3.tuya_apply_o20) && - (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) { - Tuya.ignore_dim = true; - - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER "3 %d"), Tuya.new_dim ); - ExecuteCommand(scmnd, SRC_SWITCH); - } - } - } - - #ifdef USE_ENERGY_SENSOR - else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_VOLTAGE) { - Energy.voltage[0] = (float)packetValue / 10; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[dpidStart], packetValue); - } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_CURRENT) { - Energy.current[0] = (float)packetValue / 1000; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[dpidStart], packetValue); - } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER) { - Energy.active_power[0] = (float)packetValue / 10; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[dpidStart], packetValue); - - if (Tuya.lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { - Energy.kWhtoday += (float)Energy.active_power[0] * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36; - EnergyUpdateToday(); - } - Tuya.lastPowerCheckTime = Rtc.utc_time; - } - #endif - - } - - - dpidStart += dpDataLen + 4; - } -} - -void TuyaLowPowerModePacketProcess(void) { - switch (Tuya.buffer[3]) { - case TUYA_CMD_QUERY_PRODUCT: - TuyaHandleProductInfoPacket(); - TuyaSetWifiLed(); - break; - - case TUYA_LOW_POWER_CMD_STATE: - TuyaProcessStatePacket(); - Tuya.send_success_next_second = true; - break; - } - -} - -void TuyaHandleProductInfoPacket(void) { - uint16_t dataLength = Tuya.buffer[4] << 8 | Tuya.buffer[5]; - char *data = &Tuya.buffer[6]; - AddLog_P2(LOG_LEVEL_INFO, PSTR("TYA: MCU Product ID: %.*s"), dataLength, data); -} - -void TuyaSendLowPowerSuccessIfNeeded(void) { - uint8_t success = 1; - - if (Tuya.send_success_next_second) { - TuyaSendCmd(TUYA_LOW_POWER_CMD_STATE, &success, 1); - Tuya.send_success_next_second = false; - } -} - -void TuyaNormalPowerModePacketProcess(void) -{ - switch (Tuya.buffer[3]) { - case TUYA_CMD_QUERY_PRODUCT: - TuyaHandleProductInfoPacket(); - TuyaSendCmd(TUYA_CMD_MCU_CONF); - break; - - case TUYA_CMD_HEARTBEAT: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Heartbeat")); - if (Tuya.buffer[6] == 0) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Detected MCU restart")); - Tuya.wifi_state = -2; - } - break; - - case TUYA_CMD_STATE: - TuyaProcessStatePacket(); - break; - - case TUYA_CMD_WIFI_RESET: - case TUYA_CMD_WIFI_SELECT: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: RX WiFi Reset")); - TuyaResetWifi(); - break; - - case TUYA_CMD_WIFI_STATE: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: RX WiFi LED set ACK")); - Tuya.wifi_state = TuyaGetTuyaWifiState(); - break; - - case TUYA_CMD_MCU_CONF: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU configuration Mode=%d"), Tuya.buffer[5]); - - if (Tuya.buffer[5] == 2) { - uint8_t led1_gpio = Tuya.buffer[6]; - uint8_t key1_gpio = Tuya.buffer[7]; - bool key1_set = false; - bool led1_set = false; - for (uint32_t i = 0; i < sizeof(Settings.my_gp); i++) { - if (Settings.my_gp.io[i] == GPIO_LED1) led1_set = true; - else if (Settings.my_gp.io[i] == GPIO_KEY1) key1_set = true; - } - if (!Settings.my_gp.io[led1_gpio] && !led1_set) { - Settings.my_gp.io[led1_gpio] = GPIO_LED1; - restart_flag = 2; - } - if (!Settings.my_gp.io[key1_gpio] && !key1_set) { - Settings.my_gp.io[key1_gpio] = GPIO_KEY1; - restart_flag = 2; - } - } - TuyaRequestState(); - break; - - default: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: RX unknown command")); - } -} - - - - - -bool TuyaModuleSelected(void) -{ - if (!(pin[GPIO_TUYA_RX] < 99) || !(pin[GPIO_TUYA_TX] < 99)) { - pin[GPIO_TUYA_TX] = 1; - pin[GPIO_TUYA_RX] = 3; - Settings.my_gp.io[1] = GPIO_TUYA_TX; - Settings.my_gp.io[3] = GPIO_TUYA_RX; - restart_flag = 2; - } - - if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) == 0 && TUYA_DIMMER_ID > 0) { - TuyaAddMcuFunc(TUYA_MCU_FUNC_DIMMER, TUYA_DIMMER_ID); - } - - bool relaySet = false; - - for (uint8_t i = 0 ; i < MAX_TUYA_FUNCTIONS; i++) { - if ((Settings.tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1 && Settings.tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8 ) || - (Settings.tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1_INV && Settings.tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8_INV )) { - relaySet = true; - devices_present++; - } - } - - if (!relaySet) { - TuyaAddMcuFunc(TUYA_MCU_FUNC_REL1, 1); - devices_present++; - SettingsSaveAll(); - } - - if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) != 0) { - light_type = LT_SERIAL1; - } else { - light_type = LT_BASIC; - } - - if (TuyaGetDpId(TUYA_MCU_FUNC_LOWPOWER_MODE) != 0) { - Tuya.low_power_mode = true; - Settings.flag3.fast_power_cycle_disable = true; - } - - UpdateDevices(); - return true; -} - -void TuyaInit(void) -{ - Tuya.buffer = (char*)(malloc(TUYA_BUFFER_SIZE)); - if (Tuya.buffer != nullptr) { - TuyaSerial = new TasmotaSerial(pin[GPIO_TUYA_RX], pin[GPIO_TUYA_TX], 2); - if (TuyaSerial->begin(9600)) { - if (TuyaSerial->hardwareSerial()) { ClaimSerial(); } - - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Request MCU configuration")); - - TuyaSendCmd(TUYA_CMD_QUERY_PRODUCT); - } - } - Tuya.heartbeat_timer = 0; -} - -void TuyaSerialInput(void) -{ - while (TuyaSerial->available()) { - yield(); - uint8_t serial_in_byte = TuyaSerial->read(); - - if (serial_in_byte == 0x55) { - Tuya.cmd_status = 1; - Tuya.buffer[Tuya.byte_counter++] = serial_in_byte; - Tuya.cmd_checksum += serial_in_byte; - } - else if (Tuya.cmd_status == 1 && serial_in_byte == 0xAA) { - Tuya.cmd_status = 2; - - Tuya.byte_counter = 0; - Tuya.buffer[Tuya.byte_counter++] = 0x55; - Tuya.buffer[Tuya.byte_counter++] = 0xAA; - Tuya.cmd_checksum = 0xFF; - } - else if (Tuya.cmd_status == 2) { - if (Tuya.byte_counter == 5) { - Tuya.cmd_status = 3; - Tuya.data_len = serial_in_byte; - } - Tuya.cmd_checksum += serial_in_byte; - Tuya.buffer[Tuya.byte_counter++] = serial_in_byte; - } - else if ((Tuya.cmd_status == 3) && (Tuya.byte_counter == (6 + Tuya.data_len)) && (Tuya.cmd_checksum == serial_in_byte)) { - Tuya.buffer[Tuya.byte_counter++] = serial_in_byte; - - char hex_char[(Tuya.byte_counter * 2) + 2]; - uint16_t len = Tuya.buffer[4] << 8 | Tuya.buffer[5]; - Response_P(PSTR("{\"" D_JSON_TUYA_MCU_RECEIVED "\":{\"Data\":\"%s\",\"Cmnd\":%d"), ToHex_P((unsigned char*)Tuya.buffer, Tuya.byte_counter, hex_char, sizeof(hex_char)), Tuya.buffer[3]); - - if (len > 0) { - ResponseAppend_P(PSTR(",\"CmndData\":\"%s\""), ToHex_P((unsigned char*)&Tuya.buffer[6], len, hex_char, sizeof(hex_char))); - if (TUYA_CMD_STATE == Tuya.buffer[3]) { - - - uint8_t dpidStart = 6; - while (dpidStart + 4 < Tuya.byte_counter) { - uint8_t dpId = Tuya.buffer[dpidStart]; - uint8_t dpDataType = Tuya.buffer[dpidStart + 1]; - uint16_t dpDataLen = Tuya.buffer[dpidStart + 2] << 8 | Tuya.buffer[dpidStart + 3]; - const unsigned char *dpData = (unsigned char*)&Tuya.buffer[dpidStart + 4]; - const char *dpHexData = ToHex_P(dpData, dpDataLen, hex_char, sizeof(hex_char)); - - if (TUYA_CMD_STATE == Tuya.buffer[3]) { - ResponseAppend_P(PSTR(",\"DpType%uId%u\":"), dpDataType, dpId); - if (TUYA_TYPE_BOOL == dpDataType && dpDataLen == 1) { - ResponseAppend_P(PSTR("%u"), dpData[0]); - } else if (TUYA_TYPE_VALUE == dpDataType && dpDataLen == 4) { - uint32_t dpValue = (uint32_t)dpData[0] << 24 | (uint32_t)dpData[1] << 16 | (uint32_t)dpData[2] << 8 | (uint32_t)dpData[3] << 0; - ResponseAppend_P(PSTR("%u"), dpValue); - } else if (TUYA_TYPE_STRING == dpDataType) { - ResponseAppend_P(PSTR("\"%.*s\""), dpDataLen, dpData); - } else if (TUYA_TYPE_ENUM == dpDataType && dpDataLen == 1) { - ResponseAppend_P(PSTR("%u"), dpData[0]); - } else { - ResponseAppend_P(PSTR("\"0x%s\""), dpHexData); - } - } - - ResponseAppend_P(PSTR(",\"%d\":{\"DpId\":%d,\"DpIdType\":%d,\"DpIdData\":\"%s\""), dpId, dpId, dpDataType, dpHexData); - if (TUYA_TYPE_STRING == dpDataType) { - ResponseAppend_P(PSTR(",\"Type3Data\":\"%.*s\""), dpDataLen, dpData); - } - ResponseAppend_P(PSTR("}")); - dpidStart += dpDataLen + 4; - } - } - } - - ResponseAppend_P(PSTR("}}")); - - if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_TUYA_MCU_RECEIVED)); - } else { - AddLog_P(LOG_LEVEL_DEBUG, mqtt_data); - } - XdrvRulesProcess(); - - if (!Tuya.low_power_mode) { - TuyaNormalPowerModePacketProcess(); - } else { - TuyaLowPowerModePacketProcess(); - } - - Tuya.byte_counter = 0; - Tuya.cmd_status = 0; - Tuya.cmd_checksum = 0; - Tuya.data_len = 0; - } - else if (Tuya.byte_counter < TUYA_BUFFER_SIZE -1) { - Tuya.buffer[Tuya.byte_counter++] = serial_in_byte; - Tuya.cmd_checksum += serial_in_byte; - } else { - Tuya.byte_counter = 0; - Tuya.cmd_status = 0; - Tuya.cmd_checksum = 0; - Tuya.data_len = 0; - } - } -} - -bool TuyaButtonPressed(void) -{ - if (!XdrvMailbox.index && ((PRESSED == XdrvMailbox.payload) && (NOT_PRESSED == Button.last_state[XdrvMailbox.index]))) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Reset GPIO triggered")); - TuyaResetWifi(); - return true; - } - return false; -} - -uint8_t TuyaGetTuyaWifiState(void) { - - uint8_t wifi_state = 0x02; - switch(WifiState()){ - case WIFI_MANAGER: - wifi_state = 0x01; - break; - case WIFI_RESTART: - wifi_state = 0x03; - break; - } - - if (MqttIsConnected()) { - wifi_state = 0x04; - } - - return wifi_state; -} - -void TuyaSetWifiLed(void) -{ - Tuya.wifi_state = TuyaGetTuyaWifiState(); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Set WiFi LED %d (%d)"), Tuya.wifi_state, WifiState()); - - if (Tuya.low_power_mode) { - TuyaSendCmd(TUYA_LOW_POWER_CMD_WIFI_STATE, &Tuya.wifi_state, 1); - } else { - TuyaSendCmd(TUYA_CMD_WIFI_STATE, &Tuya.wifi_state, 1); - } -} - -#ifdef USE_ENERGY_SENSOR - - - - -bool Xnrg16(uint8_t function) -{ - bool result = false; - - if (TUYA_DIMMER == my_module_type) { - if (FUNC_PRE_INIT == function) { - if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0) { - if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0) { - Energy.current_available = false; - } - if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0) { - Energy.voltage_available = false; - } - energy_flg = XNRG_16; - } - } - } - return result; -} -#endif - - - - - -bool Xdrv16(uint8_t function) -{ - bool result = false; - - if (TUYA_DIMMER == my_module_type) { - switch (function) { - case FUNC_LOOP: - if (TuyaSerial) { TuyaSerialInput(); } - break; - case FUNC_MODULE_INIT: - result = TuyaModuleSelected(); - break; - case FUNC_PRE_INIT: - TuyaInit(); - break; - case FUNC_SET_DEVICE_POWER: - result = TuyaSetPower(); - break; - case FUNC_BUTTON_PRESSED: - result = TuyaButtonPressed(); - break; - case FUNC_EVERY_SECOND: - if (TuyaSerial && Tuya.wifi_state != TuyaGetTuyaWifiState()) { TuyaSetWifiLed(); } - if (!Tuya.low_power_mode) { - Tuya.heartbeat_timer++; - if (Tuya.heartbeat_timer > 10) { - Tuya.heartbeat_timer = 0; - TuyaSendCmd(TUYA_CMD_HEARTBEAT); - } - } else { - TuyaSendLowPowerSuccessIfNeeded(); - } - break; - case FUNC_SET_CHANNELS: - result = TuyaSetChannels(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kTuyaCommand, TuyaCommand); - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_17_rcswitch.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_17_rcswitch.ino" -#ifdef USE_RC_SWITCH - - - - -#define XDRV_17 17 - -#define D_JSON_RF_PROTOCOL "Protocol" -#define D_JSON_RF_BITS "Bits" -#define D_JSON_RF_DATA "Data" - -#define D_CMND_RFSEND "RFSend" -#define D_JSON_RF_PULSE "Pulse" -#define D_JSON_RF_REPEAT "Repeat" - -const char kRfSendCommands[] PROGMEM = "|" - D_CMND_RFSEND; - -void (* const RfSendCommand[])(void) PROGMEM = { - &CmndRfSend }; - -#include - -RCSwitch mySwitch = RCSwitch(); - -#define RF_TIME_AVOID_DUPLICATE 1000 - -uint32_t rf_lasttime = 0; - -void RfReceiveCheck(void) -{ - if (mySwitch.available()) { - - unsigned long data = mySwitch.getReceivedValue(); - unsigned int bits = mySwitch.getReceivedBitlength(); - int protocol = mySwitch.getReceivedProtocol(); - int delay = mySwitch.getReceivedDelay(); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFR: Data 0x%lX (%u), Bits %d, Protocol %d, Delay %d"), data, data, bits, protocol, delay); - - uint32_t now = millis(); - if ((now - rf_lasttime > RF_TIME_AVOID_DUPLICATE) && (data > 0)) { - rf_lasttime = now; - - char stemp[16]; - if (Settings.flag.rf_receive_decimal) { - snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)data); - } else { - snprintf_P(stemp, sizeof(stemp), PSTR("\"0x%lX\""), (uint32_t)data); - } - ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"), - stemp, bits, protocol, delay); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); - XdrvRulesProcess(); -#ifdef USE_DOMOTICZ - DomoticzSensor(DZ_COUNT, data); -#endif - } - mySwitch.resetAvailable(); - } -} - -void RfInit(void) -{ - if (pin[GPIO_RFSEND] < 99) { - mySwitch.enableTransmit(pin[GPIO_RFSEND]); - } - if (pin[GPIO_RFRECV] < 99) { - pinMode( pin[GPIO_RFRECV], INPUT); - mySwitch.enableReceive(pin[GPIO_RFRECV]); - } -} - - - - - -void CmndRfSend(void) -{ - bool error = false; - - if (XdrvMailbox.data_len) { - unsigned long data = 0; - unsigned int bits = 24; - int protocol = 1; - int repeat = 10; - int pulse = 350; - - char dataBufUc[XdrvMailbox.data_len + 1]; - UpperCase(dataBufUc, XdrvMailbox.data); - StaticJsonBuffer<150> jsonBuf; - JsonObject &root = jsonBuf.parseObject(dataBufUc); - if (root.success()) { - - char parm_uc[10]; - data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_DATA))], nullptr, 0); - bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_BITS))]; - protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_PROTOCOL))]; - repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_REPEAT))]; - pulse = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_PULSE))]; - } else { - - char *p; - uint8_t i = 0; - for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 5; str = strtok_r(nullptr, ", ", &p)) { - switch (i++) { - case 0: - data = strtoul(str, nullptr, 0); - break; - case 1: - bits = atoi(str); - break; - case 2: - protocol = atoi(str); - break; - case 3: - repeat = atoi(str); - break; - case 4: - pulse = atoi(str); - } - } - } - - if (!protocol) { protocol = 1; } - mySwitch.setProtocol(protocol); - if (!pulse) { pulse = 350; } - mySwitch.setPulseLength(pulse); - if (!repeat) { repeat = 10; } - mySwitch.setRepeatTransmit(repeat); - if (!bits) { bits = 24; } - if (data) { - mySwitch.send(data, bits); - ResponseCmndDone(); - } else { - error = true; - } - } else { - error = true; - } - if (error) { - Response_P(PSTR("{\"" D_CMND_RFSEND "\":\"" D_JSON_NO " " D_JSON_RF_DATA ", " D_JSON_RF_BITS ", " D_JSON_RF_PROTOCOL ", " D_JSON_RF_REPEAT " " D_JSON_OR " " D_JSON_RF_PULSE "\"}")); - } -} - - - - - -bool Xdrv17(uint8_t function) -{ - bool result = false; - - if ((pin[GPIO_RFSEND] < 99) || (pin[GPIO_RFRECV] < 99)) { - switch (function) { - case FUNC_EVERY_50_MSECOND: - if (pin[GPIO_RFRECV] < 99) { - RfReceiveCheck(); - } - break; - case FUNC_COMMAND: - if (pin[GPIO_RFSEND] < 99) { - result = DecodeCommand(kRfSendCommands, RfSendCommand); - } - break; - case FUNC_INIT: - RfInit(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_18_armtronix_dimmers.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_18_armtronix_dimmers.ino" -#ifdef USE_LIGHT -#ifdef USE_ARMTRONIX_DIMMERS - - - - - - - -#define XDRV_18 18 - -#include - -TasmotaSerial *ArmtronixSerial = nullptr; - -struct ARMTRONIX { - bool ignore_dim = false; - int8_t wifi_state = -2; - int8_t dim_state[2]; - int8_t knob_state[2]; -} Armtronix; - - - - - -bool ArmtronixSetChannels(void) -{ - LightSerial2Duty(((uint8_t*)XdrvMailbox.data)[0], ((uint8_t*)XdrvMailbox.data)[1]); - return true; -} - -void LightSerial2Duty(uint8_t duty1, uint8_t duty2) -{ - if (ArmtronixSerial && !Armtronix.ignore_dim) { - duty1 = ((float)duty1)/2.575757; - duty2 = ((float)duty2)/2.575757; - Armtronix.dim_state[0] = duty1; - Armtronix.dim_state[1] = duty2; - ArmtronixSerial->print("Dimmer1:"); - ArmtronixSerial->print(duty1); - ArmtronixSerial->print("\nDimmer2:"); - ArmtronixSerial->println(duty2); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Send Serial Packet Dim Values=%d,%d"), Armtronix.dim_state[0],Armtronix.dim_state[1]); - - } else { - Armtronix.ignore_dim = false; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Send Dim Level skipped due to already set. Value=%d,%d"), Armtronix.dim_state[0],Armtronix.dim_state[1]); - - } -} - -void ArmtronixRequestState(void) -{ - if (ArmtronixSerial) { - - AddLog_P(LOG_LEVEL_DEBUG, PSTR("ARM: Request MCU state")); - ArmtronixSerial->println("Status"); - - } -} - - - - - -bool ArmtronixModuleSelected(void) -{ - devices_present++; - light_type = LT_SERIAL2; - return true; -} - -void ArmtronixInit(void) -{ - Armtronix.dim_state[0] = -1; - Armtronix.dim_state[1] = -1; - Armtronix.knob_state[0] = -1; - Armtronix.knob_state[1] = -1; - ArmtronixSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2); - if (ArmtronixSerial->begin(115200)) { - if (ArmtronixSerial->hardwareSerial()) { ClaimSerial(); } - ArmtronixSerial->println("Status"); - } -} - -void ArmtronixSerialInput(void) -{ - String answer; - int8_t newDimState[2]; - uint8_t temp; - int commaIndex; - char scmnd[20]; - if (ArmtronixSerial->available()) { - yield(); - answer = ArmtronixSerial->readStringUntil('\n'); - if (answer.substring(0,7) == "Status:") { - commaIndex = 6; - for (uint32_t i =0; i<2; i++) { - newDimState[i] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt(); - if (newDimState[i] != Armtronix.dim_state[i]) { - temp = ((float)newDimState[i])*1.01010101010101; - Armtronix.dim_state[i] = newDimState[i]; - Armtronix.ignore_dim = true; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_CHANNEL "%d %d"),i+1, temp); - ExecuteCommand(scmnd,SRC_SWITCH); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Send CMND_CHANNEL=%s"), scmnd ); - } - commaIndex = answer.indexOf(',',commaIndex+1); - } - Armtronix.knob_state[0] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt(); - commaIndex = answer.indexOf(',',commaIndex+1); - Armtronix.knob_state[1] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt(); - } - } -} - -void ArmtronixSetWifiLed(void) -{ - uint8_t wifi_state = 0x02; - - switch (WifiState()) { - case WIFI_MANAGER: - wifi_state = 0x01; - break; - case WIFI_RESTART: - wifi_state = 0x03; - break; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ARM: Set WiFi LED to state %d (%d)"), wifi_state, WifiState()); - - char state = '0' + ((wifi_state & 1) > 0); - ArmtronixSerial->print("Setled:"); - ArmtronixSerial->write(state); - ArmtronixSerial->write(','); - state = '0' + ((wifi_state & 2) > 0); - ArmtronixSerial->write(state); - ArmtronixSerial->write(10); - Armtronix.wifi_state = WifiState(); -} - - - - - -bool Xdrv18(uint8_t function) -{ - bool result = false; - - if (ARMTRONIX_DIMMERS == my_module_type) { - switch (function) { - case FUNC_LOOP: - if (ArmtronixSerial) { ArmtronixSerialInput(); } - break; - case FUNC_MODULE_INIT: - result = ArmtronixModuleSelected(); - break; - case FUNC_INIT: - ArmtronixInit(); - break; - case FUNC_EVERY_SECOND: - if (ArmtronixSerial) { - if (Armtronix.wifi_state!=WifiState()) { ArmtronixSetWifiLed(); } - if (uptime &1) { - ArmtronixSerial->println("Status"); - } - } - break; - case FUNC_SET_CHANNELS: - result = ArmtronixSetChannels(); - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_19_ps16dz_dimmer.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_19_ps16dz_dimmer.ino" -#ifdef USE_LIGHT -#ifdef USE_PS_16_DZ - - - - -#define XDRV_19 19 - -#define PS16DZ_BUFFER_SIZE 80 - -#include - -TasmotaSerial *PS16DZSerial = nullptr; - -struct PS16DZ { - char *rx_buffer = nullptr; - int byte_counter = 0; - uint8_t dimmer = 0; -} Ps16dz; - - - - - -void PS16DZSerialSend(const char *tx_buffer) -{ - - - PS16DZSerial->print(tx_buffer); - PS16DZSerial->write(0x1B); - PS16DZSerial->flush(); -} - -void PS16DZSerialSendOk(void) -{ - char tx_buffer[16]; - snprintf_P(tx_buffer, sizeof(tx_buffer), PSTR("AT+SEND=ok")); - PS16DZSerialSend(tx_buffer); -} - - - - -void PS16DZSerialSendUpdateCommand(void) -{ - uint8_t light_state_dimmer = light_state.getDimmer(); - - light_state_dimmer = (light_state_dimmer < Settings.dimmer_hw_min) ? Settings.dimmer_hw_min : light_state_dimmer; - light_state_dimmer = (light_state_dimmer > Settings.dimmer_hw_max) ? Settings.dimmer_hw_max : light_state_dimmer; - - char tx_buffer[80]; - snprintf_P(tx_buffer, sizeof(tx_buffer), PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"switch\":\"%s\",\"bright\":%d"), - LocalTime(), millis()%1000, power?"on":"off", light_state_dimmer); - - PS16DZSerialSend(tx_buffer); -} - - - - - -void PS16DZSerialInput(void) -{ - char scmnd[20]; - while (PS16DZSerial->available()) { - yield(); - uint8_t serial_in_byte = PS16DZSerial->read(); - if (serial_in_byte != 0x1B) { - if (Ps16dz.byte_counter >= PS16DZ_BUFFER_SIZE - 1) { - memset(Ps16dz.rx_buffer, 0, PS16DZ_BUFFER_SIZE); - Ps16dz.byte_counter = 0; - } - if (Ps16dz.byte_counter || (!Ps16dz.byte_counter && ('A' == serial_in_byte))) { - Ps16dz.rx_buffer[Ps16dz.byte_counter++] = serial_in_byte; - } - } else { - Ps16dz.rx_buffer[Ps16dz.byte_counter++] = 0x00; - - - - - if (!strncmp(Ps16dz.rx_buffer+3, "RESULT", 6)) { - - } - else if (!strncmp(Ps16dz.rx_buffer+3, "UPDATE", 6)) { - - char *end_str; - char *string = Ps16dz.rx_buffer+10; - char *token = strtok_r(string, ",", &end_str); - - bool is_switch_change = false; - bool is_brightness_change = false; - - while (token != nullptr) { - char* end_token; - char* token2 = strtok_r(token, ":", &end_token); - char* token3 = strtok_r(nullptr, ":", &end_token); - - if (!strncmp(token2, "\"switch\"", 8)) { - bool switch_state = !strncmp(token3, "\"on\"", 4) ? true : false; - - - - is_switch_change = (switch_state != power); - if (is_switch_change) { - ExecuteCommandPower(1, switch_state, SRC_SWITCH); - } - } - else if (!strncmp(token2, "\"bright\"", 8)) { - Ps16dz.dimmer = atoi(token3); - - - - is_brightness_change = Ps16dz.dimmer != Settings.light_dimmer; - if (power && (Ps16dz.dimmer > 0) && is_brightness_change) { - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), Ps16dz.dimmer); - ExecuteCommand(scmnd, SRC_SWITCH); - } - } - else if (!strncmp(token2, "\"sequence\"", 10)) { - - - - } - token = strtok_r(nullptr, ",", &end_str); - } - - if (!is_brightness_change) { - - - - PS16DZSerialSendOk(); - } - } - else if (!strncmp(Ps16dz.rx_buffer+3, "SETTING", 7)) { - - - if (!Settings.flag.button_restrict) { - int state = WIFI_MANAGER; - if (!strncmp(Ps16dz.rx_buffer+10, "=exit", 5)) { state = WIFI_RETRY; } - if (state != Settings.sta_config) { - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " %d"), state); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - memset(Ps16dz.rx_buffer, 0, PS16DZ_BUFFER_SIZE); - Ps16dz.byte_counter = 0; - } - } -} - -bool PS16DZSerialSendUpdateCommandIfRequired(void) -{ - if (!PS16DZSerial) { return true; } - - bool is_switch_change = (XdrvMailbox.payload != SRC_SWITCH); - bool is_brightness_change = (light_state.getDimmer() != Ps16dz.dimmer); - - if (is_switch_change || is_brightness_change) { - PS16DZSerialSendUpdateCommand(); - } - - return true; -} - -void PS16DZInit(void) -{ - Ps16dz.rx_buffer = (char*)(malloc(PS16DZ_BUFFER_SIZE)); - if (Ps16dz.rx_buffer != nullptr) { - PS16DZSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2); - if (PS16DZSerial->begin(19200)) { - if (PS16DZSerial->hardwareSerial()) { ClaimSerial(); } - } - } -} - -bool PS16DZModuleSelected(void) -{ - devices_present++; - light_type = LT_SERIAL1; - - return true; -} - - - - - -bool Xdrv19(uint8_t function) -{ - bool result = false; - - if (PS_16_DZ == my_module_type) { - switch (function) { - case FUNC_LOOP: - if (PS16DZSerial) { PS16DZSerialInput(); } - break; - case FUNC_SET_DEVICE_POWER: - case FUNC_SET_CHANNELS: - result = PS16DZSerialSendUpdateCommandIfRequired(); - break; - case FUNC_INIT: - PS16DZInit(); - break; - case FUNC_MODULE_INIT: - result = PS16DZModuleSelected(); - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_20_hue.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_20_hue.ino" -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_20_hue.ino" -#define XDRV_20 20 - -const char HUE_RESPONSE[] PROGMEM = - "HTTP/1.1 200 OK\r\n" - "HOST: 239.255.255.250:1900\r\n" - "CACHE-CONTROL: max-age=100\r\n" - "EXT:\r\n" - "LOCATION: http://%s:80/description.xml\r\n" - "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.24.0\r\n" - "hue-bridgeid: %s\r\n"; -const char HUE_ST1[] PROGMEM = - "ST: upnp:rootdevice\r\n" - "USN: uuid:%s::upnp:rootdevice\r\n" - "\r\n"; -const char HUE_ST2[] PROGMEM = - "ST: uuid:%s\r\n" - "USN: uuid:%s\r\n" - "\r\n"; -const char HUE_ST3[] PROGMEM = - "ST: urn:schemas-upnp-org:device:basic:1\r\n" - "USN: uuid:%s\r\n" - "\r\n"; - -String HueBridgeId(void) -{ - String temp = WiFi.macAddress(); - temp.replace(":", ""); - String bridgeid = temp.substring(0, 6); - bridgeid += "FFFE"; - bridgeid += temp.substring(6); - return bridgeid; -} - -String HueSerialnumber(void) -{ - String serial = WiFi.macAddress(); - serial.replace(":", ""); - serial.toLowerCase(); - return serial; -} - -String HueUuid(void) -{ - String uuid = F("f6543a06-da50-11ba-8d8f-"); - uuid += HueSerialnumber(); - return uuid; -} - -void HueRespondToMSearch(void) -{ - char message[TOPSZ]; - - TickerMSearch.detach(); - if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) { - char response[320]; - snprintf_P(response, sizeof(response), HUE_RESPONSE, WiFi.localIP().toString().c_str(), HueBridgeId().c_str()); - int len = strlen(response); - String uuid = HueUuid(); - - snprintf_P(response + len, sizeof(response) - len, HUE_ST1, uuid.c_str()); - PortUdp.write(response); - PortUdp.endPacket(); - - snprintf_P(response + len, sizeof(response) - len, HUE_ST2, uuid.c_str(), uuid.c_str()); - PortUdp.write(response); - PortUdp.endPacket(); - - snprintf_P(response + len, sizeof(response) - len, HUE_ST3, uuid.c_str()); - PortUdp.write(response); - PortUdp.endPacket(); - - snprintf_P(message, sizeof(message), PSTR(D_3_RESPONSE_PACKETS_SENT)); - } else { - snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); - } - - PrepLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"), - message, udp_remote_ip.toString().c_str(), udp_remote_port); - - udp_response_mutex = false; -} - - - - - -const char HUE_DESCRIPTION_XML[] PROGMEM = - "" - "" - "" - "1" - "0" - "" - - "http://{x1:80/" - "" - "urn:schemas-upnp-org:device:Basic:1" - "Amazon-Echo-HA-Bridge ({x1)" - - "Royal Philips Electronics" - "http://www.philips.com" - "Philips hue Personal Wireless Lighting" - "Philips hue bridge 2012" - "929000226503" - "{x3" - "uuid:{x2" - "" - "\r\n" - "\r\n"; -const char HUE_LIGHTS_STATUS_JSON1_SUFFIX[] PROGMEM = - "%s\"alert\":\"none\"," - "\"effect\":\"none\"," - "\"reachable\":true}"; -const char HUE_LIGHTS_STATUS_JSON2[] PROGMEM = - ",\"type\":\"Extended color light\"," - "\"name\":\"%s\"," - "\"modelid\":\"LCT007\"," - "\"uniqueid\":\"%s\"," - "\"swversion\":\"5.50.1.19085\"}"; -const char HUE_GROUP0_STATUS_JSON[] PROGMEM = - "{\"name\":\"Group 0\"," - "\"lights\":[{l1]," - "\"type\":\"LightGroup\"," - "\"action\":"; - -const char HueConfigResponse_JSON[] PROGMEM = - "{\"name\":\"Philips hue\"," - "\"mac\":\"{ma\"," - "\"dhcp\":true," - "\"ipaddress\":\"{ip\"," - "\"netmask\":\"{ms\"," - "\"gateway\":\"{gw\"," - "\"proxyaddress\":\"none\"," - "\"proxyport\":0," - "\"bridgeid\":\"{br\"," - "\"UTC\":\"{dt\"," - "\"whitelist\":{\"{id\":{" - "\"last use date\":\"{dt\"," - "\"create date\":\"{dt\"," - "\"name\":\"Remote\"}}," - "\"swversion\":\"01041302\"," - "\"apiversion\":\"1.17.0\"," - "\"swupdate\":{\"updatestate\":0,\"url\":\"\",\"text\":\"\",\"notify\": false}," - "\"linkbutton\":false," - "\"portalservices\":false" - "}"; -const char HUE_ERROR_JSON[] PROGMEM = - "[{\"error\":{\"type\":901,\"address\":\"/\",\"description\":\"Internal Error\"}}]"; - - - -String GetHueDeviceId(uint16_t id) -{ - String deviceid = WiFi.macAddress(); - deviceid += F(":00:11-"); - deviceid += String(id); - deviceid.toLowerCase(); - return deviceid; -} - -String GetHueUserId(void) -{ - char userid[7]; - - snprintf_P(userid, sizeof(userid), PSTR("%03x"), ESP_getChipId()); - return String(userid); -} - -void HandleUpnpSetupHue(void) -{ - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_HUE_BRIDGE_SETUP)); - String description_xml = FPSTR(HUE_DESCRIPTION_XML); - description_xml.replace("{x1", WiFi.localIP().toString()); - description_xml.replace("{x2", HueUuid()); - description_xml.replace("{x3", HueSerialnumber()); - WSSend(200, CT_XML, description_xml); -} - -void HueNotImplemented(String *path) -{ - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_API_NOT_IMPLEMENTED " (%s)"), path->c_str()); - - WSSend(200, CT_JSON, "{}"); -} - -void HueConfigResponse(String *response) -{ - *response += FPSTR(HueConfigResponse_JSON); - response->replace("{ma", WiFi.macAddress()); - response->replace("{ip", WiFi.localIP().toString()); - response->replace("{ms", WiFi.subnetMask().toString()); - response->replace("{gw", WiFi.gatewayIP().toString()); - response->replace("{br", HueBridgeId()); - response->replace("{dt", GetDateAndTime(DT_UTC)); - response->replace("{id", GetHueUserId()); -} - -void HueConfig(String *path) -{ - String response = ""; - HueConfigResponse(&response); - WSSend(200, CT_JSON, response); -} - - - -bool g_gotct = false; - - - - -uint16_t prev_hue = 0; -uint8_t prev_sat = 0; -uint8_t prev_bri = 254; -uint16_t prev_ct = 254; -char prev_x_str[24] = "\0"; -char prev_y_str[24] = "\0"; - -uint8_t getLocalLightSubtype(uint8_t device) { - if (light_type) { - if (device >= Light.device) { - if (Settings.flag3.pwm_multi_channels) { - return LST_SINGLE; - } else { - return Light.subtype; - } - } else { - return LST_NONE; - } - } else { - return LST_NONE; - } -} - -void HueLightStatus1(uint8_t device, String *response) -{ - uint16_t ct = 0; - uint8_t color_mode; - String light_status = ""; - uint16_t hue = 0; - uint8_t sat = 0; - uint8_t bri = 254; - uint32_t echo_gen = findEchoGeneration(); - - - uint8_t local_light_subtype = getLocalLightSubtype(device); - - bri = LightGetBri(device); - if (bri > 254) bri = 254; - if (bri < 1) bri = 1; - -#ifdef USE_SHUTTER - if (ShutterState(device)) { - bri = (float)((Settings.shutter_options[device-1] & 1) ? 100 - Settings.shutter_position[device-1] : Settings.shutter_position[device-1]) / 100; - } -#endif - - if (light_type) { - light_state.getHSB(&hue, &sat, nullptr); - - if ((bri > prev_bri ? bri - prev_bri : prev_bri - bri) < 1) - bri = prev_bri; - - if (sat > 254) sat = 254; - if ((sat > prev_sat ? sat - prev_sat : prev_sat - sat) < 1) { - sat = prev_sat; - } else { - prev_x_str[0] = prev_y_str[0] = 0; - } - - hue = changeUIntScale(hue, 0, 360, 0, 65535); - if ((hue > prev_hue ? hue - prev_hue : prev_hue - hue) < 400) { - hue = prev_hue; - } else { - prev_x_str[0] = prev_y_str[0] = 0; - } - - color_mode = light_state.getColorMode(); - ct = light_state.getCT(); - if (LCM_RGB == color_mode) { g_gotct = false; } - if (LCM_CT == color_mode) { g_gotct = true; } - - - - if ((ct > prev_ct ? ct - prev_ct : prev_ct - ct) < 1) - ct = prev_ct; - - - - } - - const size_t buf_size = 256; - char * buf = (char*) malloc(buf_size); - - snprintf_P(buf, buf_size, PSTR("{\"on\":%s,"), (power & (1 << (device-1))) ? "true" : "false"); - - if ((1 == echo_gen) || (LST_SINGLE <= local_light_subtype)) { - snprintf_P(buf, buf_size, PSTR("%s\"bri\":%d,"), buf, bri); - } - if (LST_COLDWARM <= local_light_subtype) { - snprintf_P(buf, buf_size, PSTR("%s\"colormode\":\"%s\","), buf, g_gotct ? "ct" : "hs"); - } - if (LST_RGB <= local_light_subtype) { - if (prev_x_str[0] && prev_y_str[0]) { - snprintf_P(buf, buf_size, PSTR("%s\"xy\":[%s,%s],"), buf, prev_x_str, prev_y_str); - } else { - float x, y; - light_state.getXY(&x, &y); - snprintf_P(buf, buf_size, PSTR("%s\"xy\":[%s,%s],"), buf, String(x, 5).c_str(), String(y, 5).c_str()); - } - snprintf_P(buf, buf_size, PSTR("%s\"hue\":%d,\"sat\":%d,"), buf, hue, sat); - } - if (LST_COLDWARM == local_light_subtype || LST_RGBW <= local_light_subtype) { - snprintf_P(buf, buf_size, PSTR("%s\"ct\":%d,"), buf, ct > 0 ? ct : 284); - } - snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON1_SUFFIX, buf); - - *response += buf; - free(buf); -} - - - -bool HueActive(uint8_t device) { - if (device > MAX_FRIENDLYNAMES) { device = MAX_FRIENDLYNAMES; } - return '$' != *SettingsText(SET_FRIENDLYNAME1 +device -1); -} - -void HueLightStatus2(uint8_t device, String *response) -{ - const size_t buf_size = 192; - char * buf = (char*) malloc(buf_size); - const size_t max_name_len = 32; - char fname[max_name_len + 1]; - - strlcpy(fname, SettingsText(device <= MAX_FRIENDLYNAMES ? SET_FRIENDLYNAME1 + device -1 : SET_FRIENDLYNAME1 + MAX_FRIENDLYNAMES -1), max_name_len + 1); - - if (device > MAX_FRIENDLYNAMES) { - uint32_t fname_len = strlen(fname); - if (fname_len > max_name_len - 2) { fname_len = max_name_len - 2; } - fname[fname_len++] = '-'; - if (device - MAX_FRIENDLYNAMES < 10) { - fname[fname_len++] = '0' + device - MAX_FRIENDLYNAMES; - } else { - fname[fname_len++] = 'A' + device - MAX_FRIENDLYNAMES - 10; - } - fname[fname_len] = 0x00; - } - snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON2, fname, GetHueDeviceId(device).c_str()); - *response += buf; - free(buf); -} - - - - - -#ifndef USE_ZIGBEE -uint32_t EncodeLightId(uint8_t relay_id) -#else -uint32_t EncodeLightId(uint8_t relay_id, uint16_t z_shortaddr = 0) -#endif -{ - uint8_t mac[6]; - WiFi.macAddress(mac); - uint32_t id = (mac[3] << 20) | (mac[4] << 12) | (mac[5] << 4); - - if (relay_id >= 32) { - relay_id = 0; - } - if (relay_id > 15) { - id |= (1 << 28); - } - id |= (relay_id & 0xF); -#ifdef USE_ZIGBEE - if ((z_shortaddr) && (!relay_id)) { - - id = (1 << 29) | z_shortaddr; - } -#endif - - return id; -} - - - - - - - -#ifndef USE_ZIGBEE -uint32_t DecodeLightId(uint32_t hue_id) -#else -uint32_t DecodeLightId(uint32_t hue_id, uint16_t * shortaddr = nullptr) -#endif -{ - uint8_t relay_id = hue_id & 0xF; - if (hue_id & (1 << 28)) { - relay_id += 16; - } - if (0 == relay_id) { - relay_id = 32; - } -#ifdef USE_ZIGBEE - if (hue_id & (1 << 29)) { - - if (shortaddr) { *shortaddr = hue_id & 0xFFFF; } - relay_id = 0; - } -#endif - return relay_id; -} - -static const char * FIRST_GEN_UA[] = { - "AEOBC", -}; - - -uint32_t findEchoGeneration(void) { - - String user_agent = Webserver->header("User-Agent"); - uint32_t gen = 2; - - for (uint32_t i = 0; i < sizeof(FIRST_GEN_UA)/sizeof(char*); i++) { - if (user_agent.indexOf(FIRST_GEN_UA[i]) >= 0) { - gen = 1; - break; - } - } - if (0 == user_agent.length()) { - gen = 1; - } - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " User-Agent: %s, gen=%d"), user_agent.c_str(), gen); - - return gen; -} - -void HueGlobalConfig(String *path) { - String response; - - path->remove(0,1); - response = F("{\"lights\":{"); - bool appending = false; - CheckHue(&response, appending); -#ifdef USE_ZIGBEE - ZigbeeCheckHue(&response, appending); -#endif - response += F("},\"groups\":{},\"schedules\":{},\"config\":"); - HueConfigResponse(&response); - response += "}"; - WSSend(200, CT_JSON, response); -} - -void HueAuthentication(String *path) -{ - char response[38]; - - snprintf_P(response, sizeof(response), PSTR("[{\"success\":{\"username\":\"%s\"}}]"), GetHueUserId().c_str()); - WSSend(200, CT_JSON, response); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " Authentication Result (%s)"), response); -} - - -void CheckHue(String * response, bool &appending) { - uint8_t maxhue = (devices_present > MAX_HUE_DEVICES) ? MAX_HUE_DEVICES : devices_present; - for (uint32_t i = 1; i <= maxhue; i++) { - if (HueActive(i)) { - if (appending) { *response += ","; } - *response += "\""; - *response += EncodeLightId(i); - *response += F("\":{\"state\":"); - HueLightStatus1(i, response); - HueLightStatus2(i, response); - appending = true; - } - } -} - -void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) { - uint16_t tmp = 0; - uint16_t hue = 0; - uint8_t sat = 0; - uint8_t bri = 254; - uint16_t ct = 0; - bool on = false; - bool resp = false; - bool change = false; - uint8_t local_light_subtype = getLocalLightSubtype(device); - - const size_t buf_size = 100; - char * buf = (char*) malloc(buf_size); - - if (Webserver->args()) { - response = "["; - - StaticJsonBuffer<300> jsonBuffer; - JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1)); - if (hue_json.containsKey("on")) { - on = hue_json["on"]; - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/on\":%s}}"), - device_id, on ? "true" : "false"); - -#ifdef USE_SHUTTER - if (ShutterState(device)) { - if (!change) { - bri = on ? 1.0f : 0.0f; - change = true; - resp = true; - response += buf; - } - } else { -#endif -# 554 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_20_hue.ino" - ExecuteCommandPower(device, (on) ? POWER_ON : POWER_OFF, SRC_HUE); - response += buf; - resp = true; -#ifdef USE_SHUTTER - } -#endif - } - - if (light_type && (local_light_subtype >= LST_SINGLE)) { - if (!Settings.flag3.pwm_multi_channels) { - light_state.getHSB(&hue, &sat, nullptr); - bri = light_state.getBri(); - ct = light_state.getCT(); - uint8_t color_mode = light_state.getColorMode(); - if (LCM_RGB == color_mode) { g_gotct = false; } - if (LCM_CT == color_mode) { g_gotct = true; } - - } else { - bri = LightGetBri(device); - } - } - prev_x_str[0] = prev_y_str[0] = 0; - - if (hue_json.containsKey("bri")) { - bri = hue_json["bri"]; - prev_bri = bri; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "bri", bri); - response += buf; - if (LST_SINGLE <= Light.subtype) { - - if (254 <= bri) { bri = 255; } - change = true; - } - resp = true; - } - - - if (hue_json.containsKey("xy")) { - float x = hue_json["xy"][0]; - float y = hue_json["xy"][1]; - const String &x_str = hue_json["xy"][0]; - const String &y_str = hue_json["xy"][1]; - x_str.toCharArray(prev_x_str, sizeof(prev_x_str)); - y_str.toCharArray(prev_y_str, sizeof(prev_y_str)); - uint8_t rr,gg,bb; - LightStateClass::XyToRgb(x, y, &rr, &gg, &bb); - LightStateClass::RgbToHsb(rr, gg, bb, &hue, &sat, nullptr); - prev_hue = changeUIntScale(hue, 0, 360, 0, 65535); - prev_sat = (sat > 254 ? 254 : sat); - - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/xy\":[%s,%s]}}"), - device_id, prev_x_str, prev_y_str); - response += buf; - g_gotct = false; - resp = true; - change = true; - } - if (hue_json.containsKey("hue")) { - hue = hue_json["hue"]; - prev_hue = hue; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "hue", hue); - response += buf; - if (LST_RGB <= Light.subtype) { - - hue = changeUIntScale(hue, 0, 65535, 0, 360); - g_gotct = false; - change = true; - } - resp = true; - } - if (hue_json.containsKey("sat")) { - sat = hue_json["sat"]; - prev_sat = sat; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "sat", sat); - response += buf; - if (LST_RGB <= Light.subtype) { - - if (254 <= sat) { sat = 255; } - g_gotct = false; - change = true; - } - resp = true; - } - if (hue_json.containsKey("ct")) { - ct = hue_json["ct"]; - prev_ct = ct; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "ct", ct); - response += buf; - if ((LST_COLDWARM == Light.subtype) || (LST_RGBW <= Light.subtype)) { - g_gotct = true; - change = true; - } - resp = true; - } - if (change) { -#ifdef USE_SHUTTER - if (ShutterState(device)) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Settings.shutter_invert: %d"), Settings.shutter_options[device-1] & 1); - ShutterSetPosition(device, bri * 100.0f ); - } else -#endif - if (light_type && (local_light_subtype > LST_NONE)) { - if (!Settings.flag3.pwm_multi_channels) { - if (g_gotct) { - light_controller.changeCTB(ct, bri); - } else { - light_controller.changeHSB(hue, sat, bri); - } - LightPreparePower(); - } else { - LightSetBri(device, bri); - } - if (LST_COLDWARM <= local_light_subtype) { - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_COLOR)); - } else { - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_DIMMER)); - } - XdrvRulesProcess(); - } - change = false; - } - response += "]"; - if (2 == response.length()) { - response = FPSTR(HUE_ERROR_JSON); - } - } - else { - response = FPSTR(HUE_ERROR_JSON); - } - free(buf); -} - -void HueLights(String *path) -{ - - - - String response; - int code = 200; - uint8_t device = 1; - uint32_t device_id; - uint8_t maxhue = (devices_present > MAX_HUE_DEVICES) ? MAX_HUE_DEVICES : devices_present; - - path->remove(0,path->indexOf(F("/lights"))); - if (path->endsWith(F("/lights"))) { - response = "{"; - bool appending = false; - CheckHue(&response, appending); -#ifdef USE_ZIGBEE - ZigbeeCheckHue(&response, appending); -#endif -#ifdef USE_SCRIPT_HUE - Script_Check_Hue(&response); -#endif - response += "}"; - } - else if (path->endsWith(F("/state"))) { - path->remove(0,8); - path->remove(path->indexOf(F("/state"))); - device_id = atoi(path->c_str()); - device = DecodeLightId(device_id); -#ifdef USE_ZIGBEE - uint16_t shortaddr; - device = DecodeLightId(device_id, &shortaddr); - if (shortaddr) { - return ZigbeeHandleHue(shortaddr, device_id, response); - } -#endif - -#ifdef USE_SCRIPT_HUE - if (device > devices_present) { - return Script_Handle_Hue(path); - } -#endif - if ((device >= 1) || (device <= maxhue)) { - HueLightsCommand(device, device_id, response); - } - - } - else if(path->indexOf(F("/lights/")) >= 0) { - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("/lights path=%s"), path->c_str()); - path->remove(0,8); - device_id = atoi(path->c_str()); - device = DecodeLightId(device_id); -#ifdef USE_ZIGBEE - uint16_t shortaddr; - device = DecodeLightId(device_id, &shortaddr); - if (shortaddr) { - ZigbeeHueStatus(&response, shortaddr); - goto exit; - } -#endif - -#ifdef USE_SCRIPT_HUE - if (device > devices_present) { - Script_HueStatus(&response, device-devices_present - 1); - goto exit; - } -#endif - - if ((device < 1) || (device > maxhue)) { - device = 1; - } - response += F("{\"state\":"); - HueLightStatus1(device, &response); - HueLightStatus2(device, &response); - } - else { - response = "{}"; - code = 406; - } - exit: - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " Result (%s)"), response.c_str()); - WSSend(code, CT_JSON, response); -} - -void HueGroups(String *path) -{ - - - - String response = "{}"; - uint8_t maxhue = (devices_present > MAX_HUE_DEVICES) ? MAX_HUE_DEVICES : devices_present; - - - if (path->endsWith("/0")) { - response = FPSTR(HUE_GROUP0_STATUS_JSON); - String lights = F("\"1\""); - for (uint32_t i = 2; i <= maxhue; i++) { - lights += ",\""; - lights += EncodeLightId(i); - lights += "\""; - } - -#ifdef USE_ZIGBEE - ZigbeeHueGroups(&response); -#endif - response.replace("{l1", lights); - HueLightStatus1(1, &response); - response += F("}"); - } - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " HueGroups Result (%s)"), path->c_str()); - WSSend(200, CT_JSON, response); -} - -void HandleHueApi(String *path) -{ -# 828 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_20_hue.ino" - uint8_t args = 0; - - path->remove(0, 4); - uint16_t apilen = path->length(); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_API " (%s)"), path->c_str()); - for (args = 0; args < Webserver->args(); args++) { - String json = Webserver->arg(args); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_POST_ARGS " (%s)"), json.c_str()); - } - - if (path->endsWith(F("/invalid/"))) {} - else if (!apilen) HueAuthentication(path); - else if (path->endsWith(F("/"))) HueAuthentication(path); - else if (path->endsWith(F("/config"))) HueConfig(path); - else if (path->indexOf(F("/lights")) >= 0) HueLights(path); - else if (path->indexOf(F("/groups")) >= 0) HueGroups(path); - else if (path->endsWith(F("/schedules"))) HueNotImplemented(path); - else if (path->endsWith(F("/sensors"))) HueNotImplemented(path); - else if (path->endsWith(F("/scenes"))) HueNotImplemented(path); - else if (path->endsWith(F("/rules"))) HueNotImplemented(path); - else if (path->endsWith(F("/resourcelinks"))) HueNotImplemented(path); - else HueGlobalConfig(path); -} - - - - - -bool Xdrv20(uint8_t function) -{ - bool result = false; - -#if defined(USE_SCRIPT_HUE) || defined(USE_ZIGBEE) - if ((EMUL_HUE == Settings.flag2.emulation)) { -#else - if (devices_present && (EMUL_HUE == Settings.flag2.emulation)) { -#endif - switch (function) { - case FUNC_WEB_ADD_HANDLER: - Webserver->on(F("/description.xml"), HandleUpnpSetupHue); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_21_wemo.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_21_wemo.ino" -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined (USE_EMULATION_WEMO) - - - - -#define XDRV_21 21 - -const char WEMO_MSEARCH[] PROGMEM = - "HTTP/1.1 200 OK\r\n" - "CACHE-CONTROL: max-age=86400\r\n" - "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n" - "EXT:\r\n" - "LOCATION: http://%s:80/setup.xml\r\n" - "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" - "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n" - "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" - "ST: %s\r\n" - "USN: uuid:%s::%s\r\n" - "X-User-Agent: redsonic\r\n" - "\r\n"; - -String WemoSerialnumber(void) -{ - char serial[16]; - - snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP_getChipId()); - return String(serial); -} - -String WemoUuid(void) -{ - char uuid[27]; - - snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str()); - return String(uuid); -} - -void WemoRespondToMSearch(int echo_type) -{ - char message[TOPSZ]; - - TickerMSearch.detach(); - if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) { - char type[24]; - if (1 == echo_type) { - strcpy_P(type, URN_BELKIN_DEVICE_CAP); - } else { - strcpy_P(type, UPNP_ROOTDEVICE); - } - char response[400]; - snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type); - PortUdp.write(response); - PortUdp.endPacket(); - snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT)); - } else { - snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); - } - - PrepLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), - echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port); - - udp_response_mutex = false; -} - - - - - -const char WEMO_EVENTSERVICE_XML[] PROGMEM = - "" - "" - "" - "SetBinaryState" - "" - "" - "" - "BinaryState" - "BinaryState" - "in" - "" - "" - "" - "" - "GetBinaryState" - "" - "" - "" - "BinaryState" - "BinaryState" - "out" - "" - "" - "" - "" - "" - "" - "BinaryState" - "bool" - "0" - "" - "" - "level" - "string" - "0" - "" - "" - "\r\n\r\n"; - -const char WEMO_METASERVICE_XML[] PROGMEM = - "" - "" - "1" - "0" - "" - "" - "" - "GetMetaInfo" - "" - "" - "GetMetaInfo" - "MetaInfo" - "in" - "" - "" - "" - "" - "" - "MetaInfo" - "string" - "0" - "" - "" - "\r\n\r\n"; - -const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM = - "" - "" - "" - "%d" - "" - "" - "\r\n"; - -const char WEMO_SETUP_XML[] PROGMEM = - "" - "" - "" - "urn:Belkin:device:controllee:1" - "{x1" - "Belkin International Inc." - "Socket" - "3.1415" - "uuid:{x2" - "{x3" - "0" - "" - "" - "urn:Belkin:service:basicevent:1" - "urn:Belkin:serviceId:basicevent1" - "/upnp/control/basicevent1" - "/upnp/event/basicevent1" - "/eventservice.xml" - "" - "" - "urn:Belkin:service:metainfo:1" - "urn:Belkin:serviceId:metainfo1" - "/upnp/control/metainfo1" - "/upnp/event/metainfo1" - "/metainfoservice.xml" - "" - "" - "" - "\r\n"; - - - -void HandleUpnpEvent(void) -{ - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT)); - - char event[500]; - strlcpy(event, Webserver->arg(0).c_str(), sizeof(event)); - - - - - char state = 'G'; - if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) { - state = 'S'; - uint8_t power = POWER_TOGGLE; - if (strstr_P(event, PSTR("State>10on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); - Webserver->on("/eventservice.xml", HandleUpnpService); - Webserver->on("/metainfoservice.xml", HandleUpnpMetaService); - Webserver->on("/setup.xml", HandleUpnpSetupWemo); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_22_sonoff_ifan.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_22_sonoff_ifan.ino" -#ifdef USE_SONOFF_IFAN - - - - -#define XDRV_22 22 - -const uint8_t MAX_FAN_SPEED = 4; - -const uint8_t kIFan02Speed[MAX_FAN_SPEED] = { 0x00, 0x01, 0x03, 0x05 }; -const uint8_t kIFan03Speed[MAX_FAN_SPEED +2] = { 0x00, 0x01, 0x03, 0x04, 0x05, 0x06 }; -const uint8_t kIFan03Sequence[MAX_FAN_SPEED][MAX_FAN_SPEED] = {{0, 2, 2, 2}, {0, 1, 2, 4}, {1, 1, 2, 5}, {4, 4, 5, 3}}; - -const char kSonoffIfanCommands[] PROGMEM = "|" - D_CMND_FANSPEED; - -void (* const SonoffIfanCommand[])(void) PROGMEM = { - &CmndFanspeed }; - -uint8_t ifan_fanspeed_timer = 0; -uint8_t ifan_fanspeed_goal = 0; -bool ifan_receive_flag = false; -bool ifan_restart_flag = true; - - - -bool IsModuleIfan(void) -{ - return ((SONOFF_IFAN02 == my_module_type) || (SONOFF_IFAN03 == my_module_type)); -} - -uint8_t MaxFanspeed(void) -{ - return MAX_FAN_SPEED; -} - -uint8_t GetFanspeed(void) -{ - if (ifan_fanspeed_timer) { - return ifan_fanspeed_goal; - } else { - - - - - - - uint8_t fanspeed = (uint8_t)(power &0xF) >> 1; - if (fanspeed) { fanspeed = (fanspeed >> 1) +1; } - return fanspeed; - } -} - - - -void SonoffIFanSetFanspeed(uint8_t fanspeed, bool sequence) -{ - ifan_fanspeed_timer = 0; - ifan_fanspeed_goal = fanspeed; - - uint8_t fanspeed_now = GetFanspeed(); - - if (fanspeed == fanspeed_now) { return; } - - uint8_t fans = kIFan02Speed[fanspeed]; - if (SONOFF_IFAN03 == my_module_type) { - if (sequence) { - fanspeed = kIFan03Sequence[fanspeed_now][ifan_fanspeed_goal]; - if (fanspeed != ifan_fanspeed_goal) { - if (0 == fanspeed_now) { - ifan_fanspeed_timer = 20; - } else { - ifan_fanspeed_timer = 2; - } - } - } - fans = kIFan03Speed[fanspeed]; - } - for (uint32_t i = 2; i < 5; i++) { - uint8_t state = (fans &1) + POWER_OFF_NO_STATE; - ExecuteCommandPower(i, state, SRC_IGNORE); - fans >>= 1; - } - -#ifdef USE_DOMOTICZ - if (sequence) { DomoticzUpdateFanState(); } -#endif -} - - - -void SonoffIfanReceived(void) -{ - char svalue[32]; - - uint8_t mode = serial_in_buffer[3]; - uint8_t action = serial_in_buffer[6]; - - if (4 == mode) { - if (action < 4) { - - - - - if (action != GetFanspeed()) { - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_FANSPEED " %d"), action); - ExecuteCommand(svalue, SRC_REMOTE); -#ifdef USE_BUZZER - BuzzerEnabledBeep((action) ? action : 1, (action) ? 1 : 4); -#endif - } - } else { - - ExecuteCommandPower(1, POWER_TOGGLE, SRC_REMOTE); - } - } - if (6 == mode) { - - Settings.flag3.buzzer_enable = !Settings.flag3.buzzer_enable; - } - if (7 == mode) { - -#ifdef USE_BUZZER - BuzzerEnabledBeep(4, 1); -#endif - } - - - - serial_in_buffer[5] = 0; - serial_in_buffer[6] = 0; - for (uint32_t i = 0; i < 7; i++) { - if ((i > 1) && (i < 6)) { serial_in_buffer[6] += serial_in_buffer[i]; } - Serial.write(serial_in_buffer[i]); - } -} - -bool SonoffIfanSerialInput(void) -{ - if (SONOFF_IFAN03 == my_module_type) { - if (0xAA == serial_in_byte) { - serial_in_byte_counter = 0; - ifan_receive_flag = true; - } - if (ifan_receive_flag) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (serial_in_byte_counter == 8) { -# 176 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_22_sonoff_ifan.ino" - AddLogSerial(LOG_LEVEL_DEBUG); - uint8_t crc = 0; - for (uint32_t i = 2; i < 7; i++) { - crc += serial_in_buffer[i]; - } - if (crc == serial_in_buffer[7]) { - SonoffIfanReceived(); - ifan_receive_flag = false; - return true; - } - } - serial_in_byte = 0; - } - return false; - } -} - - - - - -void CmndFanspeed(void) -{ - if (XdrvMailbox.data_len > 0) { - if ('-' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = (int16_t)GetFanspeed() -1; - if (XdrvMailbox.payload < 0) { XdrvMailbox.payload = MAX_FAN_SPEED -1; } - } - else if ('+' == XdrvMailbox.data[0]) { - XdrvMailbox.payload = GetFanspeed() +1; - if (XdrvMailbox.payload > MAX_FAN_SPEED -1) { XdrvMailbox.payload = 0; } - } - } - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_FAN_SPEED)) { - SonoffIFanSetFanspeed(XdrvMailbox.payload, true); - } - ResponseCmndNumber(GetFanspeed()); -} - - - -bool SonoffIfanInit(void) -{ - if (SONOFF_IFAN03 == my_module_type) { - SetSerial(9600, TS_SERIAL_8N1); - } - return false; -} - -void SonoffIfanUpdate(void) -{ - if (SONOFF_IFAN03 == my_module_type) { - if (ifan_fanspeed_timer) { - ifan_fanspeed_timer--; - if (!ifan_fanspeed_timer) { - SonoffIFanSetFanspeed(ifan_fanspeed_goal, false); - } - } - } - - if (ifan_restart_flag && (4 == uptime) && (SONOFF_IFAN02 == my_module_type)) { - ifan_restart_flag = false; - SetDevicePower(1, SRC_RETRY); - SetDevicePower(power, SRC_RETRY); - } -} - - - - - -bool Xdrv22(uint8_t function) -{ - bool result = false; - - if (IsModuleIfan()) { - switch (function) { - case FUNC_EVERY_250_MSECOND: - SonoffIfanUpdate(); - break; - case FUNC_SERIAL: - result = SonoffIfanSerialInput(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kSonoffIfanCommands, SonoffIfanCommand); - break; - case FUNC_MODULE_INIT: - result = SonoffIfanInit(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_0_constants.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_0_constants.ino" -#ifdef USE_ZIGBEE - -#define OCCUPANCY "Occupancy" - -typedef uint64_t Z_IEEEAddress; -typedef uint16_t Z_ShortAddress; - -enum ZnpCommandType { - Z_POLL = 0x00, - Z_SREQ = 0x20, - Z_AREQ = 0x40, - Z_SRSP = 0x60 -}; - -enum ZnpSubsystem { - Z_RPC_Error = 0x00, - Z_SYS = 0x01, - Z_MAC = 0x02, - Z_NWK = 0x03, - Z_AF = 0x04, - Z_ZDO = 0x05, - Z_SAPI = 0x06, - Z_UTIL = 0x07, - Z_DEBUG = 0x08, - Z_APP = 0x09 -}; - - -enum SysCommand { - SYS_RESET = 0x00, - SYS_PING = 0x01, - SYS_VERSION = 0x02, - SYS_SET_EXTADDR = 0x03, - SYS_GET_EXTADDR = 0x04, - SYS_RAM_READ = 0x05, - SYS_RAM_WRITE = 0x06, - SYS_OSAL_NV_ITEM_INIT = 0x07, - SYS_OSAL_NV_READ = 0x08, - SYS_OSAL_NV_WRITE = 0x09, - SYS_OSAL_START_TIMER = 0x0A, - SYS_OSAL_STOP_TIMER = 0x0B, - SYS_RANDOM = 0x0C, - SYS_ADC_READ = 0x0D, - SYS_GPIO = 0x0E, - SYS_STACK_TUNE = 0x0F, - SYS_SET_TIME = 0x10, - SYS_GET_TIME = 0x11, - SYS_OSAL_NV_DELETE = 0x12, - SYS_OSAL_NV_LENGTH = 0x13, - SYS_TEST_RF = 0x40, - SYS_TEST_LOOPBACK = 0x41, - SYS_RESET_IND = 0x80, - SYS_OSAL_TIMER_EXPIRED = 0x81, -}; - -enum SapiCommand { - SAPI_START_REQUEST = 0x00, - SAPI_BIND_DEVICE = 0x01, - SAPI_ALLOW_BIND = 0x02, - SAPI_SEND_DATA_REQUEST = 0x03, - SAPI_READ_CONFIGURATION = 0x04, - SAPI_WRITE_CONFIGURATION = 0x05, - SAPI_GET_DEVICE_INFO = 0x06, - SAPI_FIND_DEVICE_REQUEST = 0x07, - SAPI_PERMIT_JOINING_REQUEST = 0x08, - SAPI_SYSTEM_RESET = 0x09, - SAPI_START_CONFIRM = 0x80, - SAPI_BIND_CONFIRM = 0x81, - SAPI_ALLOW_BIND_CONFIRM = 0x82, - SAPI_SEND_DATA_CONFIRM = 0x83, - SAPI_FIND_DEVICE_CONFIRM = 0x85, - SAPI_RECEIVE_DATA_INDICATION = 0x87, -}; -enum Z_configuration { - CONF_EXTADDR = 0x01, - CONF_BOOTCOUNTER = 0x02, - CONF_STARTUP_OPTION = 0x03, - CONF_START_DELAY = 0x04, - CONF_NIB = 0x21, - CONF_DEVICE_LIST = 0x22, - CONF_ADDRMGR = 0x23, - CONF_POLL_RATE = 0x24, - CONF_QUEUED_POLL_RATE = 0x25, - CONF_RESPONSE_POLL_RATE = 0x26, - CONF_REJOIN_POLL_RATE = 0x27, - CONF_DATA_RETRIES = 0x28, - CONF_POLL_FAILURE_RETRIES = 0x29, - CONF_STACK_PROFILE = 0x2A, - CONF_INDIRECT_MSG_TIMEOUT = 0x2B, - CONF_ROUTE_EXPIRY_TIME = 0x2C, - CONF_EXTENDED_PAN_ID = 0x2D, - CONF_BCAST_RETRIES = 0x2E, - CONF_PASSIVE_ACK_TIMEOUT = 0x2F, - CONF_BCAST_DELIVERY_TIME = 0x30, - CONF_NWK_MODE = 0x31, - CONF_CONCENTRATOR_ENABLE = 0x32, - CONF_CONCENTRATOR_DISCOVERY = 0x33, - CONF_CONCENTRATOR_RADIUS = 0x34, - CONF_CONCENTRATOR_RC = 0x36, - CONF_NWK_MGR_MODE = 0x37, - CONF_SRC_RTG_EXPIRY_TIME = 0x38, - CONF_ROUTE_DISCOVERY_TIME = 0x39, - CONF_NWK_ACTIVE_KEY_INFO = 0x3A, - CONF_NWK_ALTERN_KEY_INFO = 0x3B, - CONF_ROUTER_OFF_ASSOC_CLEANUP = 0x3C, - CONF_NWK_LEAVE_REQ_ALLOWED = 0x3D, - CONF_NWK_CHILD_AGE_ENABLE = 0x3E, - CONF_DEVICE_LIST_KA_TIMEOUT = 0x3F, - CONF_BINDING_TABLE = 0x41, - CONF_GROUP_TABLE = 0x42, - CONF_APS_FRAME_RETRIES = 0x43, - CONF_APS_ACK_WAIT_DURATION = 0x44, - CONF_APS_ACK_WAIT_MULTIPLIER = 0x45, - CONF_BINDING_TIME = 0x46, - CONF_APS_USE_EXT_PANID = 0x47, - CONF_APS_USE_INSECURE_JOIN = 0x48, - CONF_COMMISSIONED_NWK_ADDR = 0x49, - CONF_APS_NONMEMBER_RADIUS = 0x4B, - CONF_APS_LINK_KEY_TABLE = 0x4C, - CONF_APS_DUPREJ_TIMEOUT_INC = 0x4D, - CONF_APS_DUPREJ_TIMEOUT_COUNT = 0x4E, - CONF_APS_DUPREJ_TABLE_SIZE = 0x4F, - CONF_DIAGNOSTIC_STATS = 0x50, - CONF_SECURITY_LEVEL = 0x61, - CONF_PRECFGKEY = 0x62, - CONF_PRECFGKEYS_ENABLE = 0x63, - CONF_SECURITY_MODE = 0x64, - CONF_SECURE_PERMIT_JOIN = 0x65, - CONF_APS_LINK_KEY_TYPE = 0x66, - CONF_APS_ALLOW_R19_SECURITY = 0x67, - CONF_IMPLICIT_CERTIFICATE = 0x69, - CONF_DEVICE_PRIVATE_KEY = 0x6A, - CONF_CA_PUBLIC_KEY = 0x6B, - CONF_KE_MAX_DEVICES = 0x6C, - CONF_USE_DEFAULT_TCLK = 0x6D, - CONF_RNG_COUNTER = 0x6F, - CONF_RANDOM_SEED = 0x70, - CONF_TRUSTCENTER_ADDR = 0x71, - CONF_USERDESC = 0x81, - CONF_NWKKEY = 0x82, - CONF_PANID = 0x83, - CONF_CHANLIST = 0x84, - CONF_LEAVE_CTRL = 0x85, - CONF_SCAN_DURATION = 0x86, - CONF_LOGICAL_TYPE = 0x87, - CONF_NWKMGR_MIN_TX = 0x88, - CONF_NWKMGR_ADDR = 0x89, - CONF_ZDO_DIRECT_CB = 0x8F, - CONF_TCLK_TABLE_START = 0x0101, - ZNP_HAS_CONFIGURED = 0xF00 -}; - - -enum Z_Status { - Z_SUCCESS = 0x00, - Z_FAILURE = 0x01, - Z_INVALIDPARAMETER = 0x02, - Z_MEMERROR = 0x03, - Z_CREATED = 0x09, - Z_BUFFERFULL = 0x11 -}; - -enum Z_App_Profiles { - Z_PROF_IPM = 0x0101, - Z_PROF_HA = 0x0104, - Z_PROF_CBA = 0x0105, - Z_PROF_TA = 0x0107, - Z_PROF_PHHC = 0x0108, - Z_PROF_AMI = 0x0109, -}; - -enum Z_Device_Ids { - Z_DEVID_CONF_TOOL = 0x0005, -# 225 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_0_constants.ino" -}; - - enum Z_AddrMode : uint8_t { - Z_Addr_NotPresent = 0, - Z_Addr_Group = 1, - Z_Addr_ShortAddress = 2, - Z_Addr_IEEEAddress = 3, - Z_Addr_Broadcast = 0xFF -}; - - -enum AfCommand : uint8_t { - AF_REGISTER = 0x00, - AF_DATA_REQUEST = 0x01, - AF_DATA_REQUEST_EXT = 0x02, - AF_DATA_REQUEST_SRC_RTG = 0x03, - AF_INTER_PAN_CTL = 0x10, - AF_DATA_STORE = 0x11, - AF_DATA_RETRIEVE = 0x12, - AF_APSF_CONFIG_SET = 0x13, - AF_DATA_CONFIRM = 0x80, - AF_REFLECT_ERROR = 0x83, - AF_INCOMING_MSG = 0x81, - AF_INCOMING_MSG_EXT = 0x82 -}; - - -enum : uint8_t { - ZDO_NWK_ADDR_REQ = 0x00, - ZDO_IEEE_ADDR_REQ = 0x01, - ZDO_NODE_DESC_REQ = 0x02, - ZDO_POWER_DESC_REQ = 0x03, - ZDO_SIMPLE_DESC_REQ = 0x04, - ZDO_ACTIVE_EP_REQ = 0x05, - ZDO_MATCH_DESC_REQ = 0x06, - ZDO_COMPLEX_DESC_REQ = 0x07, - ZDO_USER_DESC_REQ = 0x08, - ZDO_DEVICE_ANNCE = 0x0A, - ZDO_USER_DESC_SET = 0x0B, - ZDO_SERVER_DISC_REQ = 0x0C, - ZDO_END_DEVICE_BIND_REQ = 0x20, - ZDO_BIND_REQ = 0x21, - ZDO_UNBIND_REQ = 0x22, - ZDO_SET_LINK_KEY = 0x23, - ZDO_REMOVE_LINK_KEY = 0x24, - ZDO_GET_LINK_KEY = 0x25, - ZDO_MGMT_NWK_DISC_REQ = 0x30, - ZDO_MGMT_LQI_REQ = 0x31, - ZDO_MGMT_RTQ_REQ = 0x32, - ZDO_MGMT_BIND_REQ = 0x33, - ZDO_MGMT_LEAVE_REQ = 0x34, - ZDO_MGMT_DIRECT_JOIN_REQ = 0x35, - ZDO_MGMT_PERMIT_JOIN_REQ = 0x36, - ZDO_MGMT_NWK_UPDATE_REQ = 0x37, - ZDO_MSG_CB_REGISTER = 0x3E, - ZDO_MGS_CB_REMOVE = 0x3F, - ZDO_STARTUP_FROM_APP = 0x40, - ZDO_AUTO_FIND_DESTINATION = 0x41, - ZDO_EXT_REMOVE_GROUP = 0x47, - ZDO_EXT_REMOVE_ALL_GROUP = 0x48, - ZDO_EXT_FIND_ALL_GROUPS_ENDPOINT = 0x49, - ZDO_EXT_FIND_GROUP = 0x4A, - ZDO_EXT_ADD_GROUP = 0x4B, - ZDO_EXT_COUNT_ALL_GROUPS = 0x4C, - ZDO_NWK_ADDR_RSP = 0x80, - ZDO_IEEE_ADDR_RSP = 0x81, - ZDO_NODE_DESC_RSP = 0x82, - ZDO_POWER_DESC_RSP = 0x83, - ZDO_SIMPLE_DESC_RSP = 0x84, - ZDO_ACTIVE_EP_RSP = 0x85, - ZDO_MATCH_DESC_RSP = 0x86, - ZDO_COMPLEX_DESC_RSP = 0x87, - ZDO_USER_DESC_RSP = 0x88, - ZDO_USER_DESC_CONF = 0x89, - ZDO_SERVER_DISC_RSP = 0x8A, - ZDO_END_DEVICE_BIND_RSP = 0xA0, - ZDO_BIND_RSP = 0xA1, - ZDO_UNBIND_RSP = 0xA2, - ZDO_MGMT_NWK_DISC_RSP = 0xB0, - ZDO_MGMT_LQI_RSP = 0xB1, - ZDO_MGMT_RTG_RSP = 0xB2, - ZDO_MGMT_BIND_RSP = 0xB3, - ZDO_MGMT_LEAVE_RSP = 0xB4, - ZDO_MGMT_DIRECT_JOIN_RSP = 0xB5, - ZDO_MGMT_PERMIT_JOIN_RSP = 0xB6, - ZDO_STATE_CHANGE_IND = 0xC0, - ZDO_END_DEVICE_ANNCE_IND = 0xC1, - ZDO_MATCH_DESC_RSP_SENT = 0xC2, - ZDO_STATUS_ERROR_RSP = 0xC3, - ZDO_SRC_RTG_IND = 0xC4, - ZDO_LEAVE_IND = 0xC9, - ZDO_TC_DEV_IND = 0xCA, - ZDO_PERMIT_JOIN_IND = 0xCB, - ZDO_MSG_CB_INCOMING = 0xFF -}; - - -enum ZdoStates { - ZDO_DEV_HOLD = 0x00, - ZDO_DEV_INIT = 0x01, - ZDO_DEV_NWK_DISC = 0x02, - ZDO_DEV_NWK_JOINING = 0x03, - ZDO_DEV_NWK_REJOIN = 0x04, - ZDO_DEV_END_DEVICE_UNAUTH = 0x05, - ZDO_DEV_END_DEVICE = 0x06, - ZDO_DEV_ROUTER = 0x07, - ZDO_DEV_COORD_STARTING = 0x08, - ZDO_DEV_ZB_COORD = 0x09, - ZDO_DEV_NWK_ORPHAN = 0x0A, -}; - - -enum Z_Util { - Z_UTIL_GET_DEVICE_INFO = 0x00, - Z_UTIL_GET_NV_INFO = 0x01, - Z_UTIL_SET_PANID = 0x02, - Z_UTIL_SET_CHANNELS = 0x03, - Z_UTIL_SET_SECLEVEL = 0x04, - Z_UTIL_SET_PRECFGKEY = 0x05, - Z_UTIL_CALLBACK_SUB_CMD = 0x06, - Z_UTIL_KEY_EVENT = 0x07, - Z_UTIL_TIME_ALIVE = 0x09, - Z_UTIL_LED_CONTROL = 0x0A, - Z_UTIL_TEST_LOOPBACK = 0x10, - Z_UTIL_DATA_REQ = 0x11, - Z_UTIL_SRC_MATCH_ENABLE = 0x20, - Z_UTIL_SRC_MATCH_ADD_ENTRY = 0x21, - Z_UTIL_SRC_MATCH_DEL_ENTRY = 0x22, - Z_UTIL_SRC_MATCH_CHECK_SRC_ADDR = 0x23, - Z_UTIL_SRC_MATCH_ACK_ALL_PENDING = 0x24, - Z_UTIL_SRC_MATCH_CHECK_ALL_PENDING = 0x25, - Z_UTIL_ADDRMGR_EXT_ADDR_LOOKUP = 0x40, - Z_UTIL_ADDRMGR_NWK_ADDR_LOOKUP = 0x41, - Z_UTIL_APSME_LINK_KEY_DATA_GET = 0x44, - Z_UTIL_APSME_LINK_KEY_NV_ID_GET = 0x45, - Z_UTIL_ASSOC_COUNT = 0x48, - Z_UTIL_ASSOC_FIND_DEVICE = 0x49, - Z_UTIL_ASSOC_GET_WITH_ADDRESS = 0x4A, - Z_UTIL_APSME_REQUEST_KEY_CMD = 0x4B, - Z_UTIL_ZCL_KEY_EST_INIT_EST = 0x80, - Z_UTIL_ZCL_KEY_EST_SIGN = 0x81, - Z_UTIL_UTIL_SYNC_REQ = 0xE0, - Z_UTIL_ZCL_KEY_ESTABLISH_IND = 0xE1 -}; - -enum ZCL_Global_Commands { - ZCL_READ_ATTRIBUTES = 0x00, - ZCL_READ_ATTRIBUTES_RESPONSE = 0x01, - ZCL_WRITE_ATTRIBUTES = 0x02, - ZCL_WRITE_ATTRIBUTES_UNDIVIDED = 0x03, - ZCL_WRITE_ATTRIBUTES_RESPONSE = 0x04, - ZCL_WRITE_ATTRIBUTES_NORESPONSE = 0x05, - ZCL_CONFIGURE_REPORTING = 0x06, - ZCL_CONFIGURE_REPORTING_RESPONSE = 0x07, - ZCL_READ_REPORTING_CONFIGURATION = 0x08, - ZCL_READ_REPORTING_CONFIGURATION_RESPONSE = 0x09, - ZCL_REPORT_ATTRIBUTES = 0x0a, - ZCL_DEFAULT_RESPONSE = 0x0b, - ZCL_DISCOVER_ATTRIBUTES = 0x0c, - ZCL_DISCOVER_ATTRIBUTES_RESPONSE = 0x0d - -}; - -#define ZF(s) static const char ZS_ ## s[] PROGMEM = #s; -#define Z(s) ZS_ ## s - -typedef struct Z_StatusLine { - uint32_t status; - const char * status_msg; -} Z_StatusLine; - - -String getZigbeeStatusMessage(uint8_t status) { - static const char StatusMsg[] PROGMEM = "SUCCESS|FAILURE|NOT_AUTHORIZED|RESERVED_FIELD_NOT_ZERO|MALFORMED_COMMAND|UNSUP_CLUSTER_COMMAND|UNSUP_GENERAL_COMMAND" - "|UNSUP_MANUF_CLUSTER_COMMAND|UNSUP_MANUF_GENERAL_COMMAND|INVALID_FIELD|UNSUPPORTED_ATTRIBUTE|INVALID_VALE|READ_ONLY" - "|INSUFFICIENT_SPACE|DUPLICATE_EXISTS|NOT_FOUND|UNREPORTABLE_ATTRIBUTE|INVALID_DATA_TYPE|INVALID_SELECTOR|WRITE_ONLY" - "|INCONSISTENT_STARTUP_STATE|DEFINED_OUT_OF_BAND|INCONSISTENT|ACTION_DENIED|TIMEOUT|ABORT|INVALID_IMAGE|WAIT_FOR_DATA" - "|NO_IMAGE_AVAILABLE|REQUIRE_MORE_IMAGE|NOTIFICATION_PENDING|HARDWARE_FAILURE|SOFTWARE_FAILURE|CALIBRATION_ERROR|UNSUPPORTED_CLUSTER|NO_ROUTE" - "|CHANNEL_ACCESS_FAILURE|NO_ACK|NO_APP_ACK|NO_ROUTE" - ; - static const uint8_t StatusIdx[] PROGMEM = { 0x00, 0x01, 0x7E, 0x7F, 0x80, 0x81, 0x82, - 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9A, 0xC0, 0xC1, 0xC2, 0xC3, 0xCD, - 0xE1, 0xE9, 0xA7, 0xD0}; - - char msg[32]; - int32_t idx = -1; - for (uint32_t i = 0; i < sizeof(StatusIdx); i++) { - if (status == pgm_read_byte(&StatusIdx[i])) { - idx = i; - break; - } - } - if (idx >= 0) { - GetTextIndexed(msg, sizeof(msg), idx, StatusMsg); - } else { - *msg = 0x00; - } - return String(msg); -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_1_headers.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_1_headers.ino" -#ifdef USE_ZIGBEE - - - -void ZigbeeZCLSend_Raw(uint16_t dtsAddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId); - - - -const JsonVariant &getCaseInsensitive(const JsonObject &json, const char *needle) { - - if ((nullptr == &json) || (nullptr == needle) || (0 == pgm_read_byte(needle))) { - return *(JsonVariant*)nullptr; - } - - for (JsonObject::const_iterator it=json.begin(); it!=json.end(); ++it) { - const char *key = it->key; - const JsonVariant &value = it->value; - - if (0 == strcasecmp_P(key, needle)) { - return value; - } - } - - return *(JsonVariant*)nullptr; -} - - -const char * getCaseInsensitiveConstCharNull(const JsonObject &json, const char *needle) { - const JsonVariant &val = getCaseInsensitive(json, needle); - if (&val) { - const char *val_cs = val.as(); - if (strlen(val_cs)) { - return val_cs; - } - } - return nullptr; -} - - -JsonVariant &startsWithCaseInsensitive(const JsonObject &json, const char *needle) { - - if ((nullptr == &json) || (nullptr == needle) || (0 == pgm_read_byte(needle))) { - return *(JsonVariant*)nullptr; - } - - String needle_s(needle); - needle_s.toLowerCase(); - - for (auto kv : json) { - String key_s(kv.key); - key_s.toLowerCase(); - JsonVariant &value = kv.value; - - if (key_s.startsWith(needle_s)) { - return value; - } - } - - return *(JsonVariant*)nullptr; -} - - -uint32_t parseHex(const char **data, size_t max_len = 8) { - uint32_t ret = 0; - for (uint32_t i = 0; i < max_len; i++) { - int8_t v = hexValue(**data); - if (v < 0) { break; } - ret = (ret << 4) | v; - *data += 1; - } - return ret; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -#ifdef USE_ZIGBEE - -#include - -#ifndef ZIGBEE_SAVE_DELAY_SECONDS -#define ZIGBEE_SAVE_DELAY_SECONDS 2; -#endif -const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; - - - - - -const size_t endpoints_max = 8; - -typedef struct Z_Device { - uint64_t longaddr; - char * manufacturerId; - char * modelId; - char * friendlyName; - uint8_t endpoints[endpoints_max]; - - DynamicJsonBuffer *json_buffer; - JsonObject *json; - - uint16_t shortaddr; - uint8_t seqNumber; - - int8_t bulbtype; - uint8_t power; - uint8_t colormode; - uint8_t dimmer; - uint8_t sat; - uint16_t ct; - uint16_t hue; - uint16_t x, y; -} Z_Device; - - - - - -typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value); - - -typedef enum Z_Def_Category { - Z_CAT_NONE = 0, - Z_CAT_READ_ATTR, - Z_CAT_VIRTUAL_OCCUPANCY, - Z_CAT_REACHABILITY, - Z_CAT_READ_0006, - Z_CAT_READ_0008, - Z_CAT_READ_0102, - Z_CAT_READ_0300, -} Z_Def_Category; - -const uint32_t Z_CAT_REACHABILITY_TIMEOUT = 1000; - -typedef struct Z_Deferred { - - uint32_t timer; - uint16_t shortaddr; - uint16_t groupaddr; - uint16_t cluster; - uint8_t endpoint; - uint8_t category; - uint32_t value; - Z_DeviceTimer func; -} Z_Deferred; -# 99 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -class Z_Devices { -public: - Z_Devices() {}; - - - - - - - uint16_t isKnownShortAddr(uint16_t shortaddr) const; - uint16_t isKnownLongAddr(uint64_t longaddr) const; - uint16_t isKnownIndex(uint32_t index) const; - uint16_t isKnownFriendlyName(const char * name) const; - - uint64_t getDeviceLongAddr(uint16_t shortaddr) const; - - uint8_t findFirstEndpoint(uint16_t shortaddr) const; - - - - void updateDevice(uint16_t shortaddr, uint64_t longaddr = 0); - - - void addEndpoint(uint16_t shortaddr, uint8_t endpoint); - void clearEndpoints(uint16_t shortaddr); - - void setManufId(uint16_t shortaddr, const char * str); - void setModelId(uint16_t shortaddr, const char * str); - void setFriendlyName(uint16_t shortaddr, const char * str); - const char * getFriendlyName(uint16_t shortaddr) const; - const char * getModelId(uint16_t shortaddr) const; - void setReachable(uint16_t shortaddr, bool reachable); - - - uint8_t getNextSeqNumber(uint16_t shortaddr); - - - String dumpLightState(uint16_t shortaddr) const; - String dump(uint32_t dump_mode, uint16_t status_shortaddr = 0) const; - int32_t deviceRestore(const JsonObject &json); - - - void setHueBulbtype(uint16_t shortaddr, int8_t bulbtype); - int8_t getHueBulbtype(uint16_t shortaddr) const ; - void updateHueState(uint16_t shortaddr, - const bool *power, const uint8_t *colormode, - const uint8_t *dimmer, const uint8_t *sat, - const uint16_t *ct, const uint16_t *hue, - const uint16_t *x, const uint16_t *y, - const bool *reachable); - bool getHueState(uint16_t shortaddr, - bool *power, uint8_t *colormode, - uint8_t *dimmer, uint8_t *sat, - uint16_t *ct, uint16_t *hue, - uint16_t *x, uint16_t *y, - bool *reachable) const ; - - - void resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category); - void setTimer(uint16_t shortaddr, uint16_t groupaddr, uint32_t wait_ms, uint16_t cluster, uint8_t endpoint, uint8_t category, uint32_t value, Z_DeviceTimer func); - void runTimer(void); - - - void jsonClear(uint16_t shortaddr); - void jsonAppend(uint16_t shortaddr, const JsonObject &values); - const JsonObject *jsonGet(uint16_t shortaddr); - void jsonPublishFlush(uint16_t shortaddr); - bool jsonIsConflict(uint16_t shortaddr, const JsonObject &values); - void jsonPublishNow(uint16_t shortaddr, JsonObject &values); - - - size_t devicesSize(void) const { - return _devices.size(); - } - const Z_Device &devicesAt(size_t i) const { - return *(_devices.at(i)); - } - - - bool removeDevice(uint16_t shortaddr); - - - void dirty(void); - void clean(void); - void shrinkToFit(uint16_t shortaddr); - - - uint16_t parseDeviceParam(const char * param, bool short_must_be_known = false) const; - -private: - std::vector _devices = {}; - std::vector _deferred = {}; - uint32_t _saveTimer = 0; - uint8_t _seqNumber = 0; - - template < typename T> - static bool findInVector(const std::vector & vecOfElements, const T & element); - - template < typename T> - static int32_t findEndpointInVector(const std::vector & vecOfElements, uint8_t element); - - Z_Device & getShortAddr(uint16_t shortaddr); - const Z_Device & getShortAddrConst(uint16_t shortaddr) const ; - Z_Device & getLongAddr(uint64_t longaddr); - - int32_t findShortAddr(uint16_t shortaddr) const; - int32_t findLongAddr(uint64_t longaddr) const; - int32_t findFriendlyName(const char * name) const; - - - Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0); - void freeDeviceEntry(Z_Device *device); - - void setStringAttribute(char*& attr, const char * str); -}; - - - - -Z_Devices zigbee_devices = Z_Devices(); - - -uint64_t localIEEEAddr = 0; - - - - - - -template < typename T> -bool Z_Devices::findInVector(const std::vector & vecOfElements, const T & element) { - - auto it = std::find(vecOfElements.begin(), vecOfElements.end(), element); - - if (it != vecOfElements.end()) { - return true; - } else { - return false; - } -} - -template < typename T> -int32_t Z_Devices::findEndpointInVector(const std::vector & vecOfElements, uint8_t element) { - - - int32_t found = 0; - for (auto &elem : vecOfElements) { - if (elem == element) { return found; } - found++; - } - - return -1; -} - - - - - -Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) { - if (!shortaddr && !longaddr) { return *(Z_Device*) nullptr; } - - Z_Device* device_alloc = new Z_Device{ - longaddr, - nullptr, - nullptr, - nullptr, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - nullptr, nullptr, - shortaddr, - 0, - - -1, - 0x80, - 0, - 0, - 0, - 200, - 0, - 0, 0, - }; - - device_alloc->json_buffer = new DynamicJsonBuffer(16); - _devices.push_back(device_alloc); - dirty(); - return *(_devices.back()); -} - -void Z_Devices::freeDeviceEntry(Z_Device *device) { - if (device->manufacturerId) { free(device->manufacturerId); } - if (device->modelId) { free(device->modelId); } - if (device->friendlyName) { free(device->friendlyName); } - free(device); -} -# 301 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const { - if (!shortaddr) { return -1; } - int32_t found = 0; - if (shortaddr) { - for (auto &elem : _devices) { - if (elem->shortaddr == shortaddr) { return found; } - found++; - } - } - return -1; -} -# 320 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -int32_t Z_Devices::findLongAddr(uint64_t longaddr) const { - if (!longaddr) { return -1; } - int32_t found = 0; - if (longaddr) { - for (auto &elem : _devices) { - if (elem->longaddr == longaddr) { return found; } - found++; - } - } - return -1; -} -# 339 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -int32_t Z_Devices::findFriendlyName(const char * name) const { - if (!name) { return -1; } - size_t name_len = strlen(name); - int32_t found = 0; - if (name_len) { - for (auto &elem : _devices) { - if (elem->friendlyName) { - if (strcmp(elem->friendlyName, name) == 0) { return found; } - } - found++; - } - } - return -1; -} - - -uint16_t Z_Devices::isKnownShortAddr(uint16_t shortaddr) const { - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - return shortaddr; - } else { - return 0; - } -} - -uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const { - int32_t found = findLongAddr(longaddr); - if (found >= 0) { - const Z_Device & device = devicesAt(found); - return device.shortaddr; - } else { - return 0; - } -} - -uint16_t Z_Devices::isKnownIndex(uint32_t index) const { - if (index < devicesSize()) { - const Z_Device & device = devicesAt(index); - return device.shortaddr; - } else { - return 0; - } -} - -uint16_t Z_Devices::isKnownFriendlyName(const char * name) const { - if ((!name) || (0 == strlen(name))) { return 0xFFFF; } - int32_t found = findFriendlyName(name); - if (found >= 0) { - const Z_Device & device = devicesAt(found); - return device.shortaddr; - } else { - return 0; - } -} - -uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const { - const Z_Device & device = getShortAddrConst(shortaddr); - return device.longaddr; -} - - - - -Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) { - if (!shortaddr) { return *(Z_Device*) nullptr; } - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - return *(_devices[found]); - } - - return createDeviceEntry(shortaddr, 0); -} - -const Z_Device & Z_Devices::getShortAddrConst(uint16_t shortaddr) const { - if (!shortaddr) { return *(Z_Device*) nullptr; } - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - return *(_devices[found]); - } - return *((Z_Device*)nullptr); -} - - -Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) { - if (!longaddr) { return *(Z_Device*) nullptr; } - int32_t found = findLongAddr(longaddr); - if (found > 0) { - return *(_devices[found]); - } - return createDeviceEntry(0, longaddr); -} - - -bool Z_Devices::removeDevice(uint16_t shortaddr) { - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - freeDeviceEntry(_devices.at(found)); - _devices.erase(_devices.begin() + found); - dirty(); - return true; - } - return false; -} - - - - - - -void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) { - int32_t s_found = findShortAddr(shortaddr); - int32_t l_found = findLongAddr(longaddr); - - if ((s_found >= 0) && (l_found >= 0)) { - if (s_found == l_found) { - } else { - - _devices[l_found]->shortaddr = shortaddr; - - freeDeviceEntry(_devices.at(s_found)); - _devices.erase(_devices.begin() + s_found); - dirty(); - } - } else if (s_found >= 0) { - - - _devices[s_found]->longaddr = longaddr; - dirty(); - } else if (l_found >= 0) { - - _devices[l_found]->shortaddr = shortaddr; - dirty(); - } else { - - if (shortaddr || longaddr) { - createDeviceEntry(shortaddr, longaddr); - } - } -} - - - - -void Z_Devices::clearEndpoints(uint16_t shortaddr) { - if (!shortaddr) { return; } - Z_Device &device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - - for (uint32_t i = 0; i < endpoints_max; i++) { - device.endpoints[i] = 0; - - } -} - - - - -void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) { - if (!shortaddr) { return; } - if (0x00 == endpoint) { return; } - Z_Device &device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - - for (uint32_t i = 0; i < endpoints_max; i++) { - if (endpoint == device.endpoints[i]) { - return; - } - if (0 == device.endpoints[i]) { - device.endpoints[i] = endpoint; - dirty(); - return; - } - } -} - - -uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const { - int32_t found = findShortAddr(shortaddr); - if (found < 0) return 0; - const Z_Device &device = devicesAt(found); - - return device.endpoints[0]; -} - -void Z_Devices::setStringAttribute(char*& attr, const char * str) { - size_t str_len = str ? strlen(str) : 0; - - if ((nullptr == attr) && (0 == str_len)) { return; } - if (attr) { - - if (strcmp(attr, str) != 0) { - - free(attr); - attr = nullptr; - } else { - return; - } - } - if (str_len) { - attr = (char*) malloc(str_len + 1); - strlcpy(attr, str, str_len + 1); - } - dirty(); -} -# 553 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -void Z_Devices::setManufId(uint16_t shortaddr, const char * str) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - - setStringAttribute(device.manufacturerId, str); -} - -void Z_Devices::setModelId(uint16_t shortaddr, const char * str) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - - setStringAttribute(device.modelId, str); -} - -void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - - setStringAttribute(device.friendlyName, str); -} - -const char * Z_Devices::getFriendlyName(uint16_t shortaddr) const { - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - const Z_Device & device = devicesAt(found); - return device.friendlyName; - } - return nullptr; -} - -const char * Z_Devices::getModelId(uint16_t shortaddr) const { - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - const Z_Device & device = devicesAt(found); - return device.modelId; - } - return nullptr; -} - -void Z_Devices::setReachable(uint16_t shortaddr, bool reachable) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - bitWrite(device.power, 7, reachable); -} - - -uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) { - int32_t short_found = findShortAddr(shortaddr); - if (short_found >= 0) { - Z_Device &device = getShortAddr(shortaddr); - device.seqNumber += 1; - return device.seqNumber; - } else { - _seqNumber += 1; - return _seqNumber; - } -} - - - -void Z_Devices::setHueBulbtype(uint16_t shortaddr, int8_t bulbtype) { - Z_Device &device = getShortAddr(shortaddr); - if (bulbtype != device.bulbtype) { - device.bulbtype = bulbtype; - dirty(); - } -} -int8_t Z_Devices::getHueBulbtype(uint16_t shortaddr) const { - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - return _devices[found]->bulbtype; - } else { - return -1; - } -} - - -void Z_Devices::updateHueState(uint16_t shortaddr, - const bool *power, const uint8_t *colormode, - const uint8_t *dimmer, const uint8_t *sat, - const uint16_t *ct, const uint16_t *hue, - const uint16_t *x, const uint16_t *y, - const bool *reachable) { - Z_Device &device = getShortAddr(shortaddr); - if (power) { bitWrite(device.power, 0, *power); } - if (colormode){ device.colormode = *colormode; } - if (dimmer) { device.dimmer = *dimmer; } - if (sat) { device.sat = *sat; } - if (ct) { device.ct = *ct; } - if (hue) { device.hue = *hue; } - if (x) { device.x = *x; } - if (y) { device.y = *y; } - if (reachable){ bitWrite(device.power, 7, *reachable); } -} - - -bool Z_Devices::getHueState(uint16_t shortaddr, - bool *power, uint8_t *colormode, - uint8_t *dimmer, uint8_t *sat, - uint16_t *ct, uint16_t *hue, - uint16_t *x, uint16_t *y, - bool *reachable) const { - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - const Z_Device &device = *(_devices[found]); - if (power) { *power = bitRead(device.power, 0); } - if (colormode){ *colormode = device.colormode; } - if (dimmer) { *dimmer = device.dimmer; } - if (sat) { *sat = device.sat; } - if (ct) { *ct = device.ct; } - if (hue) { *hue = device.hue; } - if (x) { *x = device.x; } - if (y) { *y = device.y; } - if (reachable){ *reachable = bitRead(device.power, 7); } - return true; - } else { - return false; - } -} - - - -void Z_Devices::resetTimersForDevice(uint16_t shortaddr, uint16_t groupaddr, uint8_t category) { - - for (auto it = _deferred.begin(); it != _deferred.end(); it++) { - - - - if ((it->shortaddr == shortaddr) && (it->groupaddr == groupaddr)) { - if ((0xFF == category) || (it->category == category)) { - _deferred.erase(it--); - } - } - } -} - - -void Z_Devices::setTimer(uint16_t shortaddr, uint16_t groupaddr, uint32_t wait_ms, uint16_t cluster, uint8_t endpoint, uint8_t category, uint32_t value, Z_DeviceTimer func) { - - if (category) { - resetTimersForDevice(shortaddr, groupaddr, category); - } - - - Z_Deferred deferred = { wait_ms + millis(), - shortaddr, - groupaddr, - cluster, - endpoint, - category, - value, - func }; - _deferred.push_back(deferred); -} - - - -void Z_Devices::runTimer(void) { - - for (auto it = _deferred.begin(); it != _deferred.end(); it++) { - Z_Deferred &defer = *it; - - uint32_t timer = defer.timer; - if (TimeReached(timer)) { - (*defer.func)(defer.shortaddr, defer.groupaddr, defer.cluster, defer.endpoint, defer.value); - _deferred.erase(it--); - } - } - - - if ((_saveTimer) && TimeReached(_saveTimer)) { - saveZigbeeDevices(); - _saveTimer = 0; - } -} - - -void Z_Devices::jsonClear(uint16_t shortaddr) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - - device.json = nullptr; - device.json_buffer->clear(); -} - - -void CopyJsonVariant(JsonObject &to, const String &key, const JsonVariant &val) { - - to.remove(key); - - if (val.is()) { - String sval = val.as(); - to.set(key, sval); - } else if (val.is()) { - JsonArray &nested_arr = to.createNestedArray(key); - CopyJsonArray(nested_arr, val.as()); - } else if (val.is()) { - JsonObject &nested_obj = to.createNestedObject(key); - CopyJsonObject(nested_obj, val.as()); - } else { - to.set(key, val); - } -} - - -void CopyJsonArray(JsonArray &to, const JsonArray &arr) { - for (auto v : arr) { - if (v.is()) { - String sval = v.as(); - to.add(sval); - } else if (v.is()) { - } else if (v.is()) { - } else { - to.add(v); - } - } -} - - -void CopyJsonObject(JsonObject &to, const JsonObject &from) { - for (auto kv : from) { - String key_string = kv.key; - JsonVariant &val = kv.value; - - CopyJsonVariant(to, key_string, val); - } -} - - - - -bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return false; } - if (&values == nullptr) { return false; } - - if (nullptr == device.json) { - return false; - } -# 800 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" - uint16_t group1 = device.json->get(D_CMND_ZIGBEE_GROUP); - uint16_t group2 = values.get(D_CMND_ZIGBEE_GROUP); - if (group1 != group2) { - return true; - } - - - for (auto kv : values) { - String key_string = kv.key; - - if (0 == strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_GROUP))) { - - } else if (0 == strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_ENDPOINT))) { - - if (device.json->containsKey(kv.key)) { - if (kv.value.as() != device.json->get(kv.key)) { - return true; - } - } - } else if (strcasecmp_P(kv.key, PSTR(D_CMND_ZIGBEE_LINKQUALITY))) { - if (device.json->containsKey(kv.key)) { - return true; - } - } - } - return false; -} - -void Z_Devices::jsonAppend(uint16_t shortaddr, const JsonObject &values) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - if (&values == nullptr) { return; } - - if (nullptr == device.json) { - device.json = &(device.json_buffer->createObject()); - } - - char sa[8]; - snprintf_P(sa, sizeof(sa), PSTR("0x%04X"), shortaddr); - device.json->set(F(D_JSON_ZIGBEE_DEVICE), sa); - - const char * fname = zigbee_devices.getFriendlyName(shortaddr); - if (fname) { - device.json->set(F(D_JSON_ZIGBEE_NAME), (char*) fname); - } - - - CopyJsonObject(*device.json, values); -} - -const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return nullptr; } - return device.json; -} - -void Z_Devices::jsonPublishFlush(uint16_t shortaddr) { - Z_Device & device = getShortAddr(shortaddr); - if (&device == nullptr) { return; } - JsonObject * json = device.json; - if (json == nullptr) { return; } - - const char * fname = zigbee_devices.getFriendlyName(shortaddr); - bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); - - - if (use_fname) { - json->remove(F(D_JSON_ZIGBEE_NAME)); - } else { - json->remove(F(D_JSON_ZIGBEE_DEVICE)); - } - - String msg = ""; - json->printTo(msg); - zigbee_devices.jsonClear(shortaddr); - - if (use_fname) { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":{\"%s\":%s}}"), fname, msg.c_str()); - } else { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str()); - } - if (Settings.flag4.zigbee_distinct_topics) { - char subtopic[16]; - snprintf_P(subtopic, sizeof(subtopic), PSTR("%04X/" D_RSLT_SENSOR), shortaddr); - MqttPublishPrefixTopic_P(TELE, subtopic, Settings.flag.mqtt_sensor_retain); - } else { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - } - XdrvRulesProcess(); -} - -void Z_Devices::jsonPublishNow(uint16_t shortaddr, JsonObject & values) { - jsonPublishFlush(shortaddr); - jsonAppend(shortaddr, values); - jsonPublishFlush(shortaddr); -} - -void Z_Devices::dirty(void) { - _saveTimer = kZigbeeSaveDelaySeconds * 1000 + millis(); -} -void Z_Devices::clean(void) { - _saveTimer = 0; -} - - - - - - -uint16_t Z_Devices::parseDeviceParam(const char * param, bool short_must_be_known) const { - if (nullptr == param) { return 0; } - size_t param_len = strlen(param); - char dataBuf[param_len + 1]; - strcpy(dataBuf, param); - RemoveSpace(dataBuf); - uint16_t shortaddr = 0; - - if (strlen(dataBuf) < 4) { - - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 99)) { - shortaddr = zigbee_devices.isKnownIndex(XdrvMailbox.payload - 1); - } - } else if ((dataBuf[0] == '0') && (dataBuf[1] == 'x')) { - - if (strlen(dataBuf) < 18) { - - shortaddr = strtoull(dataBuf, nullptr, 0); - if (short_must_be_known) { - shortaddr = zigbee_devices.isKnownShortAddr(shortaddr); - } - - } else { - - uint64_t longaddr = strtoull(dataBuf, nullptr, 0); - shortaddr = zigbee_devices.isKnownLongAddr(longaddr); - } - } else { - - shortaddr = zigbee_devices.isKnownFriendlyName(dataBuf); - } - - return shortaddr; -} - - -String Z_Devices::dumpLightState(uint16_t shortaddr) const { - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - char hex[8]; - - int32_t found = findShortAddr(shortaddr); - if (found >= 0) { - const Z_Device & device = devicesAt(found); - const char * fname = getFriendlyName(shortaddr); - - bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); - - snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr); - - JsonObject& dev = use_fname ? json.createNestedObject((char*) fname) - : json.createNestedObject(hex); - if (use_fname) { - dev[F(D_JSON_ZIGBEE_DEVICE)] = hex; - } else if (fname) { - dev[F(D_JSON_ZIGBEE_NAME)] = (char*) fname; - } - - - dev[F(D_JSON_ZIGBEE_LIGHT)] = device.bulbtype; - if (0 <= device.bulbtype) { - - dev[F("Power")] = bitRead(device.power, 0); - dev[F("Reachable")] = bitRead(device.power, 7); - if (1 <= device.bulbtype) { - dev[F("Dimmer")] = device.dimmer; - } - if (2 <= device.bulbtype) { - dev[F("Colormode")] = device.colormode; - } - if ((2 == device.bulbtype) || (5 == device.bulbtype)) { - dev[F("CT")] = device.ct; - } - if (3 <= device.bulbtype) { - dev[F("Sat")] = device.sat; - dev[F("Hue")] = device.hue; - dev[F("X")] = device.x; - dev[F("Y")] = device.y; - } - } - } - - String payload = ""; - payload.reserve(200); - json.printTo(payload); - return payload; -} - - - - - -String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const { - DynamicJsonBuffer jsonBuffer; - JsonArray& json = jsonBuffer.createArray(); - JsonArray& devices = json; - - for (std::vector::const_iterator it = _devices.begin(); it != _devices.end(); ++it) { - const Z_Device &device = **it; - uint16_t shortaddr = device.shortaddr; - char hex[22]; - - - if ((status_shortaddr) && (status_shortaddr != shortaddr)) { continue; } - - JsonObject& dev = devices.createNestedObject(); - - snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr); - dev[F(D_JSON_ZIGBEE_DEVICE)] = hex; - - if (device.friendlyName > 0) { - dev[F(D_JSON_ZIGBEE_NAME)] = (char*) device.friendlyName; - } - - if (2 <= dump_mode) { - hex[0] = '0'; - hex[1] = 'x'; - Uint64toHex(device.longaddr, &hex[2], 64); - dev[F("IEEEAddr")] = hex; - if (device.modelId) { - dev[F(D_JSON_MODEL D_JSON_ID)] = device.modelId; - } - if (device.bulbtype >= 0) { - dev[F(D_JSON_ZIGBEE_LIGHT)] = device.bulbtype; - } - if (device.manufacturerId) { - dev[F("Manufacturer")] = device.manufacturerId; - } - JsonArray& dev_endpoints = dev.createNestedArray(F("Endpoints")); - for (uint32_t i = 0; i < endpoints_max; i++) { - uint8_t endpoint = device.endpoints[i]; - if (0x00 == endpoint) { break; } - - snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint); - dev_endpoints.add(hex); - } - } - } - String payload = ""; - payload.reserve(200); - json.printTo(payload); - return payload; -} -# 1062 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_2_devices.ino" -int32_t Z_Devices::deviceRestore(const JsonObject &json) { - - - uint16_t device = 0x0000; - uint64_t ieeeaddr = 0x0000000000000000LL; - const char * modelid = nullptr; - const char * manufid = nullptr; - const char * friendlyname = nullptr; - int8_t bulbtype = 0xFF; - size_t endpoints_len = 0; - - - const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); - if (nullptr != &val_device) { - device = strToUInt(val_device); - } else { - return -1; - } - - - const JsonVariant &val_ieeeaddr = getCaseInsensitive(json, PSTR("IEEEAddr")); - if (nullptr != &val_ieeeaddr) { - ieeeaddr = strtoull(val_ieeeaddr.as(), nullptr, 0); - } - - - friendlyname = getCaseInsensitiveConstCharNull(json, PSTR("Name")); - - - modelid = getCaseInsensitiveConstCharNull(json, PSTR("ModelId")); - - - manufid = getCaseInsensitiveConstCharNull(json, PSTR("Manufacturer")); - - - const JsonVariant &val_bulbtype = getCaseInsensitive(json, PSTR(D_JSON_ZIGBEE_LIGHT)); - if (nullptr != &val_bulbtype) { bulbtype = strToUInt(val_bulbtype);; } - - - updateDevice(device, ieeeaddr); - if (modelid) { setModelId(device, modelid); } - if (manufid) { setManufId(device, manufid); } - if (friendlyname) { setFriendlyName(device, friendlyname); } - if (&val_bulbtype) { setHueBulbtype(device, bulbtype); } - - - const JsonVariant &val_endpoints = getCaseInsensitive(json, PSTR("Endpoints")); - if ((nullptr != &val_endpoints) && (val_endpoints.is())) { - const JsonArray &arr_ep = val_endpoints.as(); - endpoints_len = arr_ep.size(); - clearEndpoints(device); - if (endpoints_len) { - for (auto ep_elt : arr_ep) { - uint8_t ep = strToUInt(ep_elt); - if (ep) { - addEndpoint(device, ep); - } - } - } - } - - return 0; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_3_hue.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_3_hue.ino" -#ifdef USE_ZIGBEE -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) - - - - -void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, String *response) { - static const char HUE_LIGHTS_STATUS_JSON1_SUFFIX_ZIGBEE[] PROGMEM = - "%s\"alert\":\"none\"," - "\"effect\":\"none\"," - "\"reachable\":%s}"; - - bool power, reachable; - uint8_t colormode, bri, sat; - uint16_t ct, hue; - uint16_t x, y; - String light_status = ""; - uint32_t echo_gen = findEchoGeneration(); - - zigbee_devices.getHueState(shortaddr, &power, &colormode, &bri, &sat, &ct, &hue, &x, &y, &reachable); - - if (bri > 254) bri = 254; - if (bri < 1) bri = 1; - if (sat > 254) sat = 254; - uint16_t hue16 = changeUIntScale(hue, 0, 360, 0, 65535); - - const size_t buf_size = 256; - char * buf = (char*) malloc(buf_size); - - snprintf_P(buf, buf_size, PSTR("{\"on\":%s,"), power ? "true" : "false"); - - if ((1 == echo_gen) || (LST_SINGLE <= local_light_subtype)) { - snprintf_P(buf, buf_size, PSTR("%s\"bri\":%d,"), buf, bri); - } - if (LST_COLDWARM <= local_light_subtype) { - snprintf_P(buf, buf_size, PSTR("%s\"colormode\":\"%s\","), buf, (0 == colormode) ? "hs" : (1 == colormode) ? "xy" : "ct"); - } - if (LST_RGB <= local_light_subtype) { - if (prev_x_str[0] && prev_y_str[0]) { - snprintf_P(buf, buf_size, PSTR("%s\"xy\":[%s,%s],"), buf, prev_x_str, prev_y_str); - } else { - float x_f = x / 65536.0f; - float y_f = y / 65536.0f; - snprintf_P(buf, buf_size, PSTR("%s\"xy\":[%s,%s],"), buf, String(x, 5).c_str(), String(y, 5).c_str()); - } - snprintf_P(buf, buf_size, PSTR("%s\"hue\":%d,\"sat\":%d,"), buf, hue16, sat); - } - if (LST_COLDWARM == local_light_subtype || LST_RGBW <= local_light_subtype) { - snprintf_P(buf, buf_size, PSTR("%s\"ct\":%d,"), buf, ct > 0 ? ct : 284); - } - snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON1_SUFFIX_ZIGBEE, buf, reachable ? "true" : "false"); - - *response += buf; - free(buf); -} - -void HueLightStatus2Zigbee(uint16_t shortaddr, String *response) -{ - const size_t buf_size = 192; - char * buf = (char*) malloc(buf_size); - - const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); - char shortaddrname[8]; - snprintf_P(shortaddrname, sizeof(shortaddrname), PSTR("0x%04X"), shortaddr); - - snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON2, - (friendlyName) ? friendlyName : shortaddrname, - GetHueDeviceId(shortaddr).c_str()); - *response += buf; - free(buf); -} - -void ZigbeeHueStatus(String * response, uint16_t shortaddr) { - *response += F("{\"state\":"); - HueLightStatus1Zigbee(shortaddr, zigbee_devices.getHueBulbtype(shortaddr), response); - HueLightStatus2Zigbee(shortaddr, response); -} - -void ZigbeeCheckHue(String * response, bool &appending) { - uint32_t zigbee_num = zigbee_devices.devicesSize(); - for (uint32_t i = 0; i < zigbee_num; i++) { - int8_t bulbtype = zigbee_devices.devicesAt(i).bulbtype; - - if (bulbtype >= 0) { - uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr; - - if (appending) { *response += ","; } - *response += "\""; - *response += EncodeLightId(0, shortaddr); - *response += F("\":{\"state\":"); - HueLightStatus1Zigbee(shortaddr, bulbtype, response); - HueLightStatus2Zigbee(shortaddr, response); - appending = true; - } - } -} - -void ZigbeeHueGroups(String * lights) { - uint32_t zigbee_num = zigbee_devices.devicesSize(); - for (uint32_t i = 0; i < zigbee_num; i++) { - int8_t bulbtype = zigbee_devices.devicesAt(i).bulbtype; - - if (bulbtype >= 0) { - *lights += ",\""; - *lights += EncodeLightId(i); - *lights += "\""; - } - } -} - - - -void ZigbeeHuePower(uint16_t shortaddr, bool power) { - zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0006, power ? 1 : 0, ""); - zigbee_devices.updateHueState(shortaddr, &power, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); -} - - -void ZigbeeHueDimmer(uint16_t shortaddr, uint8_t dimmer) { - if (dimmer > 0xFE) { dimmer = 0xFE; } - char param[8]; - snprintf_P(param, sizeof(param), PSTR("%02X0A00"), dimmer); - zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0008, 0x04, param); - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, &dimmer, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); -} - - -void ZigbeeHueCT(uint16_t shortaddr, uint16_t ct) { - if (ct > 0xFEFF) { ct = 0xFEFF; } - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeHueCT 0x%04X - %d"), shortaddr, ct); - char param[12]; - snprintf_P(param, sizeof(param), PSTR("%02X%02X0A00"), ct & 0xFF, ct >> 8); - uint8_t colormode = 2; - zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x0A, param); - zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr, &ct, nullptr, nullptr, nullptr, nullptr); -} - - -void ZigbeeHueXY(uint16_t shortaddr, uint16_t x, uint16_t y) { - char param[16]; - if (x > 0xFEFF) { x = 0xFEFF; } - if (y > 0xFEFF) { y = 0xFEFF; } - snprintf_P(param, sizeof(param), PSTR("%02X%02X%02X%02X0A00"), x & 0xFF, x >> 8, y & 0xFF, y >> 8); - uint8_t colormode = 1; - zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x07, param); - zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr, nullptr, nullptr, &x, &y, nullptr); -} - - -void ZigbeeHueHS(uint16_t shortaddr, uint16_t hue, uint8_t sat) { - char param[16]; - uint8_t hue8 = changeUIntScale(hue, 0, 360, 0, 254); - if (sat > 0xFE) { sat = 0xFE; } - snprintf_P(param, sizeof(param), PSTR("%02X%02X0000"), hue8, sat); - uint8_t colormode = 0; - zigbeeZCLSendStr(shortaddr, 0, 0, true, 0, 0x0300, 0x06, param); - zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, &sat, nullptr, &hue, nullptr, nullptr, nullptr); -} - -void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response) { - uint8_t power, colormode, bri, sat; - uint16_t ct, hue; - float x, y; - int code = 200; - - bool resp = false; - bool on = false; - - uint8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr); - - const size_t buf_size = 100; - char * buf = (char*) malloc(buf_size); - - if (Webserver->args()) { - response = "["; - - StaticJsonBuffer<300> jsonBuffer; - JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1)); - if (hue_json.containsKey("on")) { - on = hue_json["on"]; - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/on\":%s}}"), - device_id, on ? "true" : "false"); - - if (on) { - ZigbeeHuePower(shortaddr, 0x01); - } else { - ZigbeeHuePower(shortaddr, 0x00); - } - response += buf; - resp = true; - } - - if (hue_json.containsKey("bri")) { - bri = hue_json["bri"]; - prev_bri = bri; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "bri", bri); - response += buf; - if (LST_SINGLE <= bulbtype) { - - if (254 <= bri) { bri = 255; } - ZigbeeHueDimmer(shortaddr, bri); - } - resp = true; - } - - - if (hue_json.containsKey("xy")) { - float x = hue_json["xy"][0]; - float y = hue_json["xy"][1]; - const String &x_str = hue_json["xy"][0]; - const String &y_str = hue_json["xy"][1]; - x_str.toCharArray(prev_x_str, sizeof(prev_x_str)); - y_str.toCharArray(prev_y_str, sizeof(prev_y_str)); - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/xy\":[%s,%s]}}"), - device_id, prev_x_str, prev_y_str); - response += buf; - resp = true; - uint16_t xi = x * 65536.0f; - uint16_t yi = y * 65536.0f; - ZigbeeHueXY(shortaddr, xi, yi); - } - bool huesat_changed = false; - if (hue_json.containsKey("hue")) { - hue = hue_json["hue"]; - prev_hue = hue; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "hue", hue); - response += buf; - if (LST_RGB <= bulbtype) { - - hue = changeUIntScale(hue, 0, 65535, 0, 360); - huesat_changed = true; - } - resp = true; - } - if (hue_json.containsKey("sat")) { - sat = hue_json["sat"]; - prev_sat = sat; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "sat", sat); - response += buf; - if (LST_RGB <= bulbtype) { - - if (254 <= sat) { sat = 255; } - huesat_changed = true; - } - if (huesat_changed) { - ZigbeeHueHS(shortaddr, hue, sat); - } - resp = true; - } - if (hue_json.containsKey("ct")) { - ct = hue_json["ct"]; - prev_ct = ct; - if (resp) { response += ","; } - snprintf_P(buf, buf_size, - PSTR("{\"success\":{\"/lights/%d/state/%s\":%d}}"), - device_id, "ct", ct); - response += buf; - if ((LST_COLDWARM == bulbtype) || (LST_RGBW <= bulbtype)) { - ZigbeeHueCT(shortaddr, ct); - } - resp = true; - } - - response += "]"; - if (2 == response.length()) { - response = FPSTR(HUE_ERROR_JSON); - } - } - else { - response = FPSTR(HUE_ERROR_JSON); - } - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " Result (%s)"), response.c_str()); - WSSend(code, CT_JSON, response); - - free(buf); -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_4_persistence.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_4_persistence.ino" -#ifdef USE_ZIGBEE -# 52 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_4_persistence.ino" -const static uint16_t z_spi_start_sector = 0xFF; -const static uint8_t* z_spi_start = (uint8_t*) 0x402FF000; -const static uint8_t* z_dev_start = z_spi_start + 0x0800; -const static size_t z_spi_len = 0x1000; -const static size_t z_block_offset = 0x0800; -const static size_t z_block_len = 0x0800; - -class z_flashdata_t { -public: - uint32_t name; - uint16_t len; - uint16_t reserved; -}; - -const static uint32_t ZIGB_NAME = 0x3167697A; -const static size_t Z_MAX_FLASH = z_block_len - sizeof(z_flashdata_t); - - -const uint16_t Z_ClusterNumber[] PROGMEM = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0100, 0x0101, 0x0102, - 0x0201, 0x0202, 0x0203, 0x0204, - 0x0300, 0x0301, - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, - 0x0500, 0x0501, 0x0502, - 0x0700, 0x0701, 0x0702, - 0x0B00, 0x0B01, 0x0B02, 0x0B03, 0x0B04, 0x0B05, - 0x1000, - 0xFC0F, -}; - - -uint16_t fromClusterCode(uint8_t c) { - if (c >= sizeof(Z_ClusterNumber)/sizeof(Z_ClusterNumber[0])) { - return 0xFFFF; - } - return pgm_read_word(&Z_ClusterNumber[c]); -} - - -uint8_t toClusterCode(uint16_t c) { - for (uint32_t i = 0; i < sizeof(Z_ClusterNumber)/sizeof(Z_ClusterNumber[0]); i++) { - if (c == pgm_read_word(&Z_ClusterNumber[i])) { - return i; - } - } - return 0xFF; -} - -class SBuffer hibernateDevice(const struct Z_Device &device) { - SBuffer buf(128); - - buf.add8(0x00); - buf.add16(device.shortaddr); - buf.add64(device.longaddr); - - uint32_t endpoints_count = 0; - for (endpoints_count = 0; endpoints_count < endpoints_max; endpoints_count++) { - if (0x00 == device.endpoints[endpoints_count]) { break; } - } - - buf.add8(endpoints_count); - - for (uint32_t i = 0; i < endpoints_max; i++) { - uint8_t endpoint = device.endpoints[i]; - if (0x00 == endpoint) { break; } - - buf.add8(endpoint); - buf.add16(0x0000); - - - buf.add8(0xFF); - - - buf.add8(0xFF); - } - - - if (device.modelId) { - size_t model_len = strlen(device.modelId); - if (model_len > 32) { model_len = 32; } - buf.addBuffer(device.modelId, model_len); - } - buf.add8(0x00); - - - if (device.manufacturerId) { - size_t manuf_len = strlen(device.manufacturerId); - if (manuf_len > 32) { manuf_len = 32; } - buf.addBuffer(device.manufacturerId, manuf_len); - } - buf.add8(0x00); - - - if (device.friendlyName) { - size_t frname_len = strlen(device.friendlyName); - if (frname_len > 32) {frname_len = 32; } - buf.addBuffer(device.friendlyName, frname_len); - } - buf.add8(0x00); - - - buf.add8(device.bulbtype); - - - buf.set8(0, buf.len()); - - return buf; -} - -class SBuffer hibernateDevices(void) { - SBuffer buf(2048); - - size_t devices_size = zigbee_devices.devicesSize(); - if (devices_size > 32) { devices_size = 32; } - buf.add8(devices_size); - - for (uint32_t i = 0; i < devices_size; i++) { - const Z_Device & device = zigbee_devices.devicesAt(i); - const SBuffer buf_device = hibernateDevice(device); - buf.addBuffer(buf_device); - } - - size_t buf_len = buf.len(); - if (buf_len > 2040) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Devices list too big to fit in Flash (%d)"), buf_len); - } - - - char *hex_char = (char*) malloc((buf_len * 2) + 2); - if (hex_char) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "ZbFlashStore %s"), - ToHex_P(buf.getBuffer(), buf_len, hex_char, (buf_len * 2) + 2)); - free(hex_char); - } - - return buf; -} - -void hydrateDevices(const SBuffer &buf) { - uint32_t buf_len = buf.len(); - if (buf_len <= 10) { return; } - - uint32_t k = 0; - uint32_t num_devices = buf.get8(k++); - - for (uint32_t i = 0; (i < num_devices) && (k < buf_len); i++) { - uint32_t dev_record_len = buf.get8(k); - - - - - SBuffer buf_d = buf.subBuffer(k, dev_record_len); -# 217 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_4_persistence.ino" - uint32_t d = 1; - uint16_t shortaddr = buf_d.get16(d); d += 2; - uint64_t longaddr = buf_d.get64(d); d += 8; - zigbee_devices.updateDevice(shortaddr, longaddr); - - uint32_t endpoints = buf_d.get8(d++); - for (uint32_t j = 0; j < endpoints; j++) { - uint8_t ep = buf_d.get8(d++); - uint16_t ep_profile = buf_d.get16(d); d += 2; - zigbee_devices.addEndpoint(shortaddr, ep); - - - while (d < dev_record_len) { - uint8_t ep_cluster = buf_d.get8(d++); - if (0xFF == ep_cluster) { break; } - - } - - while (d < dev_record_len) { - uint8_t ep_cluster = buf_d.get8(d++); - if (0xFF == ep_cluster) { break; } - - } - } - - - - char empty[] = ""; - - - uint32_t s_len = buf_d.strlen_s(d); - char *ptr = s_len ? buf_d.charptr(d) : empty; - zigbee_devices.setModelId(shortaddr, ptr); - d += s_len + 1; - - - s_len = buf_d.strlen_s(d); - ptr = s_len ? buf_d.charptr(d) : empty; - zigbee_devices.setManufId(shortaddr, ptr); - d += s_len + 1; - - - s_len = buf_d.strlen_s(d); - ptr = s_len ? buf_d.charptr(d) : empty; - zigbee_devices.setFriendlyName(shortaddr, ptr); - d += s_len + 1; - - - if (d < dev_record_len) { - zigbee_devices.setHueBulbtype(shortaddr, buf_d.get8(d)); - d++; - } - - - k += dev_record_len; - - } -} - -void loadZigbeeDevices(void) { - z_flashdata_t flashdata; - memcpy_P(&flashdata, z_dev_start, sizeof(z_flashdata_t)); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Zigbee signature in Flash: %08X - %d"), flashdata.name, flashdata.len); - - - if ((flashdata.name == ZIGB_NAME) && (flashdata.len > 0)) { - uint16_t buf_len = flashdata.len; - - SBuffer buf(buf_len); - buf.addBuffer(z_dev_start + sizeof(z_flashdata_t), buf_len); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee devices data in Flash (%d bytes)"), buf_len); - hydrateDevices(buf); - zigbee_devices.clean(); - } else { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "No zigbee devices data in Flash")); - } - -} - -void saveZigbeeDevices(void) { - SBuffer buf = hibernateDevices(); - size_t buf_len = buf.len(); - if (buf_len > Z_MAX_FLASH) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Buffer too big to fit in Flash (%d bytes)"), buf_len); - return; - } - - - uint8_t *spi_buffer = (uint8_t*) malloc(z_spi_len); - if (!spi_buffer) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Cannot allocate 4KB buffer")); - return; - } - - ESP.flashRead(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); - - z_flashdata_t *flashdata = (z_flashdata_t*)(spi_buffer + z_block_offset); - flashdata->name = ZIGB_NAME; - flashdata->len = buf_len; - flashdata->reserved = 0; - - memcpy(spi_buffer + z_block_offset + sizeof(z_flashdata_t), buf.getBuffer(), buf_len); - - - if (ESP.flashEraseSector(z_spi_start_sector)) { - ESP.flashWrite(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); - } - - free(spi_buffer); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data store in Flash (0x%08X - %d bytes)"), z_dev_start, buf_len); -} - - -void eraseZigbeeDevices(void) { - zigbee_devices.clean(); - - uint8_t *spi_buffer = (uint8_t*) malloc(z_spi_len); - if (!spi_buffer) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Cannot allocate 4KB buffer")); - return; - } - - ESP.flashRead(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); - - - memset(spi_buffer + z_block_offset, 0xFF, z_block_len); - - - if (ESP.flashEraseSector(z_spi_start_sector)) { - ESP.flashWrite(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); - } - - free(spi_buffer); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data erased (0x%08X - %d bytes)"), z_dev_start, z_block_len); -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_5_converters.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_5_converters.ino" -#ifdef USE_ZIGBEE - - - - - - -enum Z_DataTypes { - Znodata = 0x00, - Zdata8 = 0x08, Zdata16, Zdata24, Zdata32, Zdata40, Zdata48, Zdata56, Zdata64, - Zbool = 0x10, - Zmap8 = 0x18, Zmap16, Zmap24, Zmap32, Zmap40, Zmap48, Zmap56, Zmap64, - Zuint8 = 0x20, Zuint16, Zuint24, Zuint32, Zuint40, Zuint48, Zuint56, Zuint64, - Zint8 = 0x28, Zint16, Zint24, Zint32, Zint40, Zint48, Zint56, Zint64, - Zenum8 = 0x30, Zenum16 = 0x31, - Zsemi = 0x38, Zsingle = 0x39, Zdouble = 0x3A, - Zoctstr = 0x41, Zstring = 0x42, Zoctstr16 = 0x43, Zstring16 = 0x44, - Arrray = 0x48, - Zstruct = 0x4C, - Zset = 0x50, Zbag = 0x51, - ZToD = 0xE0, Zdate = 0xE1, ZUTC = 0xE2, - ZclusterId = 0xE8, ZattribId = 0xE9, ZbacOID = 0xEA, - ZEUI64 = 0xF0, Zkey128 = 0xF1, - Zunk = 0xFF -}; - - - - - - -uint8_t Z_getDatatypeLen(uint8_t t) { - if ( ((t >= 0x08) && (t <= 0x0F)) || - ((t >= 0x18) && (t <= 0x2F)) ) { - return (t & 0x07) + 1; - } - switch (t) { - case Zbool: - case Zenum8: - return 1; - case Zenum16: - case Zsemi: - case ZclusterId: - case ZattribId: - return 2; - case Zsingle: - case ZToD: - case Zdate: - case ZUTC: - case ZbacOID: - return 4; - case Zdouble: - case ZEUI64: - return 8; - case Zkey128: - return 16; - case Znodata: - default: - return 0; - } -} -# 92 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_5_converters.ino" -typedef union ZCLHeaderFrameControl_t { - struct { - uint8_t frame_type : 2; - uint8_t manuf_specific : 1; - uint8_t direction : 1; - uint8_t disable_def_resp : 1; - uint8_t reserved : 3; - } b; - uint32_t d8; -} ZCLHeaderFrameControl_t; - - -class ZCLFrame { -public: - - ZCLFrame(uint8_t frame_control, uint16_t manuf_code, uint8_t transact_seq, uint8_t cmd_id, - const char *buf, size_t buf_len, uint16_t clusterid, uint16_t groupaddr, - uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast, - uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber, - uint32_t timestamp): - _manuf_code(manuf_code), _transact_seq(transact_seq), _cmd_id(cmd_id), - _payload(buf_len ? buf_len : 250), - _cluster_id(clusterid), _groupaddr(groupaddr), - _srcaddr(srcaddr), _srcendpoint(srcendpoint), _dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast), - _linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber), - _timestamp(timestamp) - { - _frame_control.d8 = frame_control; - _payload.addBuffer(buf, buf_len); - }; - - - void log(void) { - char hex_char[_payload.len()*2+2]; - ToHex_P((unsigned char*)_payload.getBuffer(), _payload.len(), hex_char, sizeof(hex_char)); - Response_P(PSTR("{\"" D_JSON_ZIGBEEZCL_RECEIVED "\":{" - "\"groupid\":%d," "\"clusterid\":%d," "\"srcaddr\":\"0x%04X\"," - "\"srcendpoint\":%d," "\"dstendpoint\":%d," "\"wasbroadcast\":%d," - "\"" D_CMND_ZIGBEE_LINKQUALITY "\":%d," "\"securityuse\":%d," "\"seqnumber\":%d," - "\"timestamp\":%d," - "\"fc\":\"0x%02X\",\"manuf\":\"0x%04X\",\"transact\":%d," - "\"cmdid\":\"0x%02X\",\"payload\":\"%s\"}}"), - _groupaddr, _cluster_id, _srcaddr, - _srcendpoint, _dstendpoint, _wasbroadcast, - _linkquality, _securityuse, _seqnumber, - _timestamp, - _frame_control, _manuf_code, _transact_seq, _cmd_id, - hex_char); - if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); - } else { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); - } - } - - static ZCLFrame parseRawFrame(const SBuffer &buf, uint8_t offset, uint8_t len, uint16_t clusterid, uint16_t groupid, - uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast, - uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber, - uint32_t timestamp) { - uint32_t i = offset; - ZCLHeaderFrameControl_t frame_control; - uint16_t manuf_code = 0; - uint8_t transact_seq; - uint8_t cmd_id; - - frame_control.d8 = buf.get8(i++); - if (frame_control.b.manuf_specific) { - manuf_code = buf.get16(i); - i += 2; - } - transact_seq = buf.get8(i++); - cmd_id = buf.get8(i++); - ZCLFrame zcl_frame(frame_control.d8, manuf_code, transact_seq, cmd_id, - (const char *)(buf.buf() + i), len + offset - i, - clusterid, groupid, - srcaddr, srcendpoint, dstendpoint, wasbroadcast, - linkquality, securityuse, seqnumber, - timestamp); - return zcl_frame; - } - - bool isClusterSpecificCommand(void) { - return _frame_control.b.frame_type & 1; - } - - static void generateAttributeName(const JsonObject& json, uint16_t cluster, uint16_t attr, char *key, size_t key_len); - void parseRawAttributes(JsonObject& json, uint8_t offset = 0); - void parseReadAttributes(JsonObject& json, uint8_t offset = 0); - void parseResponse(void); - void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0); - void postProcessAttributes(uint16_t shortaddr, JsonObject& json); - - inline void setGroupId(uint16_t groupid) { - _groupaddr = groupid; - } - - inline void setClusterId(uint16_t clusterid) { - _cluster_id = clusterid; - } - - inline uint8_t getCmdId(void) const { - return _cmd_id; - } - - inline uint16_t getClusterId(void) const { - return _cluster_id; - } - - inline uint16_t getSrcEndpoint(void) const { - return _srcendpoint; - } - - const SBuffer &getPayload(void) const { - return _payload; - } - - uint16_t getManufCode(void) const { - return _manuf_code; - } - -private: - ZCLHeaderFrameControl_t _frame_control = { .d8 = 0 }; - uint16_t _manuf_code = 0; - uint8_t _transact_seq = 0; - uint8_t _cmd_id = 0; - SBuffer _payload; - uint16_t _cluster_id = 0; - uint16_t _groupaddr = 0; - - uint16_t _srcaddr; - uint8_t _srcendpoint; - uint8_t _dstendpoint; - uint8_t _wasbroadcast; - uint8_t _linkquality; - uint8_t _securityuse; - uint8_t _seqnumber; - uint32_t _timestamp; -}; - - - - - - -uint8_t toPercentageCR2032(uint32_t voltage) { - uint32_t percentage; - if (voltage < 2100) { - percentage = 0; - } else if (voltage < 2440) { - percentage = 6 - ((2440 - voltage) * 6) / 340; - } else if (voltage < 2740) { - percentage = 18 - ((2740 - voltage) * 12) / 300; - } else if (voltage < 2900) { - percentage = 42 - ((2900 - voltage) * 24) / 160; - } else if (voltage < 3000) { - percentage = 100 - ((3000 - voltage) * 58) / 100; - } else if (voltage >= 3000) { - percentage = 100; - } - return percentage; -} - - -uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer &buf, - uint32_t offset, uint32_t buflen) { - - uint32_t i = offset; - uint32_t attrtype = buf.get8(i++); - - - json[attrid_str] = (char*) nullptr; - - uint32_t len = Z_getDatatypeLen(attrtype); - - - switch (attrtype) { - - - - case Zbool: - case Zuint8: - case Zenum8: - { - uint8_t uint8_val = buf.get8(i); - - if (0xFF != uint8_val) { - json[attrid_str] = uint8_val; - } - } - break; - case Zuint16: - case Zenum16: - { - uint16_t uint16_val = buf.get16(i); - - if (0xFFFF != uint16_val) { - json[attrid_str] = uint16_val; - } - } - break; - case Zuint32: - { - uint32_t uint32_val = buf.get32(i); - - if (0xFFFFFFFF != uint32_val) { - json[attrid_str] = uint32_val; - } - } - break; - - - case Zuint40: - case Zuint48: - case Zuint56: - case Zuint64: - case Zint40: - case Zint48: - case Zint56: - case Zint64: - { - - - char hex[2*len+1]; - ToHex_P(buf.buf(i), len, hex, sizeof(hex)); - json[attrid_str] = hex; - - } - break; - case Zint8: - { - int8_t int8_val = buf.get8(i); - - if (0x80 != int8_val) { - json[attrid_str] = int8_val; - } - } - break; - case Zint16: - { - int16_t int16_val = buf.get16(i); - - if (0x8000 != int16_val) { - json[attrid_str] = int16_val; - } - } - break; - case Zint32: - { - int32_t int32_val = buf.get32(i); - - if (0x80000000 != int32_val) { - json[attrid_str] = int32_val; - } - } - break; - - case Zoctstr: - case Zstring: - case Zoctstr16: - case Zstring16: - - { - bool parse_as_string = true; - len = (attrtype <= 0x42) ? buf.get8(i) : buf.get16(i); - i += (attrtype <= 0x42) ? 1 : 2; - if (i + len > buf.len()) { - len = buf.len() - i; - } - - - if ((0x41 == attrtype) || (0x43 == attrtype)) { parse_as_string = false; } - - if (parse_as_string) { - char str[len+1]; - strncpy(str, buf.charptr(i), len); - str[len] = 0x00; - json[attrid_str] = str; - } else { - - char hex[2*len+1]; - ToHex_P(buf.buf(i), len, hex, sizeof(hex)); - json[attrid_str] = hex; - } - - - - } - - break; - - case Zdata8: - case Zmap8: - { - uint8_t uint8_val = buf.get8(i); - - json[attrid_str] = uint8_val; - } - break; - case Zdata16: - case Zmap16: - { - uint16_t uint16_val = buf.get16(i); - - json[attrid_str] = uint16_val; - } - break; - case Zdata32: - case Zmap32: - { - uint32_t uint32_val = buf.get32(i); - - json[attrid_str] = uint32_val; - } - break; - - case Zsingle: - { - uint32_t uint32_val = buf.get32(i); - float * float_val = (float*) &uint32_val; - - json[attrid_str] = *float_val; - } - break; - - - case ZToD: - case Zdate: - case ZUTC: - case ZclusterId: - case ZattribId: - case ZbacOID: - case ZEUI64: - case Zkey128: - case Zsemi: - break; - - - case Zdata24: - case Zdata40: - case Zdata48: - case Zdata56: - case Zdata64: - break; - - case Zmap24: - case Zmap40: - case Zmap48: - case Zmap56: - case Zmap64: - break; - case Zdouble: - { - uint64_t uint64_val = buf.get64(i); - double * double_val = (double*) &uint64_val; - - json[attrid_str] = *double_val; - } - break; - } - i += len; - - - - - - - return i - offset; -} - - -void ZCLFrame::generateAttributeName(const JsonObject& json, uint16_t cluster, uint16_t attr, char *key, size_t key_len) { - uint32_t suffix = 1; - - snprintf_P(key, key_len, PSTR("%04X/%04X"), cluster, attr); - while (json.containsKey(key)) { - suffix++; - snprintf_P(key, key_len, PSTR("%04X/%04X+%d"), cluster, attr, suffix); - } -} - - -void ZCLFrame::parseRawAttributes(JsonObject& json, uint8_t offset) { - uint32_t i = offset; - uint32_t len = _payload.len(); - - while (len >= i + 3) { - uint16_t attrid = _payload.get16(i); - i += 2; - - char key[16]; - generateAttributeName(json, _cluster_id, attrid, key, sizeof(key)); - - - if ((0x0000 == _cluster_id) && (0xFF01 == attrid)) { - if (0x42 == _payload.get8(i)) { - _payload.set8(i, 0x41); - } - } - i += parseSingleAttribute(json, key, _payload, i, len); - } -} - - -void ZCLFrame::parseReadAttributes(JsonObject& json, uint8_t offset) { - uint32_t i = offset; - uint32_t len = _payload.len(); - - while (len - i >= 4) { - uint16_t attrid = _payload.get16(i); - i += 2; - uint8_t status = _payload.get8(i++); - - if (0 == status) { - char key[16]; - generateAttributeName(json, _cluster_id, attrid, key, sizeof(key)); - - i += parseSingleAttribute(json, key, _payload, i, len); - } - } -} - - -void ZCLFrame::parseResponse(void) { - if (_payload.len() < 2) { return; } - uint8_t cmd = _payload.get8(0); - uint8_t status = _payload.get8(1); - - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - - - char s[12]; - snprintf_P(s, sizeof(s), PSTR("0x%04X"), _srcaddr); - json[F(D_JSON_ZIGBEE_DEVICE)] = s; - - const char * friendlyName = zigbee_devices.getFriendlyName(_srcaddr); - if (friendlyName) { - json[F(D_JSON_ZIGBEE_NAME)] = (char*) friendlyName; - } - - snprintf_P(s, sizeof(s), PSTR("%04X!%02X"), _cluster_id, cmd); - json[F(D_JSON_ZIGBEE_CMD)] = s; - - json[F(D_JSON_ZIGBEE_STATUS)] = status; - - json[F(D_JSON_ZIGBEE_STATUS_MSG)] = getZigbeeStatusMessage(status); - - json[F(D_CMND_ZIGBEE_ENDPOINT)] = _srcendpoint; - - if (_groupaddr) { - json[F(D_CMND_ZIGBEE_GROUP)] = _groupaddr; - } - - json[F(D_CMND_ZIGBEE_LINKQUALITY)] = _linkquality; - - String msg(""); - msg.reserve(100); - json.printTo(msg); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_RESPONSE "\":%s}"), msg.c_str()); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); -} - - - -void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) { - convertClusterSpecific(json, _cluster_id, _cmd_id, _frame_control.b.direction, _payload); - sendHueUpdate(_srcaddr, _groupaddr, _cluster_id, _cmd_id, _frame_control.b.direction); -} - - - - -typedef int32_t (*Z_AttrConverter)(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); -typedef struct Z_AttributeConverter { - uint8_t type; - uint8_t cluster_short; - uint16_t attribute; - const char * name; - Z_AttrConverter func; -} Z_AttributeConverter; - -enum Cx_cluster_short { - Cx0000, Cx0001, Cx0002, Cx0003, Cx0004, Cx0005, Cx0006, Cx0007, - Cx0008, Cx0009, Cx000A, Cx000B, Cx000C, Cx000D, Cx000E, Cx000F, - Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0100, - Cx0101, Cx0102, Cx0300, Cx0400, Cx0401, Cx0402, Cx0403, Cx0404, - Cx0405, Cx0406, Cx0B01, Cx0B05, -}; - -const uint16_t Cx_cluster[] PROGMEM = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0100, - 0x0101, 0x0102, 0x0300, 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, - 0x0405, 0x0406, 0x0B01, 0x0B05, -}; - -uint16_t CxToCluster(uint8_t cx) { - if (cx < sizeof(Cx_cluster)/sizeof(Cx_cluster[0])) { - return pgm_read_word(&Cx_cluster[cx]); - } - return 0xFFFF; -} - -ZF(ZCLVersion) ZF(AppVersion) ZF(StackVersion) ZF(HWVersion) ZF(Manufacturer) ZF(ModelId) -ZF(DateCode) ZF(PowerSource) ZF(SWBuildID) ZF(Power) ZF(SwitchType) ZF(Dimmer) -ZF(MainsVoltage) ZF(MainsFrequency) ZF(BatteryVoltage) ZF(BatteryPercentage) -ZF(CurrentTemperature) ZF(MinTempExperienced) ZF(MaxTempExperienced) ZF(OverTempTotalDwell) -ZF(SceneCount) ZF(CurrentScene) ZF(CurrentGroup) ZF(SceneValid) -ZF(AlarmCount) ZF(Time) ZF(TimeStatus) ZF(TimeZone) ZF(DstStart) ZF(DstEnd) -ZF(DstShift) ZF(StandardTime) ZF(LocalTime) ZF(LastSetTime) ZF(ValidUntilTime) - -ZF(LocationType) ZF(LocationMethod) ZF(LocationAge) ZF(QualityMeasure) ZF(NumberOfDevices) - -ZF(AnalogInActiveText) ZF(AnalogInDescription) ZF(AnalogInInactiveText) ZF(AnalogInMaxValue) -ZF(AnalogInMinValue) ZF(AnalogInOutOfService) ZF(AqaraRotate) ZF(AnalogInPriorityArray) -ZF(AnalogInReliability) ZF(AnalogInRelinquishDefault) ZF(AnalogInResolution) ZF(AnalogInStatusFlags) -ZF(AnalogInEngineeringUnits) ZF(AnalogInApplicationType) ZF(Aqara_FF05) - -ZF(AnalogOutDescription) ZF(AnalogOutMaxValue) ZF(AnalogOutMinValue) ZF(AnalogOutOutOfService) -ZF(AnalogOutValue) ZF(AnalogOutPriorityArray) ZF(AnalogOutReliability) ZF(AnalogOutRelinquishDefault) -ZF(AnalogOutResolution) ZF(AnalogOutStatusFlags) ZF(AnalogOutEngineeringUnits) ZF(AnalogOutApplicationType) - -ZF(AnalogDescription) ZF(AnalogOutOfService) ZF(AnalogValue) ZF(AnalogPriorityArray) ZF(AnalogReliability) -ZF(AnalogRelinquishDefault) ZF(AnalogStatusFlags) ZF(AnalogEngineeringUnits) ZF(AnalogApplicationType) - -ZF(BinaryInActiveText) ZF(BinaryInDescription) ZF(BinaryInInactiveText) ZF(BinaryInOutOfService) -ZF(BinaryInPolarity) ZF(BinaryInValue) ZF(BinaryInPriorityArray) ZF(BinaryInReliability) -ZF(BinaryInStatusFlags) ZF(BinaryInApplicationType) - -ZF(BinaryOutActiveText) ZF(BinaryOutDescription) ZF(BinaryOutInactiveText) ZF(BinaryOutMinimumOffTime) -ZF(BinaryOutMinimumOnTime) ZF(BinaryOutOutOfService) ZF(BinaryOutPolarity) ZF(BinaryOutValue) -ZF(BinaryOutPriorityArray) ZF(BinaryOutReliability) ZF(BinaryOutRelinquishDefault) ZF(BinaryOutStatusFlags) -ZF(BinaryOutApplicationType) - -ZF(BinaryActiveText) ZF(BinaryDescription) ZF(BinaryInactiveText) ZF(BinaryMinimumOffTime) -ZF(BinaryMinimumOnTime) ZF(BinaryOutOfService) ZF(BinaryValue) ZF(BinaryPriorityArray) ZF(BinaryReliability) -ZF(BinaryRelinquishDefault) ZF(BinaryStatusFlags) ZF(BinaryApplicationType) - -ZF(MultiInStateText) ZF(MultiInDescription) ZF(MultiInNumberOfStates) ZF(MultiInOutOfService) -ZF(MultiInValue) ZF(MultiInReliability) ZF(MultiInStatusFlags) ZF(MultiInApplicationType) - -ZF(MultiOutStateText) ZF(MultiOutDescription) ZF(MultiOutNumberOfStates) ZF(MultiOutOutOfService) -ZF(MultiOutValue) ZF(MultiOutPriorityArray) ZF(MultiOutReliability) ZF(MultiOutRelinquishDefault) -ZF(MultiOutStatusFlags) ZF(MultiOutApplicationType) - -ZF(MultiStateText) ZF(MultiDescription) ZF(MultiNumberOfStates) ZF(MultiOutOfService) ZF(MultiValue) -ZF(MultiReliability) ZF(MultiRelinquishDefault) ZF(MultiStatusFlags) ZF(MultiApplicationType) - -ZF(TotalProfileNum) ZF(MultipleScheduling) ZF(EnergyFormatting) ZF(EnergyRemote) ZF(ScheduleMode) - -ZF(CheckinInterval) ZF(LongPollInterval) ZF(ShortPollInterval) ZF(FastPollTimeout) ZF(CheckinIntervalMin) -ZF(LongPollIntervalMin) ZF(FastPollTimeoutMax) - -ZF(PhysicalClosedLimit) ZF(MotorStepSize) ZF(Status) ZF(ClosedLimit) ZF(Mode) - -ZF(LockState) ZF(LockType) ZF(ActuatorEnabled) ZF(DoorState) ZF(DoorOpenEvents) -ZF(DoorClosedEvents) ZF(OpenPeriod) - -ZF(AqaraVibrationMode) ZF(AqaraVibrationsOrAngle) ZF(AqaraVibration505) ZF(AqaraAccelerometer) - -ZF(WindowCoveringType) ZF(PhysicalClosedLimitLift) ZF(PhysicalClosedLimitTilt) ZF(CurrentPositionLift) -ZF(CurrentPositionTilt) ZF(NumberofActuationsLift) ZF(NumberofActuationsTilt) ZF(ConfigStatus) -ZF(CurrentPositionLiftPercentage) ZF(CurrentPositionTiltPercentage) ZF(InstalledOpenLimitLift) -ZF(InstalledClosedLimitLift) ZF(InstalledOpenLimitTilt) ZF(InstalledClosedLimitTilt) ZF(VelocityLift) -ZF(AccelerationTimeLift) ZF(DecelerationTimeLift) ZF(IntermediateSetpointsLift) -ZF(IntermediateSetpointsTilt) - -ZF(Hue) ZF(Sat) ZF(RemainingTime) ZF(X) ZF(Y) ZF(DriftCompensation) ZF(CompensationText) ZF(CT) -ZF(ColorMode) ZF(NumberOfPrimaries) ZF(Primary1X) ZF(Primary1Y) ZF(Primary1Intensity) ZF(Primary2X) -ZF(Primary2Y) ZF(Primary2Intensity) ZF(Primary3X) ZF(Primary3Y) ZF(Primary3Intensity) ZF(WhitePointX) -ZF(WhitePointY) ZF(ColorPointRX) ZF(ColorPointRY) ZF(ColorPointRIntensity) ZF(ColorPointGX) ZF(ColorPointGY) -ZF(ColorPointGIntensity) ZF(ColorPointBX) ZF(ColorPointBY) ZF(ColorPointBIntensity) - -ZF(Illuminance) ZF(IlluminanceMinMeasuredValue) ZF(IlluminanceMaxMeasuredValue) ZF(IlluminanceTolerance) -ZF(IlluminanceLightSensorType) ZF(IlluminanceLevelStatus) ZF(IlluminanceTargetLevel) - -ZF(Temperature) ZF(TemperatureMinMeasuredValue) ZF(TemperatureMaxMeasuredValue) ZF(TemperatureTolerance) - -ZF(PressureUnit) ZF(Pressure) ZF(PressureMinMeasuredValue) ZF(PressureMaxMeasuredValue) ZF(PressureTolerance) -ZF(PressureScaledValue) ZF(PressureMinScaledValue) ZF(PressureMaxScaledValue) ZF(PressureScaledTolerance) -ZF(PressureScale) - -ZF(FlowRate) ZF(FlowMinMeasuredValue) ZF(FlowMaxMeasuredValue) ZF(FlowTolerance) - -ZF(Humidity) ZF(HumidityMinMeasuredValue) ZF(HumidityMaxMeasuredValue) ZF(HumidityTolerance) - -ZF(Occupancy) ZF(OccupancySensorType) - -ZF(CompanyName) ZF(MeterTypeID) ZF(DataQualityID) ZF(CustomerName) ZF(Model) ZF(PartNumber) -ZF(SoftwareRevision) ZF(POD) ZF(AvailablePower) ZF(PowerThreshold) ZF(ProductRevision) ZF(UtilityName) - -ZF(NumberOfResets) ZF(PersistentMemoryWrites) ZF(LastMessageLQI) ZF(LastMessageRSSI) - -const Z_AttributeConverter Z_PostProcess[] PROGMEM = { - { Zuint8, Cx0000, 0x0000, Z(ZCLVersion), &Z_Copy }, - { Zuint8, Cx0000, 0x0001, Z(AppVersion), &Z_Copy }, - { Zuint8, Cx0000, 0x0002, Z(StackVersion), &Z_Copy }, - { Zuint8, Cx0000, 0x0003, Z(HWVersion), &Z_Copy }, - { Zstring, Cx0000, 0x0004, Z(Manufacturer), &Z_ManufKeep }, - { Zstring, Cx0000, 0x0005, Z(ModelId), &Z_ModelKeep }, - { Zstring, Cx0000, 0x0006, Z(DateCode), &Z_Copy }, - { Zenum8, Cx0000, 0x0007, Z(PowerSource), &Z_Copy }, - { Zstring, Cx0000, 0x4000, Z(SWBuildID), &Z_Copy }, - { Zunk, Cx0000, 0xFFFF, nullptr, &Z_Remove }, - - { Zmap8, Cx0000, 0xFF01, nullptr, &Z_AqaraSensor }, - - - { Zuint16, Cx0001, 0x0000, Z(MainsVoltage), &Z_Copy }, - { Zuint8, Cx0001, 0x0001, Z(MainsFrequency), &Z_Copy }, - { Zuint8, Cx0001, 0x0020, Z(BatteryVoltage), &Z_FloatDiv10 }, - { Zuint8, Cx0001, 0x0021, Z(BatteryPercentage), &Z_Copy }, - - - { Zint16, Cx0002, 0x0000, Z(CurrentTemperature), &Z_Copy }, - { Zint16, Cx0002, 0x0001, Z(MinTempExperienced), &Z_Copy }, - { Zint16, Cx0002, 0x0002, Z(MaxTempExperienced), &Z_Copy }, - { Zuint16, Cx0002, 0x0003, Z(OverTempTotalDwell), &Z_Copy }, - - - { Zuint8, Cx0005, 0x0000, Z(SceneCount), &Z_Copy }, - { Zuint8, Cx0005, 0x0001, Z(CurrentScene), &Z_Copy }, - { Zuint16, Cx0005, 0x0002, Z(CurrentGroup), &Z_Copy }, - { Zbool, Cx0005, 0x0003, Z(SceneValid), &Z_Copy }, - - - - { Zbool, Cx0006, 0x0000, Z(Power), &Z_Copy }, - { Zbool, Cx0006, 0x8000, Z(Power), &Z_Copy }, - - - { Zenum8, Cx0007, 0x0000, Z(SwitchType), &Z_Copy }, - - - { Zuint8, Cx0008, 0x0000, Z(Dimmer), &Z_Copy }, -# 738 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_5_converters.ino" - { Zuint16, Cx0009, 0x0000, Z(AlarmCount), &Z_Copy }, - - - { ZUTC, Cx000A, 0x0000, Z(Time), &Z_Copy }, - { Zmap8, Cx000A, 0x0001, Z(TimeStatus), &Z_Copy }, - { Zint32, Cx000A, 0x0002, Z(TimeZone), &Z_Copy }, - { Zuint32, Cx000A, 0x0003, Z(DstStart), &Z_Copy }, - { Zuint32, Cx000A, 0x0004, Z(DstEnd), &Z_Copy }, - { Zint32, Cx000A, 0x0005, Z(DstShift), &Z_Copy }, - { Zuint32, Cx000A, 0x0006, Z(StandardTime), &Z_Copy }, - { Zuint32, Cx000A, 0x0007, Z(LocalTime), &Z_Copy }, - { ZUTC, Cx000A, 0x0008, Z(LastSetTime), &Z_Copy }, - { ZUTC, Cx000A, 0x0009, Z(ValidUntilTime), &Z_Copy }, - - - { Zdata8, Cx000B, 0x0000, Z(LocationType), &Z_Copy }, - { Zenum8, Cx000B, 0x0001, Z(LocationMethod), &Z_Copy }, - { Zuint16, Cx000B, 0x0002, Z(LocationAge), &Z_Copy }, - { Zuint8, Cx000B, 0x0003, Z(QualityMeasure), &Z_Copy }, - { Zuint8, Cx000B, 0x0004, Z(NumberOfDevices), &Z_Copy }, - - - - { Zstring, Cx000C, 0x001C, Z(AnalogInDescription), &Z_Copy }, - - { Zsingle, Cx000C, 0x0041, Z(AnalogInMaxValue), &Z_Copy }, - { Zsingle, Cx000C, 0x0045, Z(AnalogInMinValue), &Z_Copy }, - { Zbool, Cx000C, 0x0051, Z(AnalogInOutOfService), &Z_Copy }, - { Zsingle, Cx000C, 0x0055, Z(AqaraRotate), &Z_Copy }, - - { Zenum8, Cx000C, 0x0067, Z(AnalogInReliability), &Z_Copy }, - - { Zsingle, Cx000C, 0x006A, Z(AnalogInResolution), &Z_Copy }, - { Zmap8, Cx000C, 0x006F, Z(AnalogInStatusFlags), &Z_Copy }, - { Zenum16, Cx000C, 0x0075, Z(AnalogInEngineeringUnits),&Z_Copy }, - { Zuint32, Cx000C, 0x0100, Z(AnalogInApplicationType),&Z_Copy }, - { Zuint16, Cx000C, 0xFF05, Z(Aqara_FF05), &Z_Copy }, - - - { Zstring, Cx000D, 0x001C, Z(AnalogOutDescription), &Z_Copy }, - { Zsingle, Cx000D, 0x0041, Z(AnalogOutMaxValue), &Z_Copy }, - { Zsingle, Cx000D, 0x0045, Z(AnalogOutMinValue), &Z_Copy }, - { Zbool, Cx000D, 0x0051, Z(AnalogOutOutOfService),&Z_Copy }, - { Zsingle, Cx000D, 0x0055, Z(AnalogOutValue), &Z_Copy }, - - { Zenum8, Cx000D, 0x0067, Z(AnalogOutReliability), &Z_Copy }, - { Zsingle, Cx000D, 0x0068, Z(AnalogOutRelinquishDefault),&Z_Copy }, - { Zsingle, Cx000D, 0x006A, Z(AnalogOutResolution), &Z_Copy }, - { Zmap8, Cx000D, 0x006F, Z(AnalogOutStatusFlags), &Z_Copy }, - { Zenum16, Cx000D, 0x0075, Z(AnalogOutEngineeringUnits),&Z_Copy }, - { Zuint32, Cx000D, 0x0100, Z(AnalogOutApplicationType),&Z_Copy }, - - - { Zstring, Cx000E, 0x001C, Z(AnalogDescription), &Z_Copy }, - { Zbool, Cx000E, 0x0051, Z(AnalogOutOfService), &Z_Copy }, - { Zsingle, Cx000E, 0x0055, Z(AnalogValue), &Z_Copy }, - { Zunk, Cx000E, 0x0057, Z(AnalogPriorityArray), &Z_Copy }, - { Zenum8, Cx000E, 0x0067, Z(AnalogReliability), &Z_Copy }, - { Zsingle, Cx000E, 0x0068, Z(AnalogRelinquishDefault),&Z_Copy }, - { Zmap8, Cx000E, 0x006F, Z(AnalogStatusFlags), &Z_Copy }, - { Zenum16, Cx000E, 0x0075, Z(AnalogEngineeringUnits),&Z_Copy }, - { Zuint32, Cx000E, 0x0100, Z(AnalogApplicationType),&Z_Copy }, - - - { Zstring, Cx000F, 0x0004, Z(BinaryInActiveText), &Z_Copy }, - { Zstring, Cx000F, 0x001C, Z(BinaryInDescription), &Z_Copy }, - { Zstring, Cx000F, 0x002E, Z(BinaryInInactiveText),&Z_Copy }, - { Zbool, Cx000F, 0x0051, Z(BinaryInOutOfService),&Z_Copy }, - { Zenum8, Cx000F, 0x0054, Z(BinaryInPolarity), &Z_Copy }, - { Zstring, Cx000F, 0x0055, Z(BinaryInValue), &Z_Copy }, - - { Zenum8, Cx000F, 0x0067, Z(BinaryInReliability), &Z_Copy }, - { Zmap8, Cx000F, 0x006F, Z(BinaryInStatusFlags), &Z_Copy }, - { Zuint32, Cx000F, 0x0100, Z(BinaryInApplicationType),&Z_Copy }, - - - { Zstring, Cx0010, 0x0004, Z(BinaryOutActiveText), &Z_Copy }, - { Zstring, Cx0010, 0x001C, Z(BinaryOutDescription), &Z_Copy }, - { Zstring, Cx0010, 0x002E, Z(BinaryOutInactiveText),&Z_Copy }, - { Zuint32, Cx0010, 0x0042, Z(BinaryOutMinimumOffTime),&Z_Copy }, - { Zuint32, Cx0010, 0x0043, Z(BinaryOutMinimumOnTime),&Z_Copy }, - { Zbool, Cx0010, 0x0051, Z(BinaryOutOutOfService),&Z_Copy }, - { Zenum8, Cx0010, 0x0054, Z(BinaryOutPolarity), &Z_Copy }, - { Zbool, Cx0010, 0x0055, Z(BinaryOutValue), &Z_Copy }, - - { Zenum8, Cx0010, 0x0067, Z(BinaryOutReliability), &Z_Copy }, - { Zbool, Cx0010, 0x0068, Z(BinaryOutRelinquishDefault),&Z_Copy }, - { Zmap8, Cx0010, 0x006F, Z(BinaryOutStatusFlags), &Z_Copy }, - { Zuint32, Cx0010, 0x0100, Z(BinaryOutApplicationType),&Z_Copy }, - - - { Zstring, Cx0011, 0x0004, Z(BinaryActiveText), &Z_Copy }, - { Zstring, Cx0011, 0x001C, Z(BinaryDescription), &Z_Copy }, - { Zstring, Cx0011, 0x002E, Z(BinaryInactiveText), &Z_Copy }, - { Zuint32, Cx0011, 0x0042, Z(BinaryMinimumOffTime), &Z_Copy }, - { Zuint32, Cx0011, 0x0043, Z(BinaryMinimumOnTime), &Z_Copy }, - { Zbool, Cx0011, 0x0051, Z(BinaryOutOfService), &Z_Copy }, - { Zbool, Cx0011, 0x0055, Z(BinaryValue), &Z_Copy }, - - { Zenum8, Cx0011, 0x0067, Z(BinaryReliability), &Z_Copy }, - { Zbool, Cx0011, 0x0068, Z(BinaryRelinquishDefault),&Z_Copy }, - { Zmap8, Cx0011, 0x006F, Z(BinaryStatusFlags), &Z_Copy }, - { Zuint32, Cx0011, 0x0100, Z(BinaryApplicationType),&Z_Copy }, - - - - { Zstring, Cx0012, 0x001C, Z(MultiInDescription), &Z_Copy }, - { Zuint16, Cx0012, 0x004A, Z(MultiInNumberOfStates),&Z_Copy }, - { Zbool, Cx0012, 0x0051, Z(MultiInOutOfService), &Z_Copy }, - { Zuint16, Cx0012, 0x0055, Z(MultiInValue), &Z_AqaraCube }, - { Zenum8, Cx0012, 0x0067, Z(MultiInReliability), &Z_Copy }, - { Zmap8, Cx0012, 0x006F, Z(MultiInStatusFlags), &Z_Copy }, - { Zuint32, Cx0012, 0x0100, Z(MultiInApplicationType),&Z_Copy }, - - - - { Zstring, Cx0013, 0x001C, Z(MultiOutDescription), &Z_Copy }, - { Zuint16, Cx0013, 0x004A, Z(MultiOutNumberOfStates),&Z_Copy }, - { Zbool, Cx0013, 0x0051, Z(MultiOutOutOfService), &Z_Copy }, - { Zuint16, Cx0013, 0x0055, Z(MultiOutValue), &Z_Copy }, - - { Zenum8, Cx0013, 0x0067, Z(MultiOutReliability), &Z_Copy }, - { Zuint16, Cx0013, 0x0068, Z(MultiOutRelinquishDefault),&Z_Copy }, - { Zmap8, Cx0013, 0x006F, Z(MultiOutStatusFlags), &Z_Copy }, - { Zuint32, Cx0013, 0x0100, Z(MultiOutApplicationType),&Z_Copy }, - - - - { Zstring, Cx0014, 0x001C, Z(MultiDescription), &Z_Copy }, - { Zuint16, Cx0014, 0x004A, Z(MultiNumberOfStates), &Z_Copy }, - { Zbool, Cx0014, 0x0051, Z(MultiOutOfService), &Z_Copy }, - { Zuint16, Cx0014, 0x0055, Z(MultiValue), &Z_Copy }, - { Zenum8, Cx0014, 0x0067, Z(MultiReliability), &Z_Copy }, - { Zuint16, Cx0014, 0x0068, Z(MultiRelinquishDefault),&Z_Copy }, - { Zmap8, Cx0014, 0x006F, Z(MultiStatusFlags), &Z_Copy }, - { Zuint32, Cx0014, 0x0100, Z(MultiApplicationType), &Z_Copy }, - - - { Zuint8, Cx001A, 0x0000, Z(TotalProfileNum), &Z_Copy }, - { Zbool, Cx001A, 0x0001, Z(MultipleScheduling), &Z_Copy }, - { Zmap8, Cx001A, 0x0002, Z(EnergyFormatting), &Z_Copy }, - { Zbool, Cx001A, 0x0003, Z(EnergyRemote), &Z_Copy }, - { Zmap8, Cx001A, 0x0004, Z(ScheduleMode), &Z_Copy }, - - - { Zuint32, Cx0020, 0x0000, Z(CheckinInterval), &Z_Copy }, - { Zuint32, Cx0020, 0x0001, Z(LongPollInterval), &Z_Copy }, - { Zuint16, Cx0020, 0x0002, Z(ShortPollInterval), &Z_Copy }, - { Zuint16, Cx0020, 0x0003, Z(FastPollTimeout), &Z_Copy }, - { Zuint32, Cx0020, 0x0004, Z(CheckinIntervalMin), &Z_Copy }, - { Zuint32, Cx0020, 0x0005, Z(LongPollIntervalMin), &Z_Copy }, - { Zuint16, Cx0020, 0x0006, Z(FastPollTimeoutMax), &Z_Copy }, - - - { Zuint16, Cx0100, 0x0000, Z(PhysicalClosedLimit), &Z_Copy }, - { Zuint8, Cx0100, 0x0001, Z(MotorStepSize), &Z_Copy }, - { Zmap8, Cx0100, 0x0002, Z(Status), &Z_Copy }, - { Zuint16, Cx0100, 0x0010, Z(ClosedLimit), &Z_Copy }, - { Zenum8, Cx0100, 0x0011, Z(Mode), &Z_Copy }, - - - { Zenum8, Cx0101, 0x0000, Z(LockState), &Z_Copy }, - { Zenum8, Cx0101, 0x0001, Z(LockType), &Z_Copy }, - { Zbool, Cx0101, 0x0002, Z(ActuatorEnabled), &Z_Copy }, - { Zenum8, Cx0101, 0x0003, Z(DoorState), &Z_Copy }, - { Zuint32, Cx0101, 0x0004, Z(DoorOpenEvents), &Z_Copy }, - { Zuint32, Cx0101, 0x0005, Z(DoorClosedEvents), &Z_Copy }, - { Zuint16, Cx0101, 0x0006, Z(OpenPeriod), &Z_Copy }, - - - { Zuint16, Cx0101, 0x0055, Z(AqaraVibrationMode), &Z_AqaraVibration }, - { Zuint16, Cx0101, 0x0503, Z(AqaraVibrationsOrAngle), &Z_Copy }, - { Zuint32, Cx0101, 0x0505, Z(AqaraVibration505), &Z_Copy }, - { Zuint48, Cx0101, 0x0508, Z(AqaraAccelerometer), &Z_AqaraVibration }, - - - { Zenum8, Cx0102, 0x0000, Z(WindowCoveringType), &Z_Copy }, - { Zuint16, Cx0102, 0x0001, Z(PhysicalClosedLimitLift),&Z_Copy }, - { Zuint16, Cx0102, 0x0002, Z(PhysicalClosedLimitTilt),&Z_Copy }, - { Zuint16, Cx0102, 0x0003, Z(CurrentPositionLift), &Z_Copy }, - { Zuint16, Cx0102, 0x0004, Z(CurrentPositionTilt), &Z_Copy }, - { Zuint16, Cx0102, 0x0005, Z(NumberofActuationsLift),&Z_Copy }, - { Zuint16, Cx0102, 0x0006, Z(NumberofActuationsTilt),&Z_Copy }, - { Zmap8, Cx0102, 0x0007, Z(ConfigStatus), &Z_Copy }, - { Zuint8, Cx0102, 0x0008, Z(CurrentPositionLiftPercentage),&Z_Copy }, - { Zuint8, Cx0102, 0x0009, Z(CurrentPositionTiltPercentage),&Z_Copy }, - { Zuint16, Cx0102, 0x0010, Z(InstalledOpenLimitLift),&Z_Copy }, - { Zuint16, Cx0102, 0x0011, Z(InstalledClosedLimitLift),&Z_Copy }, - { Zuint16, Cx0102, 0x0012, Z(InstalledOpenLimitTilt),&Z_Copy }, - { Zuint16, Cx0102, 0x0013, Z(InstalledClosedLimitTilt),&Z_Copy }, - { Zuint16, Cx0102, 0x0014, Z(VelocityLift), &Z_Copy }, - { Zuint16, Cx0102, 0x0015, Z(AccelerationTimeLift),&Z_Copy }, - { Zuint16, Cx0102, 0x0016, Z(DecelerationTimeLift), &Z_Copy }, - { Zmap8, Cx0102, 0x0017, Z(Mode), &Z_Copy }, - { Zoctstr, Cx0102, 0x0018, Z(IntermediateSetpointsLift),&Z_Copy }, - { Zoctstr, Cx0102, 0x0019, Z(IntermediateSetpointsTilt),&Z_Copy }, - - - { Zuint8, Cx0300, 0x0000, Z(Hue), &Z_Copy }, - { Zuint8, Cx0300, 0x0001, Z(Sat), &Z_Copy }, - { Zuint16, Cx0300, 0x0002, Z(RemainingTime), &Z_Copy }, - { Zuint16, Cx0300, 0x0003, Z(X), &Z_Copy }, - { Zuint16, Cx0300, 0x0004, Z(Y), &Z_Copy }, - { Zenum8, Cx0300, 0x0005, Z(DriftCompensation), &Z_Copy }, - { Zstring, Cx0300, 0x0006, Z(CompensationText), &Z_Copy }, - { Zuint16, Cx0300, 0x0007, Z(CT), &Z_Copy }, - { Zenum8, Cx0300, 0x0008, Z(ColorMode), &Z_Copy }, - { Zuint8, Cx0300, 0x0010, Z(NumberOfPrimaries), &Z_Copy }, - { Zuint16, Cx0300, 0x0011, Z(Primary1X), &Z_Copy }, - { Zuint16, Cx0300, 0x0012, Z(Primary1Y), &Z_Copy }, - { Zuint8, Cx0300, 0x0013, Z(Primary1Intensity), &Z_Copy }, - { Zuint16, Cx0300, 0x0015, Z(Primary2X), &Z_Copy }, - { Zuint16, Cx0300, 0x0016, Z(Primary2Y), &Z_Copy }, - { Zuint8, Cx0300, 0x0017, Z(Primary2Intensity), &Z_Copy }, - { Zuint16, Cx0300, 0x0019, Z(Primary3X), &Z_Copy }, - { Zuint16, Cx0300, 0x001A, Z(Primary3Y), &Z_Copy }, - { Zuint8, Cx0300, 0x001B, Z(Primary3Intensity), &Z_Copy }, - { Zuint16, Cx0300, 0x0030, Z(WhitePointX), &Z_Copy }, - { Zuint16, Cx0300, 0x0031, Z(WhitePointY), &Z_Copy }, - { Zuint16, Cx0300, 0x0032, Z(ColorPointRX), &Z_Copy }, - { Zuint16, Cx0300, 0x0033, Z(ColorPointRY), &Z_Copy }, - { Zuint8, Cx0300, 0x0034, Z(ColorPointRIntensity), &Z_Copy }, - { Zuint16, Cx0300, 0x0036, Z(ColorPointGX), &Z_Copy }, - { Zuint16, Cx0300, 0x0037, Z(ColorPointGY), &Z_Copy }, - { Zuint8, Cx0300, 0x0038, Z(ColorPointGIntensity), &Z_Copy }, - { Zuint16, Cx0300, 0x003A, Z(ColorPointBX), &Z_Copy }, - { Zuint16, Cx0300, 0x003B, Z(ColorPointBY), &Z_Copy }, - { Zuint8, Cx0300, 0x003C, Z(ColorPointBIntensity), &Z_Copy }, - - - { Zuint16, Cx0400, 0x0000, Z(Illuminance), &Z_Copy }, - { Zuint16, Cx0400, 0x0001, Z(IlluminanceMinMeasuredValue), &Z_Copy }, - { Zuint16, Cx0400, 0x0002, Z(IlluminanceMaxMeasuredValue), &Z_Copy }, - { Zuint16, Cx0400, 0x0003, Z(IlluminanceTolerance), &Z_Copy }, - { Zenum8, Cx0400, 0x0004, Z(IlluminanceLightSensorType), &Z_Copy }, - { Zunk, Cx0400, 0xFFFF, nullptr, &Z_Remove }, - - - { Zenum8, Cx0401, 0x0000, Z(IlluminanceLevelStatus), &Z_Copy }, - { Zenum8, Cx0401, 0x0001, Z(IlluminanceLightSensorType), &Z_Copy }, - { Zuint16, Cx0401, 0x0010, Z(IlluminanceTargetLevel), &Z_Copy }, - { Zunk, Cx0401, 0xFFFF, nullptr, &Z_Remove }, - - - { Zint16, Cx0402, 0x0000, Z(Temperature), &Z_FloatDiv100 }, - { Zint16, Cx0402, 0x0001, Z(TemperatureMinMeasuredValue), &Z_FloatDiv100 }, - { Zint16, Cx0402, 0x0002, Z(TemperatureMaxMeasuredValue), &Z_FloatDiv100 }, - { Zuint16, Cx0402, 0x0003, Z(TemperatureTolerance), &Z_FloatDiv100 }, - { Zunk, Cx0402, 0xFFFF, nullptr, &Z_Remove }, - - - { Zunk, Cx0403, 0x0000, Z(PressureUnit), &Z_AddPressureUnit }, - { Zint16, Cx0403, 0x0000, Z(Pressure), &Z_Copy }, - { Zint16, Cx0403, 0x0001, Z(PressureMinMeasuredValue), &Z_Copy }, - { Zint16, Cx0403, 0x0002, Z(PressureMaxMeasuredValue), &Z_Copy }, - { Zuint16, Cx0403, 0x0003, Z(PressureTolerance), &Z_Copy }, - { Zint16, Cx0403, 0x0010, Z(PressureScaledValue), &Z_Copy }, - { Zint16, Cx0403, 0x0011, Z(PressureMinScaledValue), &Z_Copy }, - { Zint16, Cx0403, 0x0012, Z(PressureMaxScaledValue), &Z_Copy }, - { Zuint16, Cx0403, 0x0013, Z(PressureScaledTolerance), &Z_Copy }, - { Zint8, Cx0403, 0x0014, Z(PressureScale), &Z_Copy }, - { Zunk, Cx0403, 0xFFFF, nullptr, &Z_Remove }, - - - { Zuint16, Cx0404, 0x0000, Z(FlowRate), &Z_FloatDiv10 }, - { Zuint16, Cx0404, 0x0001, Z(FlowMinMeasuredValue), &Z_Copy }, - { Zuint16, Cx0404, 0x0002, Z(FlowMaxMeasuredValue), &Z_Copy }, - { Zuint16, Cx0404, 0x0003, Z(FlowTolerance), &Z_Copy }, - { Zunk, Cx0404, 0xFFFF, nullptr, &Z_Remove }, - - - { Zuint16, Cx0405, 0x0000, Z(Humidity), &Z_FloatDiv100 }, - { Zuint16, Cx0405, 0x0001, Z(HumidityMinMeasuredValue), &Z_Copy }, - { Zuint16, Cx0405, 0x0002, Z(HumidityMaxMeasuredValue), &Z_Copy }, - { Zuint16, Cx0405, 0x0003, Z(HumidityTolerance), &Z_Copy }, - { Zunk, Cx0405, 0xFFFF, nullptr, &Z_Remove }, - - - { Zmap8, Cx0406, 0x0000, Z(Occupancy), &Z_Copy }, - { Zenum8, Cx0406, 0x0001, Z(OccupancySensorType), &Z_Copy }, - { Zunk, Cx0406, 0xFFFF, nullptr, &Z_Remove }, - - - { Zstring, Cx0B01, 0x0000, Z(CompanyName), &Z_Copy }, - { Zuint16, Cx0B01, 0x0001, Z(MeterTypeID), &Z_Copy }, - { Zuint16, Cx0B01, 0x0004, Z(DataQualityID), &Z_Copy }, - { Zstring, Cx0B01, 0x0005, Z(CustomerName), &Z_Copy }, - { Zoctstr, Cx0B01, 0x0006, Z(Model), &Z_Copy }, - { Zoctstr, Cx0B01, 0x0007, Z(PartNumber), &Z_Copy }, - { Zoctstr, Cx0B01, 0x0008, Z(ProductRevision), &Z_Copy }, - { Zoctstr, Cx0B01, 0x000A, Z(SoftwareRevision), &Z_Copy }, - { Zstring, Cx0B01, 0x000B, Z(UtilityName), &Z_Copy }, - { Zstring, Cx0B01, 0x000C, Z(POD), &Z_Copy }, - { Zint24, Cx0B01, 0x000D, Z(AvailablePower), &Z_Copy }, - { Zint24, Cx0B01, 0x000E, Z(PowerThreshold), &Z_Copy }, - - - { Zuint16, Cx0B05, 0x0000, Z(NumberOfResets), &Z_Copy }, - { Zuint16, Cx0B05, 0x0001, Z(PersistentMemoryWrites),&Z_Copy }, - { Zuint8, Cx0B05, 0x011C, Z(LastMessageLQI), &Z_Copy }, - { Zuint8, Cx0B05, 0x011D, Z(LastMessageRSSI), &Z_Copy }, - -}; - - - -int32_t Z_ManufKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = value; - zigbee_devices.setManufId(shortaddr, value.as()); - return 1; -} - -int32_t Z_ModelKeep(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = value; - zigbee_devices.setModelId(shortaddr, value.as()); - return 1; -} - - - -int32_t Z_Remove(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - return 1; -} - - -int32_t Z_Copy(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = value; - return 1; -} - - -int32_t Z_AddPressureUnit(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = F(D_UNIT_PRESSURE); - return 0; -} - - -int32_t Z_FloatDiv100(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = ((float)value) / 100.0f; - return 1; -} - -int32_t Z_FloatDiv10(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = ((float)value) / 10.0f; - return 1; -} - -int32_t Z_FloatDiv2(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = ((float)value) / 2.0f; - return 1; -} - - -int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json[F(OCCUPANCY)] = 0; - zigbee_devices.jsonPublishNow(shortaddr, json); -} - - -int32_t Z_AqaraCube(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - json[new_name] = value; - int32_t val = value; - const __FlashStringHelper *aqara_cube = F("AqaraCube"); - const __FlashStringHelper *aqara_cube_side = F("AqaraCubeSide"); - const __FlashStringHelper *aqara_cube_from_side = F("AqaraCubeFromSide"); - - switch (val) { - case 0: - json[aqara_cube] = F("shake"); - break; - case 2: - json[aqara_cube] = F("wakeup"); - break; - case 3: - json[aqara_cube] = F("fall"); - break; - case 64 ... 127: - json[aqara_cube] = F("flip90"); - json[aqara_cube_side] = val % 8; - json[aqara_cube_from_side] = (val - 64) / 8; - break; - case 128 ... 132: - json[aqara_cube] = F("flip180"); - json[aqara_cube_side] = val - 128; - break; - case 256 ... 261: - json[aqara_cube] = F("slide"); - json[aqara_cube_side] = val - 256; - break; - case 512 ... 517: - json[aqara_cube] = F("tap"); - json[aqara_cube_side] = val - 512; - break; - } -# 1154 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_5_converters.ino" - return 1; -} - - -int32_t Z_AqaraVibration(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - - switch (attr) { - case 0x0055: - { - int32_t ivalue = value; - const __FlashStringHelper * svalue; - switch (ivalue) { - case 1: svalue = F("vibrate"); break; - case 2: svalue = F("tilt"); break; - case 3: svalue = F("drop"); break; - default: svalue = F("unknown"); break; - } - json[new_name] = svalue; - } - break; - - - - - case 0x0508: - { - - - String hex = value; - SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length()); - int16_t x, y, z; - z = buf2.get16(0); - y = buf2.get16(2); - x = buf2.get16(4); - JsonArray& xyz = json.createNestedArray(new_name); - xyz.add(x); - xyz.add(y); - xyz.add(z); - - float X = x; - float Y = y; - float Z = z; - int32_t Angle_X = 0.5f + atanf(X/sqrtf(z*z+y*y)) * f_180pi; - int32_t Angle_Y = 0.5f + atanf(Y/sqrtf(x*x+z*z)) * f_180pi; - int32_t Angle_Z = 0.5f + atanf(Z/sqrtf(x*x+y*y)) * f_180pi; - JsonArray& angles = json.createNestedArray(F("AqaraAngles")); - angles.add(Angle_X); - angles.add(Angle_Y); - angles.add(Angle_Z); - } - break; - } - return 1; -} - -int32_t Z_AqaraSensor(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr) { - String hex = value; - SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length()); - uint32_t i = 0; - uint32_t len = buf2.len(); - char tmp[] = "tmp"; - - JsonVariant sub_value; - const char * modelId_c = zigbee_devices.getModelId(shortaddr); - String modelId((char*) modelId_c); - - while (len - i >= 2) { - uint8_t attrid = buf2.get8(i++); - - i += parseSingleAttribute(json, tmp, buf2, i, len); - float val = json[tmp]; - json.remove(tmp); - bool translated = false; - if (0x01 == attrid) { - json[F(D_JSON_VOLTAGE)] = val / 1000.0f; - json[F("Battery")] = toPercentageCR2032(val); - } else if ((nullptr != modelId) && (0 == zcl->getManufCode())) { - translated = true; - if (modelId.startsWith(F("lumi.sensor_ht")) || - modelId.startsWith(F("lumi.weather"))) { - - - if (0x64 == attrid) { - json[F(D_JSON_TEMPERATURE)] = val / 100.0f; - } else if (0x65 == attrid) { - json[F(D_JSON_HUMIDITY)] = val / 100.0f; - } else if (0x66 == attrid) { - json[F(D_JSON_PRESSURE)] = val / 100.0f; - json[F(D_JSON_PRESSURE_UNIT)] = F(D_UNIT_PRESSURE); - } - } else if (modelId.startsWith(F("lumi.sensor_smoke"))) { - if (0x64 == attrid) { - json[F("SmokeDensity")] = val; - } - } else if (modelId.startsWith(F("lumi.sensor_natgas"))) { - if (0x64 == attrid) { - json[F("GasDensity")] = val; - } - } else { - translated = false; - } - - } - if (!translated) { - if (attrid >= 100) { - char attr_name[12]; - snprintf_P(attr_name, sizeof(attr_name), PSTR("Xiaomi_%02X"), attrid); - json[attr_name] = val; - } - } - } - return 1; -} - - -void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) { - - for (auto kv : json) { - String key_string = kv.key; - const char * key = key_string.c_str(); - JsonVariant& value = kv.value; - - char * delimiter = strchr(key, '/'); - char * delimiter2 = strchr(key, '+'); - if (delimiter) { - uint16_t attribute; - uint16_t suffix = 1; - uint16_t cluster = strtoul(key, &delimiter, 16); - if (!delimiter2) { - attribute = strtoul(delimiter+1, nullptr, 16); - } else { - attribute = strtoul(delimiter+1, &delimiter2, 16); - suffix = strtoul(delimiter2+1, nullptr, 10); - } - - - if ((cluster == 0x0006) && ((attribute == 0x0000) || (attribute == 0x8000))) { - bool power = value; - zigbee_devices.updateHueState(shortaddr, &power, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr); - } else if ((cluster == 0x0008) && (attribute == 0x0000)) { - uint8_t dimmer = value; - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, &dimmer, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr); - } else if ((cluster == 0x0300) && (attribute == 0x0000)) { - uint16_t hue8 = value; - uint16_t hue = changeUIntScale(hue8, 0, 254, 0, 360); - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr, - nullptr, &hue, nullptr, nullptr, nullptr); - } else if ((cluster == 0x0300) && (attribute == 0x0001)) { - uint8_t sat = value; - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, &sat, - nullptr, nullptr, nullptr, nullptr, nullptr); - } else if ((cluster == 0x0300) && (attribute == 0x0003)) { - uint16_t x = value; - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, &x, nullptr, nullptr); - } else if ((cluster == 0x0300) && (attribute == 0x0004)) { - uint16_t y = value; - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, &y, nullptr), nullptr; - } else if ((cluster == 0x0300) && (attribute == 0x0007)) { - uint16_t ct = value; - zigbee_devices.updateHueState(shortaddr, nullptr, nullptr, nullptr, nullptr, - &ct, nullptr, nullptr, nullptr, nullptr); - } else if ((cluster == 0x0300) && (attribute == 0x0008)) { - uint8_t colormode = value; - zigbee_devices.updateHueState(shortaddr, nullptr, &colormode, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr); - } - - - for (uint32_t i = 0; i < sizeof(Z_PostProcess) / sizeof(Z_PostProcess[0]); i++) { - const Z_AttributeConverter *converter = &Z_PostProcess[i]; - uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); - uint16_t conv_attribute = pgm_read_word(&converter->attribute); - - if ((conv_cluster == cluster) && - ((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) { - String new_name_str = (const __FlashStringHelper*) converter->name; - if (suffix > 1) { new_name_str += suffix; } - int32_t drop = (*converter->func)(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute); - if (drop) { - json.remove(key); - } - - } - } - } - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_6_commands.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_6_commands.ino" -#ifdef USE_ZIGBEE - - - - - -typedef struct Z_CommandConverter { - const char * tasmota_cmd; - uint16_t cluster; - uint8_t cmd; - uint8_t direction; - const char * param; -} Z_CommandConverter; - -typedef struct Z_XYZ_Var { - uint32_t x = 0; - uint32_t y = 0; - uint32_t z = 0; - uint8_t x_type = 0; - uint8_t y_type = 0; - uint8_t z_type = 0; -} Z_XYZ_Var; - -ZF(AddGroup) ZF(ViewGroup) ZF(GetGroup) ZF(GetAllGroups) ZF(RemoveGroup) ZF(RemoveAllGroups) -ZF(AddScene) ZF(ViewScene) ZF(RemoveScene) ZF(RemoveAllScenes) ZF(RecallScene) ZF(StoreScene) ZF(GetSceneMembership) - -ZF(DimmerUp) ZF(DimmerDown) ZF(DimmerStop) -ZF(ResetAlarm) ZF(ResetAllAlarms) - -ZF(HueSat) ZF(Color) -ZF(ShutterOpen) ZF(ShutterClose) ZF(ShutterStop) ZF(ShutterLift) ZF(ShutterTilt) ZF(Shutter) - -ZF(DimmerMove) ZF(DimmerStep) -ZF(HueMove) ZF(HueStep) ZF(SatMove) ZF(SatStep) ZF(ColorMove) ZF(ColorStep) -ZF(ArrowClick) ZF(ArrowHold) ZF(ArrowRelease) ZF(ZoneStatusChange) - -ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(00190200) ZF(01190200) ZF(xxyyyy) ZF(xx) -ZF(xx000A00) ZF(xx0A00) ZF(xxyy0A00) ZF(xxxxyyyy0A00) ZF(xxxx0A00) ZF(xx0A) -ZF(xx190A00) ZF(xx19) ZF(xx190A) ZF(xxxxyyyy) ZF(xxxxyyzz) ZF(xxyyzzzz) ZF(xxyyyyzz) -# 67 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_6_commands.ino" -const Z_CommandConverter Z_Commands[] PROGMEM = { - - { Z(AddGroup), 0x0004, 0x00, 0x01, Z(xxxx00) }, - { Z(ViewGroup), 0x0004, 0x01, 0x01, Z(xxxx) }, - { Z(GetGroup), 0x0004, 0x02, 0x01, Z(01xxxx) }, - { Z(GetAllGroups), 0x0004, 0x02, 0x01, Z(00) }, - { Z(RemoveGroup), 0x0004, 0x03, 0x01, Z(xxxx) }, - { Z(RemoveAllGroups),0x0004, 0x04, 0x01, Z() }, - - - { Z(ViewScene), 0x0005, 0x01, 0x01, Z(xxxxyy) }, - { Z(RemoveScene), 0x0005, 0x02, 0x01, Z(xxxxyy) }, - { Z(RemoveAllScenes),0x0005, 0x03, 0x01, Z(xxxx) }, - { Z(RecallScene), 0x0005, 0x05, 0x01, Z(xxxxyy) }, - { Z(GetSceneMembership),0x0005, 0x06, 0x01, Z(xxxx) }, - - { Z(Power), 0x0006, 0xFF, 0x01, Z() }, - { Z(Dimmer), 0x0008, 0x04, 0x01, Z(xx0A00) }, - { Z(DimmerUp), 0x0008, 0x06, 0x01, Z(00190200) }, - { Z(DimmerDown), 0x0008, 0x06, 0x01, Z(01190200) }, - { Z(DimmerStop), 0x0008, 0x03, 0x01, Z() }, - { Z(ResetAlarm), 0x0009, 0x00, 0x01, Z(xxyyyy) }, - { Z(ResetAllAlarms), 0x0009, 0x01, 0x01, Z() }, - { Z(Hue), 0x0300, 0x00, 0x01, Z(xx000A00) }, - { Z(Sat), 0x0300, 0x03, 0x01, Z(xx0A00) }, - { Z(HueSat), 0x0300, 0x06, 0x01, Z(xxyy0A00) }, - { Z(Color), 0x0300, 0x07, 0x01, Z(xxxxyyyy0A00) }, - { Z(CT), 0x0300, 0x0A, 0x01, Z(xxxx0A00) }, - { Z(ShutterOpen), 0x0102, 0x00, 0x01, Z() }, - { Z(ShutterClose), 0x0102, 0x01, 0x01, Z() }, - { Z(ShutterStop), 0x0102, 0x02, 0x01, Z() }, - { Z(ShutterLift), 0x0102, 0x05, 0x01, Z(xx) }, - { Z(ShutterTilt), 0x0102, 0x08, 0x01, Z(xx) }, - { Z(Shutter), 0x0102, 0xFF, 0x01, Z() }, - - { Z(Occupancy), 0xEF00, 0x01, 0x82, Z()}, - - { Z(Dimmer), 0x0008, 0x00, 0x01, Z(xx) }, - { Z(DimmerMove), 0x0008, 0x01, 0x01, Z(xx0A) }, - { Z(DimmerStep), 0x0008, 0x02, 0x01, Z(xx190A00) }, - { Z(DimmerMove), 0x0008, 0x05, 0x01, Z(xx0A) }, - { Z(DimmerUp), 0x0008, 0x06, 0x01, Z(00) }, - { Z(DimmerDown), 0x0008, 0x06, 0x01, Z(01) }, - { Z(DimmerStop), 0x0008, 0x07, 0x01, Z() }, - { Z(HueMove), 0x0300, 0x01, 0x01, Z(xx19) }, - { Z(HueStep), 0x0300, 0x02, 0x01, Z(xx190A00) }, - { Z(SatMove), 0x0300, 0x04, 0x01, Z(xx19) }, - { Z(SatStep), 0x0300, 0x05, 0x01, Z(xx190A) }, - { Z(ColorMove), 0x0300, 0x08, 0x01, Z(xxxxyyyy) }, - { Z(ColorStep), 0x0300, 0x09, 0x01, Z(xxxxyyyy0A00) }, - - { Z(ArrowClick), 0x0005, 0x07, 0x01, Z(xx) }, - { Z(ArrowHold), 0x0005, 0x08, 0x01, Z(xx) }, - { Z(ArrowRelease), 0x0005, 0x09, 0x01, Z() }, - - { Z(ZoneStatusChange),0x0500, 0x00, 0x82, Z(xxxxyyzz) }, - - { Z(AddGroup), 0x0004, 0x00, 0x82, Z(xxyyyy) }, - { Z(ViewGroup), 0x0004, 0x01, 0x82, Z(xxyyyy) }, - { Z(GetGroup), 0x0004, 0x02, 0x82, Z(xxyyzzzz) }, - { Z(RemoveGroup), 0x0004, 0x03, 0x82, Z(xxyyyy) }, - - { Z(AddScene), 0x0005, 0x00, 0x82, Z(xxyyyyzz) }, - { Z(ViewScene), 0x0005, 0x01, 0x82, Z(xxyyyyzz) }, - { Z(RemoveScene), 0x0005, 0x02, 0x82, Z(xxyyyyzz) }, - { Z(RemoveAllScenes),0x0005, 0x03, 0x82, Z(xxyyyy) }, - { Z(StoreScene), 0x0005, 0x04, 0x82, Z(xxyyyyzz) }, - { Z(GetSceneMembership),0x0005, 0x06, 0x82,Z(xxyyzzzz) }, -}; - - - - -#define ZLE(x) ((x) & 0xFF), ((x) >> 8) - - -const uint8_t CLUSTER_0006[] = { ZLE(0x0000) }; -const uint8_t CLUSTER_0008[] = { ZLE(0x0000) }; -const uint8_t CLUSTER_0009[] = { ZLE(0x0000) }; -const uint8_t CLUSTER_0300[] = { ZLE(0x0000), ZLE(0x0001), ZLE(0x0003), ZLE(0x0004), ZLE(0x0007), ZLE(0x0008) }; - - -int32_t Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - size_t attrs_len = 0; - const uint8_t* attrs = nullptr; - - switch (cluster) { - case 0x0006: - attrs = CLUSTER_0006; - attrs_len = sizeof(CLUSTER_0006); - break; - case 0x0008: - attrs = CLUSTER_0008; - attrs_len = sizeof(CLUSTER_0008); - break; - case 0x0009: - attrs = CLUSTER_0009; - attrs_len = sizeof(CLUSTER_0009); - break; - case 0x0300: - attrs = CLUSTER_0300; - attrs_len = sizeof(CLUSTER_0300); - break; - } - if (attrs) { - ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, ZCL_READ_ATTRIBUTES, false, 0, attrs, attrs_len, true , zigbee_devices.getNextSeqNumber(shortaddr)); - } -} - - - -int32_t Z_Unreachable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - if (shortaddr) { - zigbee_devices.setReachable(shortaddr, false); - } -} - - -void zigbeeSetCommandTimer(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint) { - uint32_t wait_ms = 0; - - switch (cluster) { - case 0x0006: - case 0x0009: - wait_ms = 200; - break; - case 0x0008: - case 0x0300: - wait_ms = 1050; - break; - case 0x0102: - wait_ms = 10000; - break; - } - if (wait_ms) { - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, Z_CAT_NONE, 0 , &Z_ReadAttrCallback); - if (shortaddr) { - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 , &Z_Unreachable); - } - } -} - - -inline bool isXYZ(char c) { - return (c >= 'x') && (c <= 'z'); -} - - - - -inline int8_t hexValue(char c) { - if ((c >= '0') && (c <= '9')) { - return c - '0'; - } - if ((c >= 'A') && (c <= 'F')) { - return 10 + c - 'A'; - } - if ((c >= 'a') && (c <= 'f')) { - return 10 + c - 'a'; - } - return -1; -} - - -uint32_t parseHex_P(const char **data, size_t max_len = 8) { - uint32_t ret = 0; - for (uint32_t i = 0; i < max_len; i++) { - int8_t v = hexValue(pgm_read_byte(*data)); - if (v < 0) { break; } - ret = (ret << 4) | v; - *data += 1; - } - return ret; -} - - - - - -void parseXYZ(const char *model, const SBuffer &payload, struct Z_XYZ_Var *xyz) { - const char *p = model; - uint32_t v = 0; - char c = pgm_read_byte(p); - while (c) { - char c1 = pgm_read_byte(p+1); - if (!c1) { break; } - if (isXYZ(c) && (c == c1) && (v < payload.len())) { - uint8_t val = payload.get8(v); - switch (c) { - case 'x': - xyz->x = xyz->x | (val << (xyz->x_type * 8)); - xyz->x_type++; - break; - case 'y': - xyz->y = xyz->y | (val << (xyz->y_type * 8)); - xyz->y_type++; - break; - case 'z': - xyz->z = xyz->z | (val << (xyz->z_type * 8)); - xyz->z_type++; - break; - } - } - p += 2; - v++; - c = pgm_read_byte(p); - } -} - - - - - - -void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t cmd, bool direction) { - if (direction) { return; } - - int32_t z_cat = -1; - uint32_t wait_ms = 0; - - switch (cluster) { - case 0x0006: - z_cat = Z_CAT_READ_0006; - wait_ms = 200; - break; - case 0x0008: - z_cat = Z_CAT_READ_0008; - wait_ms = 1050; - break; - case 0x0102: - z_cat = Z_CAT_READ_0102; - wait_ms = 10000; - break; - case 0x0300: - z_cat = Z_CAT_READ_0300; - wait_ms = 1050; - break; - default: - break; - } - if (z_cat >= 0) { - uint8_t endpoint = 0; - if (shortaddr) { - endpoint = zigbee_devices.findFirstEndpoint(shortaddr); - } - if ((!shortaddr) || (endpoint)) { - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, z_cat, 0 , &Z_ReadAttrCallback); - if (shortaddr) { - zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 , &Z_Unreachable); - } - - } - } -} - - - -void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, bool direction, const SBuffer &payload) { - size_t hex_char_len = payload.len()*2+2; - char *hex_char = (char*) malloc(hex_char_len); - if (!hex_char) { return; } - ToHex_P((unsigned char*)payload.getBuffer(), payload.len(), hex_char, hex_char_len); - - const __FlashStringHelper* command_name = nullptr; - uint8_t conv_direction; - Z_XYZ_Var xyz; - - - for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) { - const Z_CommandConverter *conv = &Z_Commands[i]; - uint16_t conv_cluster = pgm_read_word(&conv->cluster); - if (conv_cluster == cluster) { - - uint8_t conv_cmd = pgm_read_byte(&conv->cmd); - conv_direction = pgm_read_byte(&conv->direction); - if ((0xFF == conv_cmd) || (cmd == conv_cmd)) { - - if ((direction && (conv_direction & 0x02)) || (!direction && (conv_direction & 0x01))) { - - - - - const char * p = conv->param; - - bool match = true; - for (uint8_t i = 0; i < payload.len(); i++) { - const char c1 = pgm_read_byte(p); - const char c2 = pgm_read_byte(p+1); - - if ((0x00 == c1) || isXYZ(c1)) { - break; - } - const char * p2 = p; - uint32_t nextbyte = parseHex_P(&p2, 2); - - if (nextbyte != payload.get8(i)) { - match = false; - break; - } - p += 2; - } - if (match) { - command_name = (const __FlashStringHelper*) conv->tasmota_cmd; - parseXYZ(conv->param, payload, &xyz); - if (0xFF == conv_cmd) { - - xyz.z = xyz.y; - xyz.z_type = xyz.y_type; - xyz.y = xyz.x; - xyz.y_type = xyz.x_type; - xyz.x = cmd; - xyz.x_type = 1; - } - break; - } - } - } - } - } - - - - - char attrid_str[12]; - snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X%c%02X"), cluster, direction ? '<' : '!', cmd); - json[attrid_str] = hex_char; - free(hex_char); - - if (command_name) { - - - if (conv_direction & 0x80) { - - - String command_name2 = String(command_name); - if ((cluster == 0x0500) && (cmd == 0x00)) { - - json[command_name] = xyz.x; - json[command_name2 + F("Ext")] = xyz.y; - json[command_name2 + F("Zone")] = xyz.z; - } else if ((cluster == 0x0004) && ((cmd == 0x00) || (cmd == 0x01) || (cmd == 0x03))) { - - json[command_name] = xyz.y; - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - } else if ((cluster == 0x0004) && (cmd == 0x02)) { - - json[command_name2 + F("Capacity")] = xyz.x; - json[command_name2 + F("Count")] = xyz.y; - JsonArray &arr = json.createNestedArray(command_name); - for (uint32_t i = 0; i < xyz.y; i++) { - arr.add(payload.get16(2 + 2*i)); - } - } else if ((cluster == 0x0005) && ((cmd == 0x00) || (cmd == 0x02) || (cmd == 0x03))) { - - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("GroupId")] = xyz.y; - json[F("SceneId")] = xyz.z; - } else if ((cluster == 0x0005) && (cmd == 0x01)) { - - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("GroupId")] = xyz.y; - json[F("SceneId")] = xyz.z; - String scene_payload = json[attrid_str]; - json[F("ScenePayload")] = scene_payload.substring(8); - } else if ((cluster == 0x0005) && (cmd == 0x03)) { - - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("GroupId")] = xyz.y; - } else if ((cluster == 0x0005) && (cmd == 0x06)) { - - json[command_name2 + F("Status")] = xyz.x; - json[command_name2 + F("StatusMsg")] = getZigbeeStatusMessage(xyz.x); - json[F("Capacity")] = xyz.y; - json[F("GroupId")] = xyz.z; - String scene_payload = json[attrid_str]; - json[F("ScenePayload")] = scene_payload.substring(8); - } - } else { - if (0 == xyz.x_type) { - json[command_name] = true; - } else if (0 == xyz.y_type) { - json[command_name] = xyz.x; - } else { - - JsonArray &arr = json.createNestedArray(command_name); - arr.add(xyz.x); - arr.add(xyz.y); - if (xyz.z_type) { - arr.add(xyz.z); - } - } - } - } -} - - - - - -const __FlashStringHelper* zigbeeFindCommand(const char *command, uint16_t *cluster, uint16_t *cmd) { - for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) { - const Z_CommandConverter *conv = &Z_Commands[i]; - uint8_t conv_direction = pgm_read_byte(&conv->direction); - uint8_t conv_cmd = pgm_read_byte(&conv->cmd); - uint16_t conv_cluster = pgm_read_word(&conv->cluster); - if ((conv_direction & 0x01) && (0 == strcasecmp_P(command, conv->tasmota_cmd))) { - *cluster = conv_cluster; - *cmd = conv_cmd; - return (const __FlashStringHelper*) conv->param; - } - } - - return nullptr; -} - - -inline char hexDigit(uint32_t h) { - uint32_t nybble = h & 0x0F; - return (nybble > 9) ? 'A' - 10 + nybble : '0' + nybble; -} - - -String zigbeeCmdAddParams(const char *zcl_cmd_P, uint32_t x, uint32_t y, uint32_t z) { - size_t len = strlen_P(zcl_cmd_P); - char zcl_cmd[len+1]; - strcpy_P(zcl_cmd, zcl_cmd_P); - - char *p = zcl_cmd; - while (*p) { - if (isXYZ(*p) && (*p == *(p+1))) { - uint8_t val; - switch (*p) { - case 'x': - val = x & 0xFF; - x = x >> 8; - break; - case 'y': - val = y & 0xFF; - y = y >> 8; - break; - case 'z': - val = z & 0xFF; - z = z >> 8; - break; - } - *p = hexDigit(val >> 4); - *(p+1) = hexDigit(val); - p++; - } - p++; - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SendZCLCommand_P: zcl_cmd = %s"), zcl_cmd); - - return String(zcl_cmd); -} - -const char kZ_Alias[] PROGMEM = "OFF|" D_OFF "|" D_FALSE "|" D_STOP "|" "OPEN" "|" - "ON|" D_ON "|" D_TRUE "|" D_START "|" "CLOSE" "|" - "TOGGLE|" D_TOGGLE "|" - "ALL" ; - -const uint8_t kZ_Numbers[] PROGMEM = { 0,0,0,0,0, - 1,1,1,1,1, - 2,2, - 255 }; - - -uint32_t ZigbeeAliasOrNumber(const char *state_text) { - char command[16]; - int state_number = GetCommandCode(command, sizeof(command), state_text, kZ_Alias); - if (state_number >= 0) { - - return pgm_read_byte(kZ_Numbers + state_number); - } else { - - return strtoul(state_text, nullptr, 0); - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_7_statemachine.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_7_statemachine.ino" -#ifdef USE_ZIGBEE - - - -const uint8_t ZIGBEE_STATUS_OK = 0; -const uint8_t ZIGBEE_STATUS_BOOT = 1; -const uint8_t ZIGBEE_STATUS_RESET_CONF = 2; -const uint8_t ZIGBEE_STATUS_STARTING = 3; -const uint8_t ZIGBEE_STATUS_PERMITJOIN_CLOSE = 20; -const uint8_t ZIGBEE_STATUS_PERMITJOIN_OPEN_60 = 21; -const uint8_t ZIGBEE_STATUS_PERMITJOIN_OPEN_XX = 22; -const uint8_t ZIGBEE_STATUS_DEVICE_ANNOUNCE = 30; -const uint8_t ZIGBEE_STATUS_NODE_DESC = 31; -const uint8_t ZIGBEE_STATUS_ACTIVE_EP = 32; -const uint8_t ZIGBEE_STATUS_SIMPLE_DESC = 33; -const uint8_t ZIGBEE_STATUS_DEVICE_INDICATION = 34; -const uint8_t ZIGBEE_STATUS_CC_VERSION = 50; -const uint8_t ZIGBEE_STATUS_CC_INFO = 51; -const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; -const uint8_t ZIGBEE_STATUS_ABORT = 99; - -typedef int32_t (*ZB_Func)(uint8_t value); -typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const class SBuffer &buf); - -typedef union Zigbee_Instruction { - struct { - uint8_t i; - uint8_t d8; - uint16_t d16; - } i; - const void *p; -} Zigbee_Instruction; - -typedef struct Zigbee_Instruction_Type { - uint8_t instr; - uint8_t data; -} Zigbee_Instruction_Type; - -enum Zigbee_StateMachine_Instruction_Set { - - ZGB_INSTR_4_BYTES = 0, - ZGB_INSTR_NOOP = 0, - ZGB_INSTR_LABEL, - ZGB_INSTR_GOTO, - ZGB_INSTR_ON_ERROR_GOTO, - ZGB_INSTR_ON_TIMEOUT_GOTO, - ZGB_INSTR_WAIT, - ZGB_INSTR_WAIT_FOREVER, - ZGB_INSTR_STOP, - - - ZGB_INSTR_8_BYTES = 0x80, - ZGB_INSTR_CALL = 0x80, - ZGB_INSTR_LOG, - ZGB_INSTR_MQTT_STATE, - ZGB_INSTR_SEND, - ZGB_INSTR_WAIT_UNTIL, - ZGB_INSTR_WAIT_RECV, - ZGB_ON_RECV_UNEXPECTED, - - - ZGB_INSTR_12_BYTES = 0xF0, - ZGB_INSTR_WAIT_RECV_CALL, -}; - -#define ZI_NOOP() { .i = { ZGB_INSTR_NOOP, 0x00, 0x0000} }, -#define ZI_LABEL(x) { .i = { ZGB_INSTR_LABEL, (x), 0x0000} }, -#define ZI_GOTO(x) { .i = { ZGB_INSTR_GOTO, (x), 0x0000} }, -#define ZI_ON_ERROR_GOTO(x) { .i = { ZGB_INSTR_ON_ERROR_GOTO, (x), 0x0000} }, -#define ZI_ON_TIMEOUT_GOTO(x) { .i = { ZGB_INSTR_ON_TIMEOUT_GOTO, (x), 0x0000} }, -#define ZI_WAIT(x) { .i = { ZGB_INSTR_WAIT, 0x00, (x)} }, -#define ZI_WAIT_FOREVER() { .i = { ZGB_INSTR_WAIT_FOREVER, 0x00, 0x0000} }, -#define ZI_STOP(x) { .i = { ZGB_INSTR_STOP, (x), 0x0000} }, - -#define ZI_CALL(f,x) { .i = { ZGB_INSTR_CALL, (x), 0x0000} }, { .p = (const void*)(f) }, -#define ZI_LOG(x,m) { .i = { ZGB_INSTR_LOG, (x), 0x0000 } }, { .p = ((const void*)(m)) }, -#define ZI_MQTT_STATE(x,m) { .i = { ZGB_INSTR_MQTT_STATE, (x), 0x0000 } }, { .p = ((const void*)(m)) }, -#define ZI_ON_RECV_UNEXPECTED(f) { .i = { ZGB_ON_RECV_UNEXPECTED, 0x00, 0x0000} }, { .p = (const void*)(f) }, -#define ZI_SEND(m) { .i = { ZGB_INSTR_SEND, sizeof(m), 0x0000} }, { .p = (const void*)(m) }, -#define ZI_WAIT_RECV(x,m) { .i = { ZGB_INSTR_WAIT_RECV, sizeof(m), (x)} }, { .p = (const void*)(m) }, -#define ZI_WAIT_UNTIL(x,m) { .i = { ZGB_INSTR_WAIT_UNTIL, sizeof(m), (x)} }, { .p = (const void*)(m) }, -#define ZI_WAIT_RECV_FUNC(x,m,f) { .i = { ZGB_INSTR_WAIT_RECV_CALL, sizeof(m), (x)} }, { .p = (const void*)(m) }, { .p = (const void*)(f) }, - - -const uint8_t ZIGBEE_LABEL_START = 10; -const uint8_t ZIGBEE_LABEL_READY = 20; -const uint8_t ZIGBEE_LABEL_MAIN_LOOP = 21; -const uint8_t ZIGBEE_LABEL_PERMIT_JOIN_CLOSE = 30; -const uint8_t ZIGBEE_LABEL_PERMIT_JOIN_OPEN_60 = 31; -const uint8_t ZIGBEE_LABEL_PERMIT_JOIN_OPEN_XX = 32; - -const uint8_t ZIGBEE_LABEL_ABORT = 99; -const uint8_t ZIGBEE_LABEL_UNSUPPORTED_VERSION = 98; - -struct ZigbeeStatus { - bool active = true; - bool state_machine = false; - bool state_waiting = false; - bool state_no_timeout = false; - bool ready = false; - uint8_t on_error_goto = ZIGBEE_LABEL_ABORT; - uint8_t on_timeout_goto = ZIGBEE_LABEL_ABORT; - int16_t pc = 0; - uint32_t next_timeout = 0; - - uint8_t *recv_filter = nullptr; - bool recv_until = false; - size_t recv_filter_len = 0; - ZB_RecvMsgFunc recv_func = nullptr; - ZB_RecvMsgFunc recv_unexpected = nullptr; - - bool init_phase = true; -}; -struct ZigbeeStatus zigbee; - -SBuffer *zigbee_buffer = nullptr; - - - - - -#define Z_B0(a) (uint8_t)( ((a) ) & 0xFF ) -#define Z_B1(a) (uint8_t)( ((a) >> 8) & 0xFF ) -#define Z_B2(a) (uint8_t)( ((a) >> 16) & 0xFF ) -#define Z_B3(a) (uint8_t)( ((a) >> 24) & 0xFF ) -#define Z_B4(a) (uint8_t)( ((a) >> 32) & 0xFF ) -#define Z_B5(a) (uint8_t)( ((a) >> 40) & 0xFF ) -#define Z_B6(a) (uint8_t)( ((a) >> 48) & 0xFF ) -#define Z_B7(a) (uint8_t)( ((a) >> 56) & 0xFF ) - -#define ZBM(n,x...) const uint8_t n[] PROGMEM = { x }; - -#define ZBR(n,x...) uint8_t n[] = { x }; -#define ZBW(n,x...) { const uint8_t n ##t[] = { x }; memcpy(n, n ##t, sizeof(n)); } - -#define USE_ZIGBEE_CHANNEL_MASK (1 << (USE_ZIGBEE_CHANNEL)) - - - -ZBM(ZBS_RESET, Z_AREQ | Z_SYS, SYS_RESET, 0x00 ) -ZBM(ZBR_RESET, Z_AREQ | Z_SYS, SYS_RESET_IND ) - -ZBM(ZBS_VERSION, Z_SREQ | Z_SYS, SYS_VERSION ) -ZBM(ZBR_VERSION, Z_SRSP | Z_SYS, SYS_VERSION ) - - -ZBM(ZBS_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_READ, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8, 0x00 ) -ZBM(ZBR_ZNPHC, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS, 0x01 , 0x55) - - -ZBM(ZBS_PAN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PANID ) -ZBR(ZBR_PAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PANID, 0x02 , - Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID) ) - -ZBM(ZBS_EXTPAN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_EXTENDED_PAN_ID ) -ZBR(ZBR_EXTPAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_EXTENDED_PAN_ID, - 0x08 , - Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), - Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID), - ) - -ZBM(ZBS_CHANN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_CHANLIST ) -ZBR(ZBR_CHANN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_CHANLIST, - 0x04 , - Z_B0(USE_ZIGBEE_CHANNEL_MASK), Z_B1(USE_ZIGBEE_CHANNEL_MASK), Z_B2(USE_ZIGBEE_CHANNEL_MASK), Z_B3(USE_ZIGBEE_CHANNEL_MASK), - ) - -ZBM(ZBS_PFGK, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PRECFGKEY ) -ZBR(ZBR_PFGK, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PRECFGKEY, - 0x10 , - Z_B0(USE_ZIGBEE_PRECFGKEY_L), Z_B1(USE_ZIGBEE_PRECFGKEY_L), Z_B2(USE_ZIGBEE_PRECFGKEY_L), Z_B3(USE_ZIGBEE_PRECFGKEY_L), - Z_B4(USE_ZIGBEE_PRECFGKEY_L), Z_B5(USE_ZIGBEE_PRECFGKEY_L), Z_B6(USE_ZIGBEE_PRECFGKEY_L), Z_B7(USE_ZIGBEE_PRECFGKEY_L), - Z_B0(USE_ZIGBEE_PRECFGKEY_H), Z_B1(USE_ZIGBEE_PRECFGKEY_H), Z_B2(USE_ZIGBEE_PRECFGKEY_H), Z_B3(USE_ZIGBEE_PRECFGKEY_H), - Z_B4(USE_ZIGBEE_PRECFGKEY_H), Z_B5(USE_ZIGBEE_PRECFGKEY_H), Z_B6(USE_ZIGBEE_PRECFGKEY_H), Z_B7(USE_ZIGBEE_PRECFGKEY_H), - - ) - -ZBM(ZBS_PFGKEN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PRECFGKEYS_ENABLE ) -ZBM(ZBR_PFGKEN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PRECFGKEYS_ENABLE, - 0x01 , 0x00 ) - - - -ZBM(ZBR_W_OK, Z_SRSP | Z_SAPI, SAPI_WRITE_CONFIGURATION, Z_SUCCESS ) -ZBM(ZBR_WNV_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_WRITE, Z_SUCCESS ) - - -ZBM(ZBS_FACTRES, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 , 0x02 ) - -ZBR(ZBS_W_PAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PANID, 0x02 , Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID) ) - -ZBR(ZBS_W_EXTPAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_EXTENDED_PAN_ID, 0x08 , - Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), - Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID) - ) - -ZBR(ZBS_W_CHANN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_CHANLIST, 0x04 , - Z_B0(USE_ZIGBEE_CHANNEL_MASK), Z_B1(USE_ZIGBEE_CHANNEL_MASK), Z_B2(USE_ZIGBEE_CHANNEL_MASK), Z_B3(USE_ZIGBEE_CHANNEL_MASK), - ) - -ZBM(ZBS_W_LOGTYP, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_LOGICAL_TYPE, 0x01 , 0x00 ) - -ZBR(ZBS_W_PFGK, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PRECFGKEY, - 0x10 , - Z_B0(USE_ZIGBEE_PRECFGKEY_L), Z_B1(USE_ZIGBEE_PRECFGKEY_L), Z_B2(USE_ZIGBEE_PRECFGKEY_L), Z_B3(USE_ZIGBEE_PRECFGKEY_L), - Z_B4(USE_ZIGBEE_PRECFGKEY_L), Z_B5(USE_ZIGBEE_PRECFGKEY_L), Z_B6(USE_ZIGBEE_PRECFGKEY_L), Z_B7(USE_ZIGBEE_PRECFGKEY_L), - Z_B0(USE_ZIGBEE_PRECFGKEY_H), Z_B1(USE_ZIGBEE_PRECFGKEY_H), Z_B2(USE_ZIGBEE_PRECFGKEY_H), Z_B3(USE_ZIGBEE_PRECFGKEY_H), - Z_B4(USE_ZIGBEE_PRECFGKEY_H), Z_B5(USE_ZIGBEE_PRECFGKEY_H), Z_B6(USE_ZIGBEE_PRECFGKEY_H), Z_B7(USE_ZIGBEE_PRECFGKEY_H), - - ) - -ZBM(ZBS_W_PFGKEN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PRECFGKEYS_ENABLE, 0x01 , 0x00 ) - -ZBM(ZBS_WNV_SECMODE, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(CONF_TCLK_TABLE_START), Z_B1(CONF_TCLK_TABLE_START), - 0x00 , 0x20 , - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x5a, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6c, - 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x30, 0x39, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) - -ZBM(ZBS_W_ZDODCB, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_ZDO_DIRECT_CB, 0x01 , 0x01 ) - -ZBM(ZBS_WNV_INITZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_ITEM_INIT, ZNP_HAS_CONFIGURED & 0xFF, ZNP_HAS_CONFIGURED >> 8, - 0x01, 0x00 , 0x01 , 0x00 ) - - -ZBM(ZBR_WNV_INIT_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_ITEM_INIT ) - - -ZBM(ZBS_WNV_ZNPHC, Z_SREQ | Z_SYS, SYS_OSAL_NV_WRITE, Z_B0(ZNP_HAS_CONFIGURED), Z_B1(ZNP_HAS_CONFIGURED), - 0x00 , 0x01 , 0x55 ) - -ZBM(ZBS_STARTUPFROMAPP, Z_SREQ | Z_ZDO, ZDO_STARTUP_FROM_APP, 100, 0 ) -ZBM(ZBR_STARTUPFROMAPP, Z_SRSP | Z_ZDO, ZDO_STARTUP_FROM_APP ) -ZBM(AREQ_STARTUPFROMAPP, Z_AREQ | Z_ZDO, ZDO_STATE_CHANGE_IND, ZDO_DEV_ZB_COORD ) - -ZBM(ZBS_GETDEVICEINFO, Z_SREQ | Z_UTIL, Z_UTIL_GET_DEVICE_INFO ) -ZBM(ZBR_GETDEVICEINFO, Z_SRSP | Z_UTIL, Z_UTIL_GET_DEVICE_INFO, Z_SUCCESS ) -# 268 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_7_statemachine.ino" -ZBM(ZBS_ZDO_NODEDESCREQ, Z_SREQ | Z_ZDO, ZDO_NODE_DESC_REQ, 0x00, 0x00 , 0x00, 0x00 ) -ZBM(ZBR_ZDO_NODEDESCREQ, Z_SRSP | Z_ZDO, ZDO_NODE_DESC_REQ, Z_SUCCESS ) - -ZBM(AREQ_ZDO_NODEDESCRSP, Z_AREQ | Z_ZDO, ZDO_NODE_DESC_RSP) -# 286 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_7_statemachine.ino" -ZBM(ZBS_ZDO_ACTIVEEPREQ, Z_SREQ | Z_ZDO, ZDO_ACTIVE_EP_REQ, 0x00, 0x00, 0x00, 0x00) -ZBM(ZBR_ZDO_ACTIVEEPREQ, Z_SRSP | Z_ZDO, ZDO_ACTIVE_EP_REQ, Z_SUCCESS) -ZBM(ZBR_ZDO_ACTIVEEPRSP_NONE, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 , Z_SUCCESS, - 0x00, 0x00 , 0x00 ) -ZBM(ZBR_ZDO_ACTIVEEPRSP_OK, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP, 0x00, 0x00 , Z_SUCCESS, - 0x00, 0x00 , 0x02 , 0x0B, 0x01 ) - - -ZBM(ZBS_AF_REGISTER01, Z_SREQ | Z_AF, AF_REGISTER, 0x01 , Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), - 0x05, 0x00 , 0x00 , 0x00 , - 0x00 , 0x00 ) -ZBM(ZBR_AF_REGISTER, Z_SRSP | Z_AF, AF_REGISTER, Z_SUCCESS) -ZBM(ZBS_AF_REGISTER0B, Z_SREQ | Z_AF, AF_REGISTER, 0x0B , Z_B0(Z_PROF_HA), Z_B1(Z_PROF_HA), - 0x05, 0x00 , 0x00 , 0x00 , - 0x00 , 0x00 ) - -ZBM(ZBS_PERMITJOINREQ_CLOSE, Z_SREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_REQ, 0x02 , - 0x00, 0x00 , 0x00 , 0x00 ) -ZBM(ZBR_PERMITJOINREQ, Z_SRSP | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_REQ, Z_SUCCESS) -ZBM(ZBR_PERMITJOIN_AREQ_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_RSP, 0x00, 0x00 , Z_SUCCESS ) - - -void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h) { - uint32_t zb_channel_mask = (1 << zb_channel); - - ZBW(ZBR_PAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PANID, 0x02 , - Z_B0(zb_pan_id), Z_B1(zb_pan_id) ) - - ZBW(ZBR_EXTPAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_EXTENDED_PAN_ID, - 0x08 , - Z_B0(zb_ext_panid), Z_B1(zb_ext_panid), Z_B2(zb_ext_panid), Z_B3(zb_ext_panid), - Z_B4(zb_ext_panid), Z_B5(zb_ext_panid), Z_B6(zb_ext_panid), Z_B7(zb_ext_panid), - ) - - ZBW(ZBR_CHANN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_CHANLIST, - 0x04 , - Z_B0(zb_channel_mask), Z_B1(zb_channel_mask), Z_B2(zb_channel_mask), Z_B3(zb_channel_mask), - ) - - ZBW(ZBR_PFGK, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PRECFGKEY, - 0x10 , - Z_B0(zb_precfgkey_l), Z_B1(zb_precfgkey_l), Z_B2(zb_precfgkey_l), Z_B3(zb_precfgkey_l), - Z_B4(zb_precfgkey_l), Z_B5(zb_precfgkey_l), Z_B6(zb_precfgkey_l), Z_B7(zb_precfgkey_l), - Z_B0(zb_precfgkey_h), Z_B1(zb_precfgkey_h), Z_B2(zb_precfgkey_h), Z_B3(zb_precfgkey_h), - Z_B4(zb_precfgkey_h), Z_B5(zb_precfgkey_h), Z_B6(zb_precfgkey_h), Z_B7(zb_precfgkey_h), - - ) - - ZBW(ZBS_W_PAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PANID, 0x02 , Z_B0(zb_pan_id), Z_B1(zb_pan_id) ) - - ZBW(ZBS_W_EXTPAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_EXTENDED_PAN_ID, 0x08 , - Z_B0(zb_ext_panid), Z_B1(zb_ext_panid), Z_B2(zb_ext_panid), Z_B3(zb_ext_panid), - Z_B4(zb_ext_panid), Z_B5(zb_ext_panid), Z_B6(zb_ext_panid), Z_B7(zb_ext_panid) - ) - - ZBW(ZBS_W_CHANN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_CHANLIST, 0x04 , - Z_B0(zb_channel_mask), Z_B1(zb_channel_mask), Z_B2(zb_channel_mask), Z_B3(zb_channel_mask), - ) - - ZBW(ZBS_W_PFGK, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PRECFGKEY, - 0x10 , - Z_B0(zb_precfgkey_l), Z_B1(zb_precfgkey_l), Z_B2(zb_precfgkey_l), Z_B3(zb_precfgkey_l), - Z_B4(zb_precfgkey_l), Z_B5(zb_precfgkey_l), Z_B6(zb_precfgkey_l), Z_B7(zb_precfgkey_l), - Z_B0(zb_precfgkey_h), Z_B1(zb_precfgkey_h), Z_B2(zb_precfgkey_h), Z_B3(zb_precfgkey_h), - Z_B4(zb_precfgkey_h), Z_B5(zb_precfgkey_h), Z_B6(zb_precfgkey_h), Z_B7(zb_precfgkey_h), - ) -} - -const char kCheckingDeviceConfiguration[] PROGMEM = D_LOG_ZIGBEE "checking device configuration"; -const char kConfigured[] PROGMEM = "Configured, starting coordinator"; -const char kStarted[] PROGMEM = "Started"; -const char kZigbeeStarted[] PROGMEM = D_LOG_ZIGBEE "Zigbee started"; -const char kResetting[] PROGMEM = "Resetting configuration"; -const char kZNP12[] PROGMEM = "Only ZNP 1.2 is currently supported"; -const char kAbort[] PROGMEM = "Abort"; -const char kZigbeeAbort[] PROGMEM = D_LOG_ZIGBEE "Abort"; - -static const Zigbee_Instruction zb_prog[] PROGMEM = { - ZI_LABEL(0) - ZI_NOOP() - ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) - ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) - ZI_ON_RECV_UNEXPECTED(&Z_Recv_Default) - ZI_WAIT(10500) - ZI_ON_ERROR_GOTO(50) - - - - ZI_SEND(ZBS_RESET) - ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &Z_Reboot) - ZI_WAIT(100) - ZI_LOG(LOG_LEVEL_DEBUG, kCheckingDeviceConfiguration) - ZI_SEND(ZBS_ZNPHC) - ZI_WAIT_RECV(2000, ZBR_ZNPHC) - ZI_SEND(ZBS_VERSION) - ZI_WAIT_RECV_FUNC(2000, ZBR_VERSION, &Z_ReceiveCheckVersion) - ZI_SEND(ZBS_PAN) - ZI_WAIT_RECV(1000, ZBR_PAN) - ZI_SEND(ZBS_EXTPAN) - ZI_WAIT_RECV(1000, ZBR_EXTPAN) - ZI_SEND(ZBS_CHANN) - ZI_WAIT_RECV(1000, ZBR_CHANN) - ZI_SEND(ZBS_PFGK) - ZI_WAIT_RECV(1000, ZBR_PFGK) - ZI_SEND(ZBS_PFGKEN) - ZI_WAIT_RECV(1000, ZBR_PFGKEN) - - - - ZI_LABEL(ZIGBEE_LABEL_START) - ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfigured) - ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) - - -ZI_SEND(ZBS_STARTUPFROMAPP) - ZI_WAIT_RECV(2000, ZBR_STARTUPFROMAPP) - ZI_WAIT_UNTIL(10000, AREQ_STARTUPFROMAPP) - ZI_SEND(ZBS_GETDEVICEINFO) - ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &Z_ReceiveDeviceInfo) - - ZI_SEND(ZBS_ZDO_NODEDESCREQ) - ZI_WAIT_RECV(1000, ZBR_ZDO_NODEDESCREQ) - ZI_WAIT_UNTIL(5000, AREQ_ZDO_NODEDESCRSP) - ZI_SEND(ZBS_ZDO_ACTIVEEPREQ) - ZI_WAIT_RECV(1000, ZBR_ZDO_ACTIVEEPREQ) - ZI_WAIT_UNTIL(1000, ZBR_ZDO_ACTIVEEPRSP_NONE) - ZI_SEND(ZBS_AF_REGISTER01) - ZI_WAIT_RECV(1000, ZBR_AF_REGISTER) - ZI_SEND(ZBS_AF_REGISTER0B) - ZI_WAIT_RECV(1000, ZBR_AF_REGISTER) - - ZI_SEND(ZBS_ZDO_ACTIVEEPREQ) - ZI_WAIT_RECV(1000, ZBR_ZDO_ACTIVEEPREQ) - ZI_WAIT_UNTIL(1000, ZBR_ZDO_ACTIVEEPRSP_OK) - ZI_SEND(ZBS_PERMITJOINREQ_CLOSE) - ZI_WAIT_RECV(1000, ZBR_PERMITJOINREQ) - ZI_WAIT_UNTIL(1000, ZBR_PERMITJOIN_AREQ_RSP) - - ZI_LABEL(ZIGBEE_LABEL_READY) - ZI_MQTT_STATE(ZIGBEE_STATUS_OK, kStarted) - ZI_LOG(LOG_LEVEL_INFO, kZigbeeStarted) - ZI_CALL(&Z_State_Ready, 1) - ZI_CALL(&Z_Load_Devices, 0) - ZI_CALL(&Z_Query_Bulbs, 0) - ZI_LABEL(ZIGBEE_LABEL_MAIN_LOOP) - ZI_WAIT_FOREVER() - ZI_GOTO(ZIGBEE_LABEL_READY) - - ZI_LABEL(50) - ZI_MQTT_STATE(ZIGBEE_STATUS_RESET_CONF, kResetting) - - ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) - ZI_SEND(ZBS_FACTRES) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_RESET) - ZI_WAIT_RECV(5000, ZBR_RESET) - ZI_SEND(ZBS_W_PAN) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_W_EXTPAN) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_W_CHANN) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_W_LOGTYP) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_W_PFGK) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_W_PFGKEN) - ZI_WAIT_RECV(1000, ZBR_W_OK) - ZI_SEND(ZBS_WNV_SECMODE) - ZI_WAIT_RECV(1000, ZBR_WNV_OK) - ZI_SEND(ZBS_W_ZDODCB) - ZI_WAIT_RECV(1000, ZBR_W_OK) - - ZI_SEND(ZBS_WNV_INITZNPHC) - ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &Z_CheckNVWrite) - ZI_SEND(ZBS_WNV_ZNPHC) - ZI_WAIT_RECV(1000, ZBR_WNV_OK) - - - ZI_GOTO(ZIGBEE_LABEL_START) - - ZI_LABEL(ZIGBEE_LABEL_UNSUPPORTED_VERSION) - ZI_MQTT_STATE(ZIGBEE_STATUS_UNSUPPORTED_VERSION, kZNP12) - ZI_GOTO(ZIGBEE_LABEL_ABORT) - - ZI_LABEL(ZIGBEE_LABEL_ABORT) - ZI_MQTT_STATE(ZIGBEE_STATUS_ABORT, kAbort) - ZI_LOG(LOG_LEVEL_ERROR, kZigbeeAbort) - ZI_STOP(ZIGBEE_LABEL_ABORT) -}; - -uint8_t ZigbeeGetInstructionSize(uint8_t instr) { - if (instr >= ZGB_INSTR_12_BYTES) { - return 3; - } else if (instr >= ZGB_INSTR_8_BYTES) { - return 2; - } else { - return 1; - } -} - -void ZigbeeGotoLabel(uint8_t label) { - - uint16_t goto_pc = 0xFFFF; - uint8_t cur_instr = 0; - uint8_t cur_d8 = 0; - uint8_t cur_instr_len = 1; - - for (uint32_t i = 0; i < sizeof(zb_prog)/sizeof(zb_prog[0]); i += cur_instr_len) { - const Zigbee_Instruction *cur_instr_line = &zb_prog[i]; - cur_instr = pgm_read_byte(&cur_instr_line->i.i); - cur_d8 = pgm_read_byte(&cur_instr_line->i.d8); - - - if (ZGB_INSTR_LABEL == cur_instr) { - - if (label == cur_d8) { - - zigbee.pc = i; - zigbee.state_machine = true; - zigbee.state_waiting = false; - return; - } - } - - cur_instr_len = ZigbeeGetInstructionSize(cur_instr); - } - - - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Goto label not found, label=%d pc=%d"), label, zigbee.pc); - if (ZIGBEE_LABEL_ABORT != label) { - - ZigbeeGotoLabel(ZIGBEE_LABEL_ABORT); - } else { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Label Abort (%d) not present, aborting Zigbee"), ZIGBEE_LABEL_ABORT); - zigbee.state_machine = false; - zigbee.active = false; - } -} - -void ZigbeeStateMachine_Run(void) { - uint8_t cur_instr = 0; - uint8_t cur_d8 = 0; - uint16_t cur_d16 = 0; - const void* cur_ptr1 = nullptr; - const void* cur_ptr2 = nullptr; - uint32_t now = millis(); - - if (zigbee.state_waiting) { - - if ((zigbee.next_timeout) && (now > zigbee.next_timeout)) { - if (!zigbee.state_no_timeout) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "timeout, goto label %d"), zigbee.on_timeout_goto); - ZigbeeGotoLabel(zigbee.on_timeout_goto); - } else { - zigbee.state_waiting = false; - } - } - } - - while ((zigbee.state_machine) && (!zigbee.state_waiting)) { - - zigbee.recv_filter = nullptr; - zigbee.recv_func = nullptr; - zigbee.recv_until = false; - zigbee.state_no_timeout = false; - - if (zigbee.pc > (sizeof(zb_prog)/sizeof(zb_prog[0]))) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Invalid pc: %d, aborting"), zigbee.pc); - zigbee.pc = -1; - } - if (zigbee.pc < 0) { - zigbee.state_machine = false; - return; - } - - - const Zigbee_Instruction *cur_instr_line = &zb_prog[zigbee.pc]; - cur_instr = pgm_read_byte(&cur_instr_line->i.i); - cur_d8 = pgm_read_byte(&cur_instr_line->i.d8); - cur_d16 = pgm_read_word(&cur_instr_line->i.d16); - if (cur_instr >= ZGB_INSTR_8_BYTES) { - cur_instr_line++; - cur_ptr1 = cur_instr_line->p; - } - if (cur_instr >= ZGB_INSTR_12_BYTES) { - cur_instr_line++; - cur_ptr2 = cur_instr_line->p; - } - - zigbee.pc += ZigbeeGetInstructionSize(cur_instr); - - switch (cur_instr) { - case ZGB_INSTR_NOOP: - case ZGB_INSTR_LABEL: - break; - case ZGB_INSTR_GOTO: - ZigbeeGotoLabel(cur_d8); - break; - case ZGB_INSTR_ON_ERROR_GOTO: - zigbee.on_error_goto = cur_d8; - break; - case ZGB_INSTR_ON_TIMEOUT_GOTO: - zigbee.on_timeout_goto = cur_d8; - break; - case ZGB_INSTR_WAIT: - zigbee.next_timeout = now + cur_d16; - zigbee.state_waiting = true; - zigbee.state_no_timeout = true; - break; - case ZGB_INSTR_WAIT_FOREVER: - zigbee.next_timeout = 0; - zigbee.state_waiting = true; - break; - case ZGB_INSTR_STOP: - zigbee.state_machine = false; - if (cur_d8) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Stopping (%d)"), cur_d8); - } - break; - case ZGB_INSTR_CALL: - if (cur_ptr1) { - uint32_t res; - res = (*((ZB_Func)cur_ptr1))(cur_d8); - if (res > 0) { - ZigbeeGotoLabel(res); - continue; - } else if (res == 0) { - - } else if (res == -1) { - - } else { - ZigbeeGotoLabel(zigbee.on_error_goto); - continue; - } - } - break; - case ZGB_INSTR_LOG: - AddLog_P(cur_d8, (char*) cur_ptr1); - break; - case ZGB_INSTR_MQTT_STATE: - { - const char *f_msg = (const char*) cur_ptr1; - char buf[strlen_P(f_msg) + 1]; - strcpy_P(buf, f_msg); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":%d,\"Message\":\"%s\"}}"), - cur_d8, buf); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); - } - break; - case ZGB_INSTR_SEND: - ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 ); - break; - case ZGB_INSTR_WAIT_UNTIL: - zigbee.recv_until = true; - case ZGB_INSTR_WAIT_RECV: - zigbee.recv_filter = (uint8_t *) cur_ptr1; - zigbee.recv_filter_len = cur_d8; - zigbee.next_timeout = now + cur_d16; - zigbee.state_waiting = true; - break; - case ZGB_ON_RECV_UNEXPECTED: - zigbee.recv_unexpected = (ZB_RecvMsgFunc) cur_ptr1; - break; - case ZGB_INSTR_WAIT_RECV_CALL: - zigbee.recv_filter = (uint8_t *) cur_ptr1; - zigbee.recv_filter_len = cur_d8; - zigbee.recv_func = (ZB_RecvMsgFunc) cur_ptr2; - zigbee.next_timeout = now + cur_d16; - zigbee.state_waiting = true; - break; - } - } -} - - - - -int32_t ZigbeeProcessInput(class SBuffer &buf) { - if (!zigbee.state_machine) { return -1; } - - - bool recv_filter_match = true; - bool recv_prefix_match = false; - if ((zigbee.recv_filter) && (zigbee.recv_filter_len > 0)) { - if (zigbee.recv_filter_len >= 2) { - recv_prefix_match = false; - if ( (pgm_read_byte(&zigbee.recv_filter[0]) == buf.get8(0)) && - (pgm_read_byte(&zigbee.recv_filter[1]) == buf.get8(1)) ) { - recv_prefix_match = true; - } - } - - for (uint32_t i = 0; i < zigbee.recv_filter_len; i++) { - if (pgm_read_byte(&zigbee.recv_filter[i]) != buf.get8(i)) { - recv_filter_match = false; - break; - } - } - } - - - int32_t res = -1; - - - - - - if ((zigbee.recv_filter) && (zigbee.recv_filter_len > 0)) { - if (!recv_prefix_match) { - res = -1; - } else { - if (recv_filter_match) { - res = 0; - } else { - if (zigbee.recv_until) { - res = -1; - } else { - res = -2; - } - } - } - } else { - res = -1; - } - - if (recv_prefix_match) { - if (zigbee.recv_func) { - res = (*zigbee.recv_func)(res, buf); - } - } - if (-1 == res) { - - if (zigbee.recv_unexpected) { - res = (*zigbee.recv_unexpected)(res, buf); - } - } - - - if (0 == res) { - - zigbee.state_waiting = false; - } else if (res > 0) { - ZigbeeGotoLabel(res); - } else if (-1 == res) { - - - } else { - - ZigbeeGotoLabel(zigbee.on_error_goto); - } -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" -#ifdef USE_ZIGBEE -# 29 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" -int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { - - - - - - - - Z_IEEEAddress long_adr = buf.get64(3); - Z_ShortAddress short_adr = buf.get16(11); - uint8_t device_type = buf.get8(13); - uint8_t device_state = buf.get8(14); - uint8_t device_associated = buf.get8(15); - - - localIEEEAddr = long_adr; - - char hex[20]; - Uint64toHex(long_adr, hex, 64); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\"" - ",\"DeviceType\":%d,\"DeviceState\":%d" - ",\"NumAssocDevices\":%d"), - ZIGBEE_STATUS_CC_INFO, hex, short_adr, device_type, device_state, - device_associated); - - if (device_associated > 0) { - uint idx = 16; - ResponseAppend_P(PSTR(",\"AssocDevicesList\":[")); - for (uint32_t i = 0; i < device_associated; i++) { - if (i > 0) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(PSTR("\"0x%04X\""), buf.get16(idx)); - idx += 2; - } - ResponseAppend_P(PSTR("]")); - } - - ResponseJsonEnd(); - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); - - return res; -} - -int32_t Z_CheckNVWrite(int32_t res, class SBuffer &buf) { - - - - uint8_t status = buf.get8(2); - if ((0x00 == status) || (0x09 == status)) { - return 0; - } else { - return -2; - } -} - -int32_t Z_Reboot(int32_t res, class SBuffer &buf) { - - - - static const char Z_RebootReason[] PROGMEM = "Power-up|External|Watchdog"; - - uint8_t reason = buf.get8(2); - uint8_t transport_rev = buf.get8(3); - uint8_t product_id = buf.get8(4); - uint8_t major_rel = buf.get8(5); - uint8_t minor_rel = buf.get8(6); - uint8_t hw_rev = buf.get8(7); - char reason_str[12]; - - if (reason > 3) { reason = 3; } - GetTextIndexed(reason_str, sizeof(reason_str), reason, Z_RebootReason); - - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"Message\":\"CC2530 booted\",\"RestartReason\":\"%s\"" - ",\"MajorRel\":%d,\"MinorRel\":%d}}"), - ZIGBEE_STATUS_BOOT, reason_str, - major_rel, minor_rel); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); - - if ((0x02 == major_rel) && (0x06 == minor_rel)) { - return 0; - } else { - return ZIGBEE_LABEL_UNSUPPORTED_VERSION; - } -} - -int32_t Z_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { -# 129 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" - uint8_t major_rel = buf.get8(4); - uint8_t minor_rel = buf.get8(5); - uint8_t maint_rel = buf.get8(6); - uint32_t revision = buf.get32(7); - - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"MajorRel\":%d,\"MinorRel\":%d" - ",\"MaintRel\":%d,\"Revision\":%d}}"), - ZIGBEE_STATUS_CC_VERSION, major_rel, minor_rel, - maint_rel, revision); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); - - if ((0x02 == major_rel) && (0x06 == minor_rel)) { - return 0; - } else { - return ZIGBEE_LABEL_UNSUPPORTED_VERSION; - } -} - - - - -bool Z_ReceiveMatchPrefix(const class SBuffer &buf, const uint8_t *match) { - if ( (pgm_read_byte(&match[0]) == buf.get8(0)) && - (pgm_read_byte(&match[1]) == buf.get8(1)) ) { - return true; - } else { - return false; - } -} - - - - -int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { - - uint8_t duration = buf.get8(2); - uint8_t status_code; - const char* message; - - if (0xFF == duration) { - status_code = ZIGBEE_STATUS_PERMITJOIN_OPEN_XX; - message = PSTR("Enable Pairing mode until next boot"); - } else if (duration > 0) { - status_code = ZIGBEE_STATUS_PERMITJOIN_OPEN_60; - message = PSTR("Enable Pairing mode for %d seconds"); - } else { - status_code = ZIGBEE_STATUS_PERMITJOIN_CLOSE; - message = PSTR("Disable Pairing mode"); - } - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"Message\":\""), - status_code); - ResponseAppend_P(message, duration); - ResponseAppend_P(PSTR("\"}}")); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); - return -1; -} - -const char* Z_DeviceType[] = { "Coordinator", "Router", "End Device", "Unknown" }; -int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { - - Z_ShortAddress srcAddr = buf.get16(2); - uint8_t status = buf.get8(4); - Z_ShortAddress nwkAddr = buf.get16(5); - uint8_t logicalType = buf.get8(7); - uint8_t apsFlags = buf.get8(8); - uint8_t MACCapabilityFlags = buf.get8(9); - uint16_t manufacturerCapabilities = buf.get16(10); - uint8_t maxBufferSize = buf.get8(12); - uint16_t maxInTransferSize = buf.get16(13); - uint16_t serverMask = buf.get16(15); - uint16_t maxOutTransferSize = buf.get16(17); - uint8_t descriptorCapabilities = buf.get8(19); - - if (0 == status) { - uint8_t deviceType = logicalType & 0x7; - if (deviceType > 3) { deviceType = 3; } - bool complexDescriptorAvailable = (logicalType & 0x08) ? 1 : 0; - - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"NodeType\":\"%s\",\"ComplexDesc\":%s}}"), - ZIGBEE_STATUS_NODE_DESC, Z_DeviceType[deviceType], - complexDescriptorAvailable ? "true" : "false" - ); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - } - - return -1; -} - - - - -int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) { - - Z_ShortAddress srcAddr = buf.get16(2); - uint8_t status = buf.get8(4); - Z_ShortAddress nwkAddr = buf.get16(5); - uint8_t activeEpCount = buf.get8(7); - uint8_t* activeEpList = (uint8_t*) buf.charptr(8); - - for (uint32_t i = 0; i < activeEpCount; i++) { - zigbee_devices.addEndpoint(nwkAddr, activeEpList[i]); - } - - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"ActiveEndpoints\":["), - ZIGBEE_STATUS_ACTIVE_EP); - for (uint32_t i = 0; i < activeEpCount; i++) { - if (i > 0) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(PSTR("\"0x%02X\""), activeEpList[i]); - } - ResponseAppend_P(PSTR("]}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - - Z_SendAFInfoRequest(nwkAddr); - - return -1; -} - - - - -int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) { - uint8_t status = buf.get8(2); - Z_IEEEAddress ieeeAddr = buf.get64(3); - Z_ShortAddress nwkAddr = buf.get16(11); - - - - if (0 == status) { - zigbee_devices.updateDevice(nwkAddr, ieeeAddr); - char hex[20]; - Uint64toHex(ieeeAddr, hex, 64); - - const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr); - if (friendlyName) { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_PING "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\"" - ",\"" D_JSON_ZIGBEE_IEEE "\":\"0x%s\"" - ",\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), nwkAddr, hex, friendlyName); - } else { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_PING "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\"" - ",\"" D_JSON_ZIGBEE_IEEE "\":\"0x%s\"" - "}}"), nwkAddr, hex); - } - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - } - return -1; -} - - - - -int32_t Z_DataConfirm(int32_t res, const class SBuffer &buf) { - uint8_t status = buf.get8(2); - uint8_t endpoint = buf.get8(3); - - - if (status) { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_CONFIRM "\":{\"" D_CMND_ZIGBEE_ENDPOINT "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" - "}}"), endpoint, status, getZigbeeStatusMessage(status).c_str()); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - } - - return -1; -} - - - - - - -int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { - Z_ShortAddress srcAddr = buf.get16(2); - Z_ShortAddress nwkAddr = buf.get16(4); - Z_IEEEAddress ieeeAddr = buf.get64(6); - uint8_t capabilities = buf.get8(14); - - zigbee_devices.updateDevice(nwkAddr, ieeeAddr); - - char hex[20]; - Uint64toHex(ieeeAddr, hex, 64); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\"" - ",\"PowerSource\":%s,\"ReceiveWhenIdle\":%s,\"Security\":%s}}"), - ZIGBEE_STATUS_DEVICE_ANNOUNCE, hex, nwkAddr, - (capabilities & 0x04) ? "true" : "false", - (capabilities & 0x08) ? "true" : "false", - (capabilities & 0x40) ? "true" : "false" - ); - - uint32_t wait_ms = 2000; - Z_Query_Bulb(nwkAddr, wait_ms); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - Z_SendActiveEpReq(nwkAddr); - return -1; -} - - - - - -int32_t Z_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { - Z_ShortAddress srcAddr = buf.get16(2); - Z_IEEEAddress ieeeAddr = buf.get64(4); - Z_ShortAddress parentNw = buf.get16(12); - - zigbee_devices.updateDevice(srcAddr, ieeeAddr); - - char hex[20]; - Uint64toHex(ieeeAddr, hex, 64); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" - "\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\"" - ",\"ParentNetwork\":\"0x%04X\"}}"), - ZIGBEE_STATUS_DEVICE_INDICATION, hex, srcAddr, parentNw - ); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - return -1; -} - - - - -int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) { - Z_ShortAddress nwkAddr = buf.get16(2); - uint8_t status = buf.get8(4); - - const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr); - if (friendlyName) { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\"" - ",\"" D_JSON_ZIGBEE_NAME "\":\"%s\"" - ",\"" D_JSON_ZIGBEE_STATUS "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" - "}}"), nwkAddr, friendlyName, status, getZigbeeStatusMessage(status).c_str()); - } else { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\"" - ",\"" D_JSON_ZIGBEE_STATUS "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" - "}}"), nwkAddr, status, getZigbeeStatusMessage(status).c_str()); - } - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - - return -1; -} - - - - -int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) { - Z_ShortAddress nwkAddr = buf.get16(2); - uint8_t status = buf.get8(4); - - const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr); - if (friendlyName) { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_UNBIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\"" - ",\"" D_JSON_ZIGBEE_NAME "\":\"%s\"" - ",\"" D_JSON_ZIGBEE_STATUS "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" - "}}"), nwkAddr, friendlyName, status, getZigbeeStatusMessage(status).c_str()); - } else { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_UNBIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\"" - ",\"" D_JSON_ZIGBEE_STATUS "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" - "}}"), nwkAddr, status, getZigbeeStatusMessage(status).c_str()); - } - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); - - return -1; -} - - - -int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { - uint16_t shortaddr = buf.get16(2); - uint8_t status = buf.get8(4); - uint8_t bind_total = buf.get8(5); - uint8_t bind_start = buf.get8(6); - uint8_t bind_len = buf.get8(7); - - const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); - - Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND_STATE "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), shortaddr); - if (friendlyName) { - ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName); - } - ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d" - ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" - ",\"BindingsTotal\":%d" - - ",\"Bindings\":[" - ), status, getZigbeeStatusMessage(status).c_str(), bind_total); - - uint32_t idx = 8; - for (uint32_t i = 0; i < bind_len; i++) { - if (idx + 14 > buf.len()) { break; } - - - uint8_t srcep = buf.get8(idx + 8); - uint8_t cluster = buf.get16(idx + 9); - uint8_t addrmode = buf.get8(idx + 11); - uint16_t group = 0x0000; - uint64_t dstaddr = 0; - uint8_t dstep = 0x00; - if (Z_Addr_Group == addrmode) { - group = buf.get16(idx + 12); - idx += 14; - } else if (Z_Addr_IEEEAddress == addrmode) { - dstaddr = buf.get64(idx + 12); - dstep = buf.get8(idx + 20); - idx += 21; - } else { - - break; - } - - if (i > 0) { - ResponseAppend_P(PSTR(",")); - } - ResponseAppend_P(PSTR("{\"Cluster\":\"0x%04X\",\"Endpoint\":%d,"), cluster, srcep); - if (Z_Addr_Group == addrmode) { - ResponseAppend_P(PSTR("\"ToGroup\":%d}"), group); - } else if (Z_Addr_IEEEAddress == addrmode) { - char hex[20]; - Uint64toHex(dstaddr, hex, 64); - ResponseAppend_P(PSTR("\"ToDevice\":\"0x%s\",\"ToEndpoint\":%d}"), hex, dstep); - } - } - - ResponseAppend_P(PSTR("]}}")); - - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_BIND_STATE)); - XdrvRulesProcess(); - - return -1; -} -# 491 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" -void Z_SendIEEEAddrReq(uint16_t shortaddr) { - uint8_t IEEEAddrReq[] = { Z_SREQ | Z_ZDO, ZDO_IEEE_ADDR_REQ, Z_B0(shortaddr), Z_B1(shortaddr), 0x00, 0x00 }; - - ZigbeeZNPSend(IEEEAddrReq, sizeof(IEEEAddrReq)); -} - - - - -void Z_SendActiveEpReq(uint16_t shortaddr) { - uint8_t ActiveEpReq[] = { Z_SREQ | Z_ZDO, ZDO_ACTIVE_EP_REQ, Z_B0(shortaddr), Z_B1(shortaddr), Z_B0(shortaddr), Z_B1(shortaddr) }; - - ZigbeeZNPSend(ActiveEpReq, sizeof(ActiveEpReq)); -} - - - - -void Z_SendAFInfoRequest(uint16_t shortaddr) { - uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr); - if (0x00 == endpoint) { endpoint = 0x01; } - uint8_t transacid = zigbee_devices.getNextSeqNumber(shortaddr); - - uint8_t AFInfoReq[] = { Z_SREQ | Z_AF, AF_DATA_REQUEST, Z_B0(shortaddr), Z_B1(shortaddr), endpoint, - 0x01, 0x00, 0x00, transacid, 0x30, 0x1E, 3 + 2*sizeof(uint16_t), - 0x00, transacid, ZCL_READ_ATTRIBUTES, 0x04, 0x00, 0x05, 0x00 - }; - ZigbeeZNPSend(AFInfoReq, sizeof(AFInfoReq)); -} -# 529 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" -void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, const JsonObject &json) { - static const uint32_t OCCUPANCY_TIMEOUT = 90 * 1000; - - const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR(OCCUPANCY)); - if (nullptr != &val_endpoint) { - uint32_t occupancy = strToUInt(val_endpoint); - - if (occupancy) { - zigbee_devices.setTimer(shortaddr, 0 , OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback); - } else { - zigbee_devices.resetTimersForDevice(shortaddr, 0 , Z_CAT_VIRTUAL_OCCUPANCY); - } - } -} - - - -int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) { - const JsonObject *json = zigbee_devices.jsonGet(shortaddr); - if (json == nullptr) { return 0; } - - zigbee_devices.jsonPublishFlush(shortaddr); - return 1; -} - - - - - -int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { - uint16_t groupid = buf.get16(2); - uint16_t clusterid = buf.get16(4); - Z_ShortAddress srcaddr = buf.get16(6); - uint8_t srcendpoint = buf.get8(8); - uint8_t dstendpoint = buf.get8(9); - uint8_t wasbroadcast = buf.get8(10); - uint8_t linkquality = buf.get8(11); - uint8_t securityuse = buf.get8(12); - uint32_t timestamp = buf.get32(13); - uint8_t seqnumber = buf.get8(17); - - bool defer_attributes = false; - - ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid, - srcaddr, - srcendpoint, dstendpoint, wasbroadcast, - linkquality, securityuse, seqnumber, - timestamp); - zcl_received.log(); - char shortaddr[8]; - snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr); - - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - - if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_DEFAULT_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseResponse(); - } else { - - if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) { - zcl_received.parseRawAttributes(json); - if (clusterid) { defer_attributes = true; } - } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_ATTRIBUTES_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseReadAttributes(json); - if (clusterid) { defer_attributes = true; } - } else if (zcl_received.isClusterSpecificCommand()) { - zcl_received.parseClusterSpecificCommand(json); - } - String msg(""); - msg.reserve(100); - json.printTo(msg); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZCL_RAW_RECEIVED ": {\"0x%04X\":%s}"), srcaddr, msg.c_str()); - - zcl_received.postProcessAttributes(srcaddr, json); - - json[F(D_CMND_ZIGBEE_ENDPOINT)] = srcendpoint; - - if (groupid) { - json[F(D_CMND_ZIGBEE_GROUP)] = groupid; - } - - json[F(D_CMND_ZIGBEE_LINKQUALITY)] = linkquality; - - - zigbee_devices.resetTimersForDevice(srcaddr, 0 , Z_CAT_REACHABILITY); - zigbee_devices.setReachable(srcaddr, true); - - - Z_AqaraOccupancy(srcaddr, clusterid, srcendpoint, json); - - if (defer_attributes) { - - if (zigbee_devices.jsonIsConflict(srcaddr, json)) { - - zigbee_devices.jsonPublishFlush(srcaddr); - } - zigbee_devices.jsonAppend(srcaddr, json); - zigbee_devices.setTimer(srcaddr, 0 , USE_ZIGBEE_COALESCE_ATTR_TIMER, clusterid, srcendpoint, Z_CAT_READ_ATTR, 0, &Z_PublishAttributes); - } else { - - zigbee_devices.jsonPublishNow(srcaddr, json); - } - } - return -1; -} - - -typedef struct Z_Dispatcher { - const uint8_t* match; - ZB_RecvMsgFunc func; -} Z_Dispatcher; - - -ZBM(AREQ_AF_DATA_CONFIRM, Z_AREQ | Z_AF, AF_DATA_CONFIRM) -ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) -ZBM(AREQ_END_DEVICE_ANNCE_IND, Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND) -ZBM(AREQ_END_DEVICE_TC_DEV_IND, Z_AREQ | Z_ZDO, ZDO_TC_DEV_IND) -ZBM(AREQ_PERMITJOIN_OPEN_XX, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND ) -ZBM(AREQ_ZDO_ACTIVEEPRSP, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP) -ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) -ZBM(AREQ_ZDO_IEEE_ADDR_RSP, Z_AREQ | Z_ZDO, ZDO_IEEE_ADDR_RSP) -ZBM(AREQ_ZDO_BIND_RSP, Z_AREQ | Z_ZDO, ZDO_BIND_RSP) -ZBM(AREQ_ZDO_UNBIND_RSP, Z_AREQ | Z_ZDO, ZDO_UNBIND_RSP) -ZBM(AREQ_ZDO_MGMT_BIND_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_BIND_RSP) - - -const Z_Dispatcher Z_DispatchTable[] PROGMEM = { - { AREQ_AF_DATA_CONFIRM, &Z_DataConfirm }, - { AREQ_AF_INCOMING_MESSAGE, &Z_ReceiveAfIncomingMessage }, - { AREQ_END_DEVICE_ANNCE_IND, &Z_ReceiveEndDeviceAnnonce }, - { AREQ_END_DEVICE_TC_DEV_IND, &Z_ReceiveTCDevInd }, - { AREQ_PERMITJOIN_OPEN_XX, &Z_ReceivePermitJoinStatus }, - { AREQ_ZDO_NODEDESCRSP, &Z_ReceiveNodeDesc }, - { AREQ_ZDO_ACTIVEEPRSP, &Z_ReceiveActiveEp }, - { AREQ_ZDO_IEEE_ADDR_RSP, &Z_ReceiveIEEEAddr }, - { AREQ_ZDO_BIND_RSP, &Z_BindRsp }, - { AREQ_ZDO_UNBIND_RSP, &Z_UnbindRsp }, - { AREQ_ZDO_MGMT_BIND_RSP, &Z_MgmtBindRsp }, -}; - - - - - -int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) { - - if (zigbee.init_phase) { - - return -1; - } else { - for (uint32_t i = 0; i < sizeof(Z_DispatchTable)/sizeof(Z_Dispatcher); i++) { - if (Z_ReceiveMatchPrefix(buf, Z_DispatchTable[i].match)) { - (*Z_DispatchTable[i].func)(res, buf); - } - } - return -1; - } -} -# 695 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_8_parsers.ino" -int32_t Z_Load_Devices(uint8_t value) { - - loadZigbeeDevices(); - return 0; -} - - - - -void Z_Query_Bulb(uint16_t shortaddr, uint32_t &wait_ms) { - const uint32_t inter_message_ms = 100; - - if (0 <= zigbee_devices.getHueBulbtype(shortaddr)) { - uint8_t endpoint = zigbee_devices.findFirstEndpoint(shortaddr); - - if (endpoint) { - zigbee_devices.setTimer(shortaddr, 0 , wait_ms, 0x0006, endpoint, Z_CAT_NONE, 0 , &Z_ReadAttrCallback); - wait_ms += inter_message_ms; - zigbee_devices.setTimer(shortaddr, 0 , wait_ms, 0x0008, endpoint, Z_CAT_NONE, 0 , &Z_ReadAttrCallback); - wait_ms += inter_message_ms; - zigbee_devices.setTimer(shortaddr, 0 , wait_ms, 0x0300, endpoint, Z_CAT_NONE, 0 , &Z_ReadAttrCallback); - wait_ms += inter_message_ms; - zigbee_devices.setTimer(shortaddr, 0, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, 0, endpoint, Z_CAT_REACHABILITY, 0 , &Z_Unreachable); - wait_ms += 1000; - } - } -} - - - - -int32_t Z_Query_Bulbs(uint8_t value) { - - uint32_t wait_ms = 1000; - for (uint32_t i = 0; i < zigbee_devices.devicesSize(); i++) { - const Z_Device &device = zigbee_devices.devicesAt(i); - Z_Query_Bulb(device.shortaddr, wait_ms); - } - return 0; -} - - - - -int32_t Z_State_Ready(uint8_t value) { - zigbee.init_phase = false; - return 0; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" -#ifdef USE_ZIGBEE - -#define XDRV_23 23 - -const uint32_t ZIGBEE_BUFFER_SIZE = 256; -const uint8_t ZIGBEE_SOF = 0xFE; -const uint8_t ZIGBEE_SOF_ALT = 0xFF; - -#include -TasmotaSerial *ZigbeeSerial = nullptr; - - -const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" - D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN "|" - D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" - D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_READ "|" D_CMND_ZIGBEEZNPRECEIVE "|" - D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|" - D_CMND_ZIGBEE_BIND "|" D_CMND_ZIGBEE_UNBIND "|" D_CMND_ZIGBEE_PING "|" D_CMND_ZIGBEE_MODELID "|" - D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|" - D_CMND_ZIGBEE_CONFIG - ; - -void (* const ZigbeeCommand[])(void) PROGMEM = { - &CmndZbZNPSend, &CmndZbPermitJoin, - &CmndZbStatus, &CmndZbReset, &CmndZbSend, - &CmndZbProbe, &CmndZbRead, &CmndZbZNPReceive, - &CmndZbForget, &CmndZbSave, &CmndZbName, - &CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId, - &CmndZbLight, &CmndZbRestore, &CmndZbBindState, - &CmndZbConfig, - }; - - - - -void ZigbeeInputLoop(void) -{ - static uint32_t zigbee_polling_window = 0; - static uint8_t fcs = ZIGBEE_SOF; - static uint32_t zigbee_frame_len = 5; -# 68 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" - while (ZigbeeSerial->available()) { - yield(); - uint8_t zigbee_in_byte = ZigbeeSerial->read(); - - - if (0 == zigbee_buffer->len()) { - zigbee_frame_len = 5; - fcs = ZIGBEE_SOF; - - - - if (ZIGBEE_SOF_ALT == zigbee_in_byte) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbInput forgiven first byte %02X (only for statistics)"), zigbee_in_byte); - zigbee_in_byte = ZIGBEE_SOF; - } - } - - if ((0 == zigbee_buffer->len()) && (ZIGBEE_SOF != zigbee_in_byte)) { - - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbInput discarding byte %02X"), zigbee_in_byte); - continue; - } - - if (zigbee_buffer->len() < zigbee_frame_len) { - zigbee_buffer->add8(zigbee_in_byte); - zigbee_polling_window = millis(); - fcs ^= zigbee_in_byte; - } - - if (zigbee_buffer->len() >= zigbee_frame_len) { - zigbee_polling_window = 0; - break; - } - - - if (02 == zigbee_buffer->len()) { - - uint8_t len_byte = zigbee_buffer->get8(1); - if (len_byte > 250) len_byte = 250; - - zigbee_frame_len = len_byte + 5; - } - } - - if (zigbee_buffer->len() && (millis() > (zigbee_polling_window + ZIGBEE_POLLING))) { - char hex_char[(zigbee_buffer->len() * 2) + 2]; - ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char)); - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric()); - - if (zigbee_buffer->len() != zigbee_frame_len) { - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received frame of wrong size %s, len %d, expected %d"), hex_char, zigbee_buffer->len(), zigbee_frame_len); - } else if (0x00 != fcs) { - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEEZNPRECEIVED ": received bad FCS frame %s, %d"), hex_char, fcs); - } else { - - - - SBuffer znp_buffer = zigbee_buffer->subBuffer(2, zigbee_frame_len - 3); - - ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char)); - Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char); - if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); - } else { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); - } - - ZigbeeProcessInput(znp_buffer); - } - zigbee_buffer->setLen(0); - } -} - - - - -void ZigbeeInit(void) -{ - - if (0 == Settings.zb_channel) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Initializing Zigbee parameters from defaults")); - Settings.zb_ext_panid = USE_ZIGBEE_EXTPANID; - Settings.zb_precfgkey_l = USE_ZIGBEE_PRECFGKEY_L; - Settings.zb_precfgkey_h = USE_ZIGBEE_PRECFGKEY_H; - Settings.zb_pan_id = USE_ZIGBEE_PANID; - Settings.zb_channel = USE_ZIGBEE_CHANNEL; - Settings.zb_free_byte = 0; - } - - Z_UpdateConfig(Settings.zb_channel, Settings.zb_pan_id, Settings.zb_ext_panid, Settings.zb_precfgkey_l, Settings.zb_precfgkey_h); - - - zigbee.active = false; - if ((pin[GPIO_ZIGBEE_RX] < 99) && (pin[GPIO_ZIGBEE_TX] < 99)) { - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "GPIOs Rx:%d Tx:%d"), pin[GPIO_ZIGBEE_RX], pin[GPIO_ZIGBEE_TX]); - - ZigbeeSerial = new TasmotaSerial(pin[GPIO_ZIGBEE_RX], pin[GPIO_ZIGBEE_TX], seriallog_level ? 1 : 2, 0, 256); - ZigbeeSerial->begin(115200); - if (ZigbeeSerial->hardwareSerial()) { - ClaimSerial(); - uint32_t aligned_buffer = ((uint32_t)serial_in_buffer + 3) & ~3; - zigbee_buffer = new PreAllocatedSBuffer(sizeof(serial_in_buffer) - 3, (char*) aligned_buffer); - } else { - - zigbee_buffer = new SBuffer(ZIGBEE_BUFFER_SIZE); - - } - zigbee.active = true; - zigbee.init_phase = true; - zigbee.state_machine = true; - ZigbeeSerial->flush(); - } - -} - - - - - -uint32_t strToUInt(const JsonVariant &val) { - - if (val.is()) { - return val.as(); - } else { - if (val.is()) { - String sval = val.as(); - return strtoull(sval.c_str(), nullptr, 0); - } - } - return 0; -} - - -const unsigned char ZIGBEE_FACTORY_RESET[] PROGMEM = - { Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 , 0x01 }; - -void CmndZbReset(void) { - if (ZigbeeSerial) { - switch (XdrvMailbox.payload) { - case 1: - ZigbeeZNPSend(ZIGBEE_FACTORY_RESET, sizeof(ZIGBEE_FACTORY_RESET)); - eraseZigbeeDevices(); - restart_flag = 2; - ResponseCmndChar_P(PSTR(D_JSON_ZIGBEE_CC2530 " " D_JSON_RESET_AND_RESTARTING)); - break; - default: - ResponseCmndChar_P(PSTR(D_JSON_ONE_TO_RESET)); - } - } -} - - - - - -void CmndZbZNPSendOrReceive(bool send) -{ - if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) { - uint8_t code; - - char *codes = RemoveSpace(XdrvMailbox.data); - int32_t size = strlen(XdrvMailbox.data); - - SBuffer buf((size+1)/2); - - while (size > 1) { - char stemp[3]; - strlcpy(stemp, codes, sizeof(stemp)); - code = strtol(stemp, nullptr, 16); - buf.add8(code); - size -= 2; - codes += 2; - } - if (send) { - - ZigbeeZNPSend(buf.getBuffer(), buf.len()); - } else { - - ZigbeeProcessInput(buf); - } - } - ResponseCmndDone(); -} - - -void CmndZbZNPReceive(void) -{ - CmndZbZNPSendOrReceive(false); -} - -void CmndZbZNPSend(void) -{ - CmndZbZNPSendOrReceive(true); -} - -void ZigbeeZNPSend(const uint8_t *msg, size_t len) { - if ((len < 2) || (len > 252)) { - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEEZNPSENT ": bad message len %d"), len); - return; - } - uint8_t data_len = len - 2; - - if (ZigbeeSerial) { - uint8_t fcs = data_len; - - ZigbeeSerial->write(ZIGBEE_SOF); - - ZigbeeSerial->write(data_len); - - for (uint32_t i = 0; i < len; i++) { - uint8_t b = pgm_read_byte(msg + i); - ZigbeeSerial->write(b); - fcs ^= b; - - } - ZigbeeSerial->write(fcs); - - } - - char hex_char[(len * 2) + 2]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %s"), - ToHex_P(msg, len, hex_char, sizeof(hex_char))); -} -# 312 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" -void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, uint16_t manuf, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId) { - - SBuffer buf(32+len); - buf.add8(Z_SREQ | Z_AF); - buf.add8(AF_DATA_REQUEST_EXT); - if (0x0000 == shortaddr) { - buf.add8(Z_Addr_Group); - buf.add64(groupaddr); - buf.add8(0xFF); - } else { - buf.add8(Z_Addr_ShortAddress); - buf.add64(shortaddr); - buf.add8(endpoint); - } - buf.add16(0x0000); - buf.add8(0x01); - buf.add16(clusterId); - buf.add8(transacId); - buf.add8(0x30); - buf.add8(0x1E); - - buf.add16(3 + len + (manuf ? 2 : 0)); - buf.add8((needResponse ? 0x00 : 0x10) | (clusterSpecific ? 0x01 : 0x00) | (manuf ? 0x04 : 0x00)); - if (manuf) { - buf.add16(manuf); - } - buf.add8(transacId); - buf.add8(cmdId); - if (len > 0) { - buf.addBuffer(msg, len); - } - - ZigbeeZNPSend(buf.getBuffer(), buf.len()); -} -# 363 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" -void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, bool clusterSpecific, uint16_t manuf, - uint16_t cluster, uint8_t cmd, const char *param) { - size_t size = param ? strlen(param) : 0; - SBuffer buf((size+2)/2); - - if (param) { - while (*param) { - uint8_t code = parseHex_P(¶m, 2); - buf.add8(code); - } - } - - if ((0 == endpoint) && (shortaddr)) { - - endpoint = zigbee_devices.findFirstEndpoint(shortaddr); - - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"), - shortaddr, groupaddr, cluster, endpoint, cmd, param); - - if ((0 == endpoint) && (shortaddr)) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint")); - return; - } - - - ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, cmd, clusterSpecific, manuf, buf.getBuffer(), buf.len(), true, zigbee_devices.getNextSeqNumber(shortaddr)); - - if (clusterSpecific) { - zigbeeSetCommandTimer(shortaddr, groupaddr, cluster, endpoint); - } -} - - - - -void CmndZbSend(void) { -# 411 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - DynamicJsonBuffer jsonBuf; - const JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data); - if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; } - - - static char delim[] = ", "; - uint16_t device = 0x0000; - uint16_t groupaddr = 0x0000; - uint8_t endpoint = 0x00; - uint16_t manuf = 0x0000; - - uint16_t cluster = 0; - uint8_t cmd = 0; - String cmd_str = ""; - const char *cmd_s; - bool clusterSpecific = true; - - - const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); - if (nullptr != &val_device) { - device = zigbee_devices.parseDeviceParam(val_device.as()); - if (0xFFFF == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - } - if (0x0000 == device) { - const JsonVariant &val_group = getCaseInsensitive(json, PSTR("Group")); - if (nullptr != &val_group) { - groupaddr = strToUInt(val_group); - } else { - ResponseCmndChar_P(PSTR("Unknown device")); - return; - } - } - - const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("Endpoint")); - if (nullptr != &val_endpoint) { endpoint = strToUInt(val_endpoint); } - const JsonVariant &val_manuf = getCaseInsensitive(json, PSTR("Manuf")); - if (nullptr != &val_manuf) { manuf = strToUInt(val_manuf); } - const JsonVariant &val_cmd = getCaseInsensitive(json, PSTR("Send")); - if (nullptr != &val_cmd) { - - - - if (val_cmd.is()) { - - const JsonObject &cmd_obj = val_cmd.as(); - int32_t cmd_size = cmd_obj.size(); - if (cmd_size > 1) { - Response_P(PSTR("Only 1 command allowed (%d)"), cmd_size); - return; - } else if (1 == cmd_size) { - - JsonObject::const_iterator it = cmd_obj.begin(); - String key = it->key; - const JsonVariant& value = it->value; - uint32_t x = 0, y = 0, z = 0; - uint16_t cmd_var; - - const __FlashStringHelper* tasmota_cmd = zigbeeFindCommand(key.c_str(), &cluster, &cmd_var); - if (tasmota_cmd) { - cmd_str = tasmota_cmd; - } else { - Response_P(PSTR("Unrecognized zigbee command: %s"), key.c_str()); - return; - } - - - if (value.is()) { - x = value.as() ? 1 : 0; - } else if (value.is()) { - x = value.as(); - } else { - - const char *s_const = value.as(); - if (s_const != nullptr) { - char s[strlen(s_const)+1]; - strcpy(s, s_const); - if ((nullptr != s) && (0x00 != *s)) { - char *sval = strtok(s, delim); - if (sval) { - x = ZigbeeAliasOrNumber(sval); - sval = strtok(nullptr, delim); - if (sval) { - y = ZigbeeAliasOrNumber(sval); - sval = strtok(nullptr, delim); - if (sval) { - z = ZigbeeAliasOrNumber(sval); - } - } - } - } - } - } - - - if (0xFF == cmd_var) { - cmd = x; - x = y; - y = z; - } else { - cmd = cmd_var; - } - cmd_str = zigbeeCmdAddParams(cmd_str.c_str(), x, y, z); - - cmd_s = cmd_str.c_str(); - } else { - - } - } else if (val_cmd.is()) { - - cmd_str = val_cmd.as(); - - - - - const char * data = cmd_str.c_str(); - cluster = parseHex(&data, 4); - - - if (('_' == *data) || ('!' == *data)) { - if ('_' == *data) { clusterSpecific = false; } - data++; - } else { - ResponseCmndChar_P(PSTR("Wrong delimiter for payload")); - return; - } - - cmd = parseHex(&data, 2); - - - - if ('/' == *data) { data++; } - - cmd_s = data; - } else { - - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeZCLSend device: 0x%04X, group: 0x%04X, endpoint:%d, cluster:0x%04X, cmd:0x%02X, send:\"%s\""), - device, groupaddr, endpoint, cluster, cmd, cmd_s); - zigbeeZCLSendStr(device, groupaddr, endpoint, clusterSpecific, manuf, cluster, cmd, cmd_s); - ResponseCmndDone(); - } else { - Response_P(PSTR("Missing zigbee 'Send'")); - return; - } -} - - - - -void ZbBindUnbind(bool unbind) { - - - - - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - DynamicJsonBuffer jsonBuf; - const JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data); - if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; } - - - - uint16_t srcDevice = 0xFFFF; - uint16_t dstDevice = 0xFFFF; - uint64_t dstLongAddr = 0; - uint8_t endpoint = 0x00; - uint8_t toendpoint = 0x00; - uint16_t toGroup = 0x0000; - uint16_t cluster = 0; - uint32_t group = 0xFFFFFFFF; - - - - const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); - if (nullptr != &val_device) { - srcDevice = zigbee_devices.parseDeviceParam(val_device.as()); - if (0xFFFF == srcDevice) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - } - if ((nullptr == &val_device) || (0x0000 == srcDevice)) { ResponseCmndChar_P(PSTR("Unknown source device")); return; } - - uint64_t srcLongAddr = zigbee_devices.getDeviceLongAddr(srcDevice); - if (0 == srcLongAddr) { ResponseCmndChar_P(PSTR("Unknown source IEEE address")); return; } - - const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("Endpoint")); - if (nullptr != &val_endpoint) { endpoint = strToUInt(val_endpoint); } - - const JsonVariant &val_cluster = getCaseInsensitive(json, PSTR("Cluster")); - if (nullptr != &val_cluster) { cluster = strToUInt(val_cluster); } - - - - - - const JsonVariant &dst_device = getCaseInsensitive(json, PSTR("ToDevice")); - if (nullptr != &dst_device) { - dstDevice = zigbee_devices.parseDeviceParam(dst_device.as()); - if (0xFFFF == dstDevice) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - if (0x0000 == dstDevice) { - dstLongAddr = localIEEEAddr; - } else { - dstLongAddr = zigbee_devices.getDeviceLongAddr(dstDevice); - } - if (0 == dstLongAddr) { ResponseCmndChar_P(PSTR("Unknown dest IEEE address")); return; } - - const JsonVariant &val_toendpoint = getCaseInsensitive(json, PSTR("ToEndpoint")); - if (nullptr != &val_toendpoint) { toendpoint = strToUInt(val_endpoint); } else { toendpoint = endpoint; } - } - - - const JsonVariant &to_group = getCaseInsensitive(json, PSTR("ToGroup")); - if (nullptr != &to_group) { toGroup = strToUInt(to_group); } - - - if (toGroup && dstLongAddr) { ResponseCmndChar_P(PSTR("Cannot have both \"ToDevice\" and \"ToGroup\"")); return; } - if (!toGroup && !dstLongAddr) { ResponseCmndChar_P(PSTR("Missing \"ToDevice\" or \"ToGroup\"")); return; } - - SBuffer buf(34); - buf.add8(Z_SREQ | Z_ZDO); - if (unbind) { - buf.add8(ZDO_UNBIND_REQ); - } else { - buf.add8(ZDO_BIND_REQ); - } - buf.add16(srcDevice); - buf.add64(srcLongAddr); - buf.add8(endpoint); - buf.add16(cluster); - if (dstLongAddr) { - buf.add8(Z_Addr_IEEEAddress); - buf.add64(dstLongAddr); - buf.add8(toendpoint); - } else { - buf.add8(Z_Addr_Group); - buf.add16(toGroup); - } - - ZigbeeZNPSend(buf.getBuffer(), buf.len()); - - ResponseCmndDone(); -} - - - - -void CmndZbBind(void) { - ZbBindUnbind(false); -} - - - - -void CmndZbUnbind(void) { - ZbBindUnbind(true); -} - - - - -void CmndZbBindState(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - - SBuffer buf(10); - buf.add8(Z_SREQ | Z_ZDO); - buf.add8(ZDO_MGMT_BIND_REQ); - buf.add16(shortaddr); - buf.add8(0); - - ZigbeeZNPSend(buf.getBuffer(), buf.len()); - - ResponseCmndDone(); -} - - -void CmndZbProbe(void) { - CmndZbProbeOrPing(true); -} - - - - -void CmndZbProbeOrPing(boolean probe) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - - - Z_SendIEEEAddrReq(shortaddr); - if (probe) { - Z_SendActiveEpReq(shortaddr); - } - ResponseCmndDone(); -} - - -void CmndZbPing(void) { - CmndZbProbeOrPing(false); -} - - - - - -void CmndZbName(void) { - - - - - - - - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - - - char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); - - - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - - if (p == nullptr) { - const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); - Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), shortaddr, friendlyName ? friendlyName : ""); - } else { - zigbee_devices.setFriendlyName(shortaddr, p); - Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), shortaddr, p); - } -} - - - - - -void CmndZbModelId(void) { - - - - - - - - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - - - char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); - - - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - - if (p == nullptr) { - const char * modelId = zigbee_devices.getModelId(shortaddr); - Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), shortaddr, modelId ? modelId : ""); - } else { - zigbee_devices.setModelId(shortaddr, p); - Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_MODELID "\":\"%s\"}}"), shortaddr, p); - } -} - - - - -void CmndZbLight(void) { - - - - - - - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - - - char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); - - - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - - if (p) { - int8_t bulbtype = strtol(p, nullptr, 10); - if (bulbtype > 5) { bulbtype = 5; } - if (bulbtype < -1) { bulbtype = -1; } - zigbee_devices.setHueBulbtype(shortaddr, bulbtype); - } - String dump = zigbee_devices.dumpLightState(shortaddr); - Response_P(PSTR("{\"" D_PRFX_ZB D_CMND_ZIGBEE_LIGHT "\":%s}"), dump.c_str()); - - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_ZB D_CMND_ZIGBEE_LIGHT)); - XdrvRulesProcess(); - ResponseCmndDone(); -} - - - - - -void CmndZbForget(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - - - if (zigbee_devices.removeDevice(shortaddr)) { - ResponseCmndDone(); - } else { - ResponseCmndChar_P(PSTR("Unknown device")); - } -} - - - - - -void CmndZbSave(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - saveZigbeeDevices(); - ResponseCmndDone(); -} -# 849 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_23_zigbee_9_impl.ino" -void CmndZbRestore(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - DynamicJsonBuffer jsonBuf; - const JsonVariant json_parsed = jsonBuf.parse((const char*) XdrvMailbox.data); - const JsonVariant * json = &json_parsed; - bool success = false; - - - if (json_parsed.is()) { - success = json_parsed.as().success(); - } else if (json_parsed.is()) { - success = json_parsed.as().success(); - } - if (!success) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; } - - - const JsonVariant * zbstatus = &startsWithCaseInsensitive(*json, PSTR("ZbStatus")); - if (nullptr != zbstatus) { - json = zbstatus; - } - - - if (json->is()) { - const JsonArray& arr = json->as(); - for (auto elt : arr) { - - int32_t res = zigbee_devices.deviceRestore(elt); - if (res < 0) { - ResponseCmndChar_P(PSTR("Restore failed")); - return; - } - } - } else if (json->is()) { - int32_t res = zigbee_devices.deviceRestore(*json); - if (res < 0) { - ResponseCmndChar_P(PSTR("Restore failed")); - return; - } - - } else { - ResponseCmndChar_P(PSTR("Missing parameters")); - return; - } - ResponseCmndDone(); -} - - - - - -void CmndZbRead(void) { - - - - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - DynamicJsonBuffer jsonBuf; - JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data); - if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; } - - - uint16_t device = 0xFFFF; - uint16_t groupaddr = 0x0000; - uint16_t cluster = 0x0000; - uint8_t endpoint = 0x00; - uint16_t manuf = 0x0000; - size_t attrs_len = 0; - uint8_t* attrs = nullptr; - - const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); - if (nullptr != &val_device) { - device = zigbee_devices.parseDeviceParam(val_device.as()); - if (0xFFFF == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - } - if (0x0000 == device) { - const JsonVariant &val_group = getCaseInsensitive(json, PSTR("Group")); - if (nullptr != &val_group) { - groupaddr = strToUInt(val_group); - } else { - ResponseCmndChar_P(PSTR("Unknown device")); - return; - } - } - - const JsonVariant &val_cluster = getCaseInsensitive(json, PSTR("Cluster")); - if (nullptr != &val_cluster) { cluster = strToUInt(val_cluster); } - const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("Endpoint")); - if (nullptr != &val_endpoint) { endpoint = strToUInt(val_endpoint); } - const JsonVariant &val_manuf = getCaseInsensitive(json, PSTR("Manuf")); - if (nullptr != &val_manuf) { manuf = strToUInt(val_manuf); } - - const JsonVariant &val_attr = getCaseInsensitive(json, PSTR("Read")); - if (nullptr != &val_attr) { - uint16_t val = strToUInt(val_attr); - if (val_attr.is()) { - const JsonArray& attr_arr = val_attr.as(); - attrs_len = attr_arr.size() * 2; - attrs = new uint8_t[attrs_len]; - - uint32_t i = 0; - for (auto value : attr_arr) { - uint16_t val = strToUInt(value); - attrs[i++] = val & 0xFF; - attrs[i++] = val >> 8; - } - } else { - attrs_len = 2; - attrs = new uint8_t[attrs_len]; - attrs[0] = val & 0xFF; - attrs[1] = val >> 8; - } - } - - if ((0 == endpoint) && (device)) { - endpoint = zigbee_devices.findFirstEndpoint(device); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint); - } - if (0x0000 == device) { - endpoint = 0xFF; - } - - if ((0 != endpoint) && (attrs_len > 0)) { - ZigbeeZCLSend_Raw(device, groupaddr, cluster, endpoint, ZCL_READ_ATTRIBUTES, false, manuf, attrs, attrs_len, true , zigbee_devices.getNextSeqNumber(device)); - ResponseCmndDone(); - } else { - ResponseCmndChar_P(PSTR("Missing parameters")); - } - - if (attrs) { delete[] attrs; } -} - - - - - -void CmndZbPermitJoin(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint32_t payload = XdrvMailbox.payload; - uint16_t dstAddr = 0xFFFC; - uint8_t duration = 60; - - if (payload <= 0) { - duration = 0; - } else if (99 == payload) { - duration = 0xFF; - } - - SBuffer buf(34); - buf.add8(Z_SREQ | Z_ZDO); - buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); - buf.add8(0x0F); - buf.add16(0xFFFC); - buf.add8(duration); - buf.add8(0x00); - - ZigbeeZNPSend(buf.getBuffer(), buf.len()); - - ResponseCmndDone(); -} - - - - -void CmndZbStatus(void) { - if (ZigbeeSerial) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); - if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } - if (XdrvMailbox.payload > 0) { - if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } - } - - String dump = zigbee_devices.dump(XdrvMailbox.index, shortaddr); - Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str()); - } -} - - - - -void CmndZbConfig(void) { - - - uint8_t zb_channel = Settings.zb_channel; - uint16_t zb_pan_id = Settings.zb_pan_id; - uint64_t zb_ext_panid = Settings.zb_ext_panid; - uint64_t zb_precfgkey_l = Settings.zb_precfgkey_l; - uint64_t zb_precfgkey_h = Settings.zb_precfgkey_h; - - - RemoveAllSpaces(XdrvMailbox.data); - if (strlen(XdrvMailbox.data) > 0) { - DynamicJsonBuffer jsonBuf; - const JsonObject &json = jsonBuf.parseObject((const char*) XdrvMailbox.data); - if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; } - - - const JsonVariant &val_channel = getCaseInsensitive(json, PSTR("Channel")); - if (nullptr != &val_channel) { zb_channel = strToUInt(val_channel); } - if (zb_channel < 11) { zb_channel = 11; } - if (zb_channel > 26) { zb_channel = 26; } - - const JsonVariant &val_pan_id = getCaseInsensitive(json, PSTR("PanID")); - if (nullptr != &val_pan_id) { zb_pan_id = strToUInt(val_pan_id); } - - const JsonVariant &val_ext_pan_id = getCaseInsensitive(json, PSTR("ExtPanID")); - if (nullptr != &val_ext_pan_id) { zb_ext_panid = strtoull(val_ext_pan_id.as(), nullptr, 0); } - - const JsonVariant &val_key_l = getCaseInsensitive(json, PSTR("KeyL")); - if (nullptr != &val_key_l) { zb_precfgkey_l = strtoull(val_key_l.as(), nullptr, 0); } - - const JsonVariant &val_key_h = getCaseInsensitive(json, PSTR("KeyH")); - if (nullptr != &val_key_h) { zb_precfgkey_h = strtoull(val_key_h.as(), nullptr, 0); } - - - if ( (zb_channel != Settings.zb_channel) || - (zb_pan_id != Settings.zb_pan_id) || - (zb_ext_panid != Settings.zb_ext_panid) || - (zb_precfgkey_l != Settings.zb_precfgkey_l) || - (zb_precfgkey_h != Settings.zb_precfgkey_h) ) { - Settings.zb_channel = zb_channel; - Settings.zb_pan_id = zb_pan_id; - Settings.zb_ext_panid = zb_ext_panid; - Settings.zb_precfgkey_l = zb_precfgkey_l; - Settings.zb_precfgkey_h = zb_precfgkey_h; - restart_flag = 2; - } - } - - - char hex_ext_panid[20] = "0x"; - Uint64toHex(zb_ext_panid, &hex_ext_panid[2], 64); - char hex_precfgkey_l[20] = "0x"; - Uint64toHex(zb_precfgkey_l, &hex_precfgkey_l[2], 64); - char hex_precfgkey_h[20] = "0x"; - Uint64toHex(zb_precfgkey_h, &hex_precfgkey_h[2], 64); - - - Response_P(PSTR("{\"" D_PRFX_ZB D_JSON_ZIGBEE_CONFIG "\":{" - "\"Channel\":%d" - ",\"PanID\":\"0x%04X\"" - ",\"ExtPanID\":\"%s\"" - ",\"KeyL\":\"%s\"" - ",\"KeyH\":\"%s\"" - "}}"), - zb_channel, zb_pan_id, - hex_ext_panid, - hex_precfgkey_l, hex_precfgkey_h); -} - - - - - -bool Xdrv23(uint8_t function) -{ - bool result = false; - - if (zigbee.active) { - switch (function) { - case FUNC_EVERY_50_MSECOND: - if (!zigbee.init_phase) { - zigbee_devices.runTimer(); - } - break; - case FUNC_LOOP: - if (ZigbeeSerial) { ZigbeeInputLoop(); } - if (zigbee.state_machine) { - ZigbeeStateMachine_Run(); - } - break; - case FUNC_PRE_INIT: - ZigbeeInit(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kZbCommands, ZigbeeCommand); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_24_buzzer.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_24_buzzer.ino" -#ifdef USE_BUZZER - - - - -#define XDRV_24 24 - -struct BUZZER { - uint32_t tune = 0; - uint32_t tune_reload = 0; - bool active = true; - bool enable = false; - uint8_t inverted = 0; - uint8_t count = 0; - uint8_t mode = 0; - uint8_t set[2]; - uint8_t duration; - uint8_t state = 0; -} Buzzer; - - - -void BuzzerOff(void) -{ - DigitalWrite(GPIO_BUZZER, Buzzer.inverted); -} - - -void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune, uint32_t mode) -{ - Buzzer.set[0] = off; - Buzzer.set[1] = on; - Buzzer.duration = 1; - Buzzer.tune_reload = 0; - Buzzer.mode = mode; - - if (tune) { - uint32_t tune1 = tune; - uint32_t tune2 = tune; - for (uint32_t i = 0; i < 32; i++) { - if (!(tune2 & 0x80000000)) { - tune2 <<= 1; - } else { - Buzzer.tune_reload <<= 1; - Buzzer.tune_reload |= tune1 & 1; - tune1 >>= 1; - } - } - Buzzer.tune = Buzzer.tune_reload; - } - Buzzer.count = count * 2; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BUZ: %d(%d),%d,%d,0x%08X(0x%08X)"), count, Buzzer.count, on, off, tune, Buzzer.tune); - - Buzzer.enable = (Buzzer.count > 0); - if (!Buzzer.enable) { - BuzzerOff(); - } -} - -void BuzzerSetStateToLed(uint32_t state) -{ - if (Buzzer.enable && (2 == Buzzer.mode)) { - Buzzer.state = (state != 0); - DigitalWrite(GPIO_BUZZER, (Buzzer.inverted) ? !Buzzer.state : Buzzer.state); - } -} - -void BuzzerBeep(uint32_t count) -{ - BuzzerBeep(count, 1, 1, 0, 0); -} - -void BuzzerEnabledBeep(uint32_t count, uint32_t duration) -{ - if (Settings.flag3.buzzer_enable) { - BuzzerBeep(count, duration, 1, 0, 0); - } -} - - - -bool BuzzerPinState(void) -{ - if (XdrvMailbox.index == GPIO_BUZZER_INV) { - Buzzer.inverted = 1; - XdrvMailbox.index -= (GPIO_BUZZER_INV - GPIO_BUZZER); - return true; - } - return false; -} - -void BuzzerInit(void) -{ - if (pin[GPIO_BUZZER] < 99) { - pinMode(pin[GPIO_BUZZER], OUTPUT); - BuzzerOff(); - } else { - Buzzer.active = false; - } -} - -void BuzzerEvery100mSec(void) -{ - if (Buzzer.enable && (Buzzer.mode != 2)) { - if (Buzzer.count) { - if (Buzzer.duration) { - Buzzer.duration--; - if (!Buzzer.duration) { - if (Buzzer.tune) { - Buzzer.state = Buzzer.tune & 1; - Buzzer.tune >>= 1; - } else { - Buzzer.tune = Buzzer.tune_reload; - Buzzer.count -= (Buzzer.tune_reload) ? 2 : 1; - Buzzer.state = Buzzer.count & 1; - if (Buzzer.mode) { - Buzzer.count |= 2; - } - } - Buzzer.duration = Buzzer.set[Buzzer.state]; - } - } - DigitalWrite(GPIO_BUZZER, (Buzzer.inverted) ? !Buzzer.state : Buzzer.state); - } else { - Buzzer.enable = false; - } - } -} - - - - - -const char kBuzzerCommands[] PROGMEM = "|" - "Buzzer" ; - -void (* const BuzzerCommand[])(void) PROGMEM = { - &CmndBuzzer }; - -void CmndBuzzer(void) -{ -# 174 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_24_buzzer.ino" - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload != 0) { - uint32_t parm[4] = { 0 }; - uint32_t mode = 0; - ParseParameters(4, parm); - if (XdrvMailbox.payload <= 0) { - parm[0] = 1; - mode = -XdrvMailbox.payload; - } - for (uint32_t i = 1; i < 3; i++) { - if (parm[i] < 1) { parm[i] = 1; } - } - BuzzerBeep(parm[0], parm[1], parm[2], parm[3], mode); - } else { - BuzzerBeep(0); - } - } else { - BuzzerBeep(1); - } - ResponseCmndDone(); -} - - - - - -bool Xdrv24(uint8_t function) -{ - bool result = false; - - if (Buzzer.active) { - switch (function) { - case FUNC_EVERY_100_MSECOND: - BuzzerEvery100mSec(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kBuzzerCommands, BuzzerCommand); - break; - case FUNC_PRE_INIT: - BuzzerInit(); - break; - case FUNC_PIN_STATE: - result = BuzzerPinState(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_25_A4988_Stepper.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_25_A4988_Stepper.ino" -#ifdef USE_A4988_STEPPER - - - - -#define XDRV_25 25 - -#include - -short A4988_dir_pin = pin[GPIO_MAX]; -short A4988_stp_pin = pin[GPIO_MAX]; -short A4988_ms1_pin = pin[GPIO_MAX]; -short A4988_ms2_pin = pin[GPIO_MAX]; -short A4988_ms3_pin = pin[GPIO_MAX]; -short A4988_ena_pin = pin[GPIO_MAX]; -int A4988_spr = 0; -float A4988_rpm = 0; -short A4988_mis = 0; - -A4988_Stepper* myA4988 = nullptr; - -void A4988Init(void) -{ - A4988_dir_pin = pin[GPIO_A4988_DIR]; - A4988_stp_pin = pin[GPIO_A4988_STP]; - A4988_ena_pin = pin[GPIO_A4988_ENA]; - A4988_ms1_pin = pin[GPIO_A4988_MS1]; - A4988_ms2_pin = pin[GPIO_A4988_MS2]; - A4988_ms3_pin = pin[GPIO_A4988_MS3]; - A4988_spr = 200; - A4988_rpm = 30; - A4988_mis = 1; - - myA4988 = new A4988_Stepper( A4988_spr - , A4988_rpm - , A4988_mis - , A4988_dir_pin - , A4988_stp_pin - , A4988_ena_pin - , A4988_ms1_pin - , A4988_ms2_pin - , A4988_ms3_pin ); -} - -const char kA4988Commands[] PROGMEM = "Motor|" - "Move|Rotate|Turn|MIS|SPR|RPM"; - -void (* const A4988Command[])(void) PROGMEM = { - &CmndDoMove,&CmndDoRotate,&CmndDoTurn,&CmndSetMIS,&CmndSetSPR,&CmndSetRPM}; - -void CmndDoMove(void) { - if (XdrvMailbox.data_len > 0) { - long stepsPlease = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->doMove(stepsPlease); - ResponseCmndDone(); - } -} - -void CmndDoRotate(void) { - if (XdrvMailbox.data_len > 0) { - long degrsPlease = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->doRotate(degrsPlease); - ResponseCmndDone(); - } -} - -void CmndDoTurn(void) { - if (XdrvMailbox.data_len > 0) { - float turnsPlease = strtod(XdrvMailbox.data,nullptr); - myA4988->doTurn(turnsPlease); - ResponseCmndDone(); - } -} - -void CmndSetMIS(void) { - if ((pin[GPIO_A4988_MS1] < 99) && (pin[GPIO_A4988_MS2] < 99) && (pin[GPIO_A4988_MS3] < 99) && (XdrvMailbox.data_len > 0)) { - short newMIS = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->setMIS(newMIS); - ResponseCmndDone(); - } -} - -void CmndSetSPR(void) { - if (XdrvMailbox.data_len > 0) { - int newSPR = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->setSPR(newSPR); - ResponseCmndDone(); - } -} - -void CmndSetRPM(void) { - if (XdrvMailbox.data_len > 0) { - short newRPM = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->setRPM(newRPM); - ResponseCmndDone(); - } -} - - - - -bool Xdrv25(uint8_t function) -{ - bool result = false; - if ((pin[GPIO_A4988_DIR] < 99) && (pin[GPIO_A4988_STP] < 99)) { - switch (function) { - case FUNC_INIT: - A4988Init(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kA4988Commands, A4988Command); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_26_ariluxrf.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_26_ariluxrf.ino" -#ifdef USE_LIGHT -#ifdef USE_ARILUX_RF - - - - -#define XDRV_26 26 - -const uint32_t ARILUX_RF_TIME_AVOID_DUPLICATE = 1000; - -const uint8_t ARILUX_RF_MAX_CHANGES = 51; -const uint32_t ARILUX_RF_SEPARATION_LIMIT = 4300; -const uint32_t ARILUX_RF_RECEIVE_TOLERANCE = 60; - -struct ARILUX { - unsigned int rf_timings[ARILUX_RF_MAX_CHANGES]; - - unsigned long rf_received_value = 0; - unsigned long rf_last_received_value = 0; - unsigned long rf_last_time = 0; - unsigned long rf_lasttime = 0; - - unsigned int rf_change_count = 0; - unsigned int rf_repeat_count = 0; - - uint8_t rf_toggle = 0; -} Arilux; - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 -#ifndef USE_WS2812_DMA -void AriluxRfInterrupt(void) ICACHE_RAM_ATTR; -#endif -#endif - -void AriluxRfInterrupt(void) -{ - unsigned long time = micros(); - unsigned int duration = time - Arilux.rf_lasttime; - - if (duration > ARILUX_RF_SEPARATION_LIMIT) { - if (abs(duration - Arilux.rf_timings[0]) < 200) { - Arilux.rf_repeat_count++; - if (Arilux.rf_repeat_count == 2) { - unsigned long code = 0; - const unsigned int delay = Arilux.rf_timings[0] / 31; - const unsigned int delayTolerance = delay * ARILUX_RF_RECEIVE_TOLERANCE / 100; - for (unsigned int i = 1; i < Arilux.rf_change_count -1; i += 2) { - code <<= 1; - if (abs(Arilux.rf_timings[i] - (delay *3)) < delayTolerance && abs(Arilux.rf_timings[i +1] - delay) < delayTolerance) { - code |= 1; - } - } - if (Arilux.rf_change_count > 49) { - Arilux.rf_received_value = code; - } - Arilux.rf_repeat_count = 0; - } - } - Arilux.rf_change_count = 0; - } - if (Arilux.rf_change_count >= ARILUX_RF_MAX_CHANGES) { - Arilux.rf_change_count = 0; - Arilux.rf_repeat_count = 0; - } - Arilux.rf_timings[Arilux.rf_change_count++] = duration; - Arilux.rf_lasttime = time; -} - -void AriluxRfHandler(void) -{ - unsigned long now = millis(); - if (Arilux.rf_received_value && !((Arilux.rf_received_value == Arilux.rf_last_received_value) && (now - Arilux.rf_last_time < ARILUX_RF_TIME_AVOID_DUPLICATE))) { - Arilux.rf_last_received_value = Arilux.rf_received_value; - Arilux.rf_last_time = now; - - uint16_t hostcode = Arilux.rf_received_value >> 8 & 0xFFFF; - if (Settings.rf_code[1][6] == Settings.rf_code[1][7]) { - Settings.rf_code[1][6] = hostcode >> 8 & 0xFF; - Settings.rf_code[1][7] = hostcode & 0xFF; - } - uint16_t stored_hostcode = Settings.rf_code[1][6] << 8 | Settings.rf_code[1][7]; - - DEBUG_DRIVER_LOG(PSTR(D_LOG_RFR D_HOST D_CODE " 0x%04X, " D_RECEIVED " 0x%06X"), stored_hostcode, Arilux.rf_received_value); - - if (hostcode == stored_hostcode) { - char command[33]; - char value = '-'; - command[0] = '\0'; - uint8_t keycode = Arilux.rf_received_value & 0xFF; - switch (keycode) { - case 1: - case 3: - snprintf_P(command, sizeof(command), PSTR(D_CMND_POWER " %d"), (1 == keycode) ? 1 : 0); - break; - case 2: - Arilux.rf_toggle++; - Arilux.rf_toggle &= 0x3; - snprintf_P(command, sizeof(command), PSTR(D_CMND_COLOR " %d"), 200 + Arilux.rf_toggle); - break; - case 4: - value = '+'; - case 7: - snprintf_P(command, sizeof(command), PSTR(D_CMND_SPEED " %c"), value); - break; - case 5: - value = '+'; - case 8: - snprintf_P(command, sizeof(command), PSTR(D_CMND_SCHEME " %c"), value); - break; - case 6: - value = '+'; - case 9: - snprintf_P(command, sizeof(command), PSTR(D_CMND_DIMMER " %c"), value); - break; - default: { - if ((keycode >= 10) && (keycode <= 21)) { - snprintf_P(command, sizeof(command), PSTR(D_CMND_COLOR " %d"), keycode -9); - } - } - } - if (strlen(command)) { - ExecuteCommand(command, SRC_LIGHT); - } - } - } - Arilux.rf_received_value = 0; -} - -void AriluxRfInit(void) -{ - if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_ARIRFSEL] < 99)) { - if (Settings.last_module != Settings.module) { - Settings.rf_code[1][6] = 0; - Settings.rf_code[1][7] = 0; - Settings.last_module = Settings.module; - } - Arilux.rf_received_value = 0; - - digitalWrite(pin[GPIO_ARIRFSEL], 0); - attachInterrupt(pin[GPIO_ARIRFRCV], AriluxRfInterrupt, CHANGE); - } -} - -void AriluxRfDisable(void) -{ - if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_ARIRFSEL] < 99)) { - detachInterrupt(pin[GPIO_ARIRFRCV]); - digitalWrite(pin[GPIO_ARIRFSEL], 1); - } -} - - - - - -bool Xdrv26(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_50_MSECOND: - if (pin[GPIO_ARIRFRCV] < 99) { AriluxRfHandler(); } - break; - case FUNC_EVERY_SECOND: - if (10 == uptime) { AriluxRfInit(); } - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_27_shutter.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_27_shutter.ino" -#ifdef USE_SHUTTER - - - - -#define XDRV_27 27 - -#define D_SHUTTER "SHUTTER" - -const uint16_t MOTOR_STOP_TIME = 500; -const uint8_t steps_per_second = 20; - -uint8_t calibrate_pos[6] = {0,30,50,70,90,100}; -uint16_t messwerte[5] = {30,50,70,90,100}; -uint16_t last_execute_step; - -enum ShutterModes { SHT_OFF_OPEN__OFF_CLOSE, SHT_OFF_ON__OPEN_CLOSE, SHT_PULSE_OPEN__PULSE_CLOSE, SHT_OFF_ON__OPEN_CLOSE_STEPPER,}; -enum ShutterButtonStates { SHT_NOT_PRESSED, SHT_PRESSED_MULTI, SHT_PRESSED_HOLD, SHT_PRESSED_IMMEDIATE, SHT_PRESSED_EXT_HOLD, SHT_PRESSED_MULTI_SIMULTANEOUS, SHT_PRESSED_HOLD_SIMULTANEOUS, SHT_PRESSED_EXT_HOLD_SIMULTANEOUS,}; - -const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|" - D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_TOGGLE "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|" - D_CMND_SHUTTER_OPENTIME "|" D_CMND_SHUTTER_CLOSETIME "|" D_CMND_SHUTTER_RELAY "|" - D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|" - D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME "|" D_CMND_SHUTTER_INVERTWEBBUTTONS "|" - D_CMND_SHUTTER_STOPOPEN "|" D_CMND_SHUTTER_STOPCLOSE "|" D_CMND_SHUTTER_STOPTOGGLE "|" D_CMND_SHUTTER_STOPPOSITION; - -void (* const ShutterCommand[])(void) PROGMEM = { - &CmndShutterOpen, &CmndShutterClose, &CmndShutterToggle, &CmndShutterStop, &CmndShutterPosition, - &CmndShutterOpenTime, &CmndShutterCloseTime, &CmndShutterRelay, - &CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay, - &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime, &CmndShutterInvertWebButtons, - &CmndShutterStopOpen, &CmndShutterStopClose, &CmndShutterStopToggle, &CmndShutterStopPosition}; - - const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d}"; - const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}"; - -#include - -Ticker TickerShutter; - -struct SHUTTER { - power_t mask = 0; - power_t old_power = 0; - power_t switched_relay = 0; - uint32_t time[MAX_SHUTTERS]; - int32_t open_max[MAX_SHUTTERS]; - int32_t target_position[MAX_SHUTTERS]; - int32_t start_position[MAX_SHUTTERS]; - int32_t real_position[MAX_SHUTTERS]; - uint16_t open_time[MAX_SHUTTERS]; - uint16_t close_time[MAX_SHUTTERS]; - uint16_t close_velocity[MAX_SHUTTERS]; - int8_t direction[MAX_SHUTTERS]; - uint8_t mode = 0; - int16_t motordelay[MAX_SHUTTERS]; - int16_t pwm_frequency[MAX_SHUTTERS]; - uint16_t max_pwm_frequency = 1000; - uint16_t max_close_pwm_frequency[MAX_SHUTTERS]; - uint8_t skip_relay_change; - int32_t accelerator[MAX_SHUTTERS]; - uint8_t start_reported = 0; -} Shutter; - -void ShutterLogPos(uint32_t i) -{ - char stemp2[10]; - dtostrfd((float)Shutter.time[i] / steps_per_second, 2, stemp2); - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter%d Real %d, Start %d, Stop %d, Dir %d, Delay %d, Rtc %s [s], Freq %d"), - i+1, Shutter.real_position[i], Shutter.start_position[i], Shutter.target_position[i], Shutter.direction[i], Shutter.motordelay[i], stemp2, Shutter.pwm_frequency[i]); -} - -void ShutterRtc50mS(void) -{ - for (uint8_t i = 0; i < shutters_present; i++) { - Shutter.time[i]++; - if (Shutter.accelerator[i]) { - - Shutter.pwm_frequency[i] += Shutter.accelerator[i]; - Shutter.pwm_frequency[i] = tmax(0,tmin(Shutter.direction[i]==1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i],Shutter.pwm_frequency[i])); - analogWriteFreq(Shutter.pwm_frequency[i]); - analogWrite(pin[GPIO_PWM1+i], 50); - } - } -} - -#define SHT_DIV_ROUND(__A,__B) (((__A) + (__B)/2) / (__B)) - -int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index) -{ - if (Settings.shutter_set50percent[index] != 50) { - return (percent <= 5) ? Settings.shuttercoeff[2][index] * percent : Settings.shuttercoeff[1][index] * percent + Settings.shuttercoeff[0][index]; - } else { - uint32_t realpos; - - for (uint32_t j = 0; j < 5; j++) { - if (0 == Settings.shuttercoeff[j][index]) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SHT: RESET/INIT CALIBRATION MATRIX DIV 0")); - for (uint32_t k = 0; k < 5; k++) { - Settings.shuttercoeff[k][index] = SHT_DIV_ROUND(calibrate_pos[k+1] * 1000, calibrate_pos[5]); - } - } - } - for (uint32_t i = 0; i < 5; i++) { - if ((percent * 10) >= Settings.shuttercoeff[i][index]) { - realpos = SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i+1], 100); - - } else { - if (0 == i) { - realpos = SHT_DIV_ROUND(SHT_DIV_ROUND(percent * Shutter.open_max[index] * calibrate_pos[i+1], Settings.shuttercoeff[i][index]), 10); - } else { - - - realpos += SHT_DIV_ROUND(SHT_DIV_ROUND((percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter.open_max[index] * (calibrate_pos[i+1] - calibrate_pos[i]), Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]), 100); - } - break; - } - } - return realpos; - } -} - -uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) -{ - if (Settings.shutter_set50percent[index] != 50) { - return (Settings.shuttercoeff[2][index] * 5 > realpos) ? SHT_DIV_ROUND(realpos, Settings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos-Settings.shuttercoeff[0][index], Settings.shuttercoeff[1][index]); - } else { - uint16_t realpercent; - - for (uint32_t i = 0; i < 5; i++) { - if (realpos >= Shutter.open_max[index] * calibrate_pos[i+1] / 100) { - realpercent = SHT_DIV_ROUND(Settings.shuttercoeff[i][index], 10); - - } else { - if (0 == i) { - realpercent = SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i], 100)) * 10 * Settings.shuttercoeff[i][index], calibrate_pos[i+1]), Shutter.open_max[index]); - } else { - - - - realpercent += SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i], 100)) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]), (calibrate_pos[i+1] - calibrate_pos[i])), Shutter.open_max[index]) ; - } - break; - } - } - return realpercent; - } -} - -void ShutterInit(void) -{ - shutters_present = 0; - Shutter.mask = 0; - - Shutter.old_power = power; - bool relay_in_interlock = false; - - - if (Settings.shutter_startrelay[MAX_SHUTTERS] == 0) { - Shutter.max_pwm_frequency = Settings.shuttercoeff[4][3] > 0 ? Settings.shuttercoeff[4][3] : Shutter.max_pwm_frequency; - } - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { - - Settings.shutter_startrelay[i] = (Settings.shutter_startrelay[i] == 0 && i == 0? 1 : Settings.shutter_startrelay[i]); - if (Settings.shutter_startrelay[i] && (Settings.shutter_startrelay[i] < 9)) { - shutters_present++; - - - Shutter.mask |= 3 << (Settings.shutter_startrelay[i] -1) ; - - for (uint32_t j = 0; j < MAX_INTERLOCKS * Settings.flag.interlock; j++) { - - if (Settings.interlock[j] && (Settings.interlock[j] & Shutter.mask)) { - - relay_in_interlock = true; - } - } - if (relay_in_interlock) { - if (Settings.pulse_timer[i] > 0) { - Shutter.mode = SHT_PULSE_OPEN__PULSE_CLOSE; - } else { - Shutter.mode = SHT_OFF_OPEN__OFF_CLOSE; - } - } else { - Shutter.mode = SHT_OFF_ON__OPEN_CLOSE; - if ((pin[GPIO_PWM1+i] < 99) && (pin[GPIO_CNTR1+i] < 99)) { - Shutter.mode = SHT_OFF_ON__OPEN_CLOSE_STEPPER; - Shutter.pwm_frequency[i] = 0; - Shutter.accelerator[i] = 0; - analogWriteFreq(Shutter.pwm_frequency[i]); - analogWrite(pin[GPIO_PWM1+i], 50); - } - } - - TickerShutter.attach_ms(50, ShutterRtc50mS ); - - Settings.shutter_set50percent[i] = (Settings.shutter_set50percent[i] > 0) ? Settings.shutter_set50percent[i] : 50; - - - Shutter.open_time[i] = (Settings.shutter_opentime[i] > 0) ? Settings.shutter_opentime[i] : 100; - Shutter.close_time[i] = (Settings.shutter_closetime[i] > 0) ? Settings.shutter_closetime[i] : 100; - - - Shutter.open_max[i] = 200 * Shutter.open_time[i]; - Shutter.close_velocity[i] = Shutter.open_max[i] / Shutter.close_time[i] / 2 ; - Shutter.max_close_pwm_frequency[i] = Shutter.max_pwm_frequency*Shutter.open_time[i] / Shutter.close_time[i]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d Closefreq: %d"),i, Shutter.max_close_pwm_frequency[i]); - - - if (Settings.shutter_set50percent[i] != 50) { - Settings.shuttercoeff[1][i] = Shutter.open_max[i] * (100 - Settings.shutter_set50percent[i] ) / 5000; - Settings.shuttercoeff[0][i] = Shutter.open_max[i] - (Settings.shuttercoeff[1][i] * 100); - Settings.shuttercoeff[2][i] = (Settings.shuttercoeff[0][i] + 5 * Settings.shuttercoeff[1][i]) / 5; - } - Shutter.mask |= 3 << (Settings.shutter_startrelay[i] -1); - - Shutter.real_position[i] = ShutterPercentToRealPosition(Settings.shutter_position[i], i); - - Shutter.start_position[i] = Shutter.target_position[i] = Shutter.real_position[i]; - Shutter.motordelay[i] = Settings.shutter_motordelay[i]; - - char shutter_open_chr[10]; - dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr); - char shutter_close_chr[10]; - dtostrfd((float)Shutter.close_time[i] / 10, 1, shutter_close_chr); - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100, Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoeffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, is locked %d, end stop time enabled %d, webButtons inverted %d, shuttermode %d, motordelay %d"), - i+1, Settings.shutter_startrelay[i], Shutter.real_position[i], Settings.shutter_position[i], Shutter.close_velocity[i], Shutter.open_max[i], shutter_open_chr, shutter_close_chr, - Settings.shuttercoeff[0][i], Settings.shuttercoeff[1][i], Settings.shuttercoeff[2][i], Settings.shuttercoeff[3][i], Settings.shuttercoeff[4][i], - Shutter.mask, (Settings.shutter_options[i]&1) ? 1 : 0, (Settings.shutter_options[i]&2) ? 1 : 0, (Settings.shutter_options[i]&4) ? 1 : 0, (Settings.shutter_options[i]&8) ? 1 : 0, Shutter.mode, Shutter.motordelay[i]); - - } else { - - break; - } - ShutterLimitRealAndTargetPositions(i); - Settings.shutter_accuracy = 1; - } -} - -void ShutterReportPosition(bool always) -{ - Response_P(PSTR("{")); - rules_flag.shutter_moving = 0; - for (uint32_t i = 0; i < shutters_present; i++) { - - uint32_t position = ShutterRealToPercentPosition(Shutter.real_position[i], i); - if (Shutter.direction[i] != 0) { - rules_flag.shutter_moving = 1; - ShutterLogPos(i); - } - if (i) { ResponseAppend_P(PSTR(",")); } - uint32_t target = ShutterRealToPercentPosition(Shutter.target_position[i], i); - ResponseAppend_P(JSON_SHUTTER_POS, i+1, (Settings.shutter_options[i] & 1) ? 100-position : position, Shutter.direction[i],(Settings.shutter_options[i] & 1) ? 100-target : target ); - } - ResponseJsonEnd(); - if (always || (rules_flag.shutter_moving)) { - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); - - } - - - -} - -void ShutterLimitRealAndTargetPositions(uint32_t i) { - if (Shutter.real_position[i]<0) Shutter.real_position[i] = 0; - if (Shutter.real_position[i]>Shutter.open_max[i]) Shutter.real_position[i] = Shutter.open_max[i]; - if (Shutter.target_position[i]<0) Shutter.target_position[i] = 0; - if (Shutter.target_position[i]>Shutter.open_max[i]) Shutter.target_position[i] = Shutter.open_max[i]; -} - -void ShutterUpdatePosition(void) -{ - - char scommand[CMDSZ]; - char stopic[TOPSZ]; - - for (uint32_t i = 0; i < shutters_present; i++) { - if (Shutter.direction[i] != 0) { - int32_t stop_position_delta = 20; - if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) { - - - Shutter.real_position[i] = ShutterCounterBasedPosition(i); - if (!Shutter.start_reported) { - ShutterReportPosition(true); - XdrvRulesProcess(); - Shutter.start_reported = 1; - } - - int32_t max_frequency = Shutter.direction[i] == 1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i]; - int32_t max_freq_change_per_sec = Shutter.max_pwm_frequency*steps_per_second / (Shutter.motordelay[i]>0 ? Shutter.motordelay[i] : 1); - int32_t min_runtime_ms = Shutter.pwm_frequency[i]*1000 / max_freq_change_per_sec; - int32_t velocity = Shutter.direction[i] == 1 ? 100 : Shutter.close_velocity[i]; - int32_t minstopway = min_runtime_ms * velocity / 100 * Shutter.pwm_frequency[i] / max_frequency * Shutter.direction[i] ; - - int32_t next_possible_stop = Shutter.real_position[i] + minstopway ; - stop_position_delta =200 * Shutter.pwm_frequency[i]/max_frequency + Shutter.direction[i] * (next_possible_stop - Shutter.target_position[i]); - - - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: time: %d, velocity %d, minstopway %d,cur_freq %d, max_frequency %d, act_freq_change %d, min_runtime_ms %d, act.pos %d, next_stop %d, target: %d"),Shutter.time[i],velocity,minstopway, - Shutter.pwm_frequency[i],max_frequency, Shutter.accelerator[i],min_runtime_ms,Shutter.real_position[i], next_possible_stop,Shutter.target_position[i]); - - if (Shutter.accelerator[i] < 0 || next_possible_stop * Shutter.direction[i] > (Shutter.target_position[i]- (100 * Shutter.direction[i])) * Shutter.direction[i] ) { - - Shutter.accelerator[i] = - tmin(tmax(max_freq_change_per_sec*(100-(Shutter.direction[i]*(Shutter.target_position[i]-next_possible_stop) ))/2000 , max_freq_change_per_sec*9/200), max_freq_change_per_sec*11/200); - - } else if ( Shutter.accelerator[i] > 0 && Shutter.pwm_frequency[i] == max_frequency) { - Shutter.accelerator[i] = 0; - } - } else { - Shutter.real_position[i] = Shutter.start_position[i] + ( (Shutter.time[i] - Shutter.motordelay[i]) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i])); - } - if ( Shutter.real_position[i] * Shutter.direction[i] + stop_position_delta >= Shutter.target_position[i] * Shutter.direction[i] ) { - - - uint8_t cur_relay = Settings.shutter_startrelay[i] + (Shutter.direction[i] == 1 ? 0 : 1) ; - int16_t missing_steps; - - switch (Shutter.mode) { - case SHT_PULSE_OPEN__PULSE_CLOSE: - - if (SRC_PULSETIMER == last_source || SRC_SHUTTER == last_source || SRC_WEBGUI == last_source) { - ExecuteCommandPower(cur_relay, 1, SRC_SHUTTER); - } else { - last_source = SRC_SHUTTER; - } - break; - case SHT_OFF_ON__OPEN_CLOSE_STEPPER: - missing_steps = ((Shutter.target_position[i]-Shutter.start_position[i])*Shutter.direction[i]*Shutter.max_pwm_frequency/2000) - RtcSettings.pulse_counter[i]; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Remain steps %d, counter %d, freq %d"), missing_steps, RtcSettings.pulse_counter[i] ,Shutter.pwm_frequency[i]); - Shutter.accelerator[i] = 0; - Shutter.pwm_frequency[i] = Shutter.pwm_frequency[i] > 250 ? 250 : Shutter.pwm_frequency[i]; - analogWriteFreq(Shutter.pwm_frequency[i]); - analogWrite(pin[GPIO_PWM1+i], 50); - Shutter.pwm_frequency[i] = 0; - analogWriteFreq(Shutter.pwm_frequency[i]); - while (RtcSettings.pulse_counter[i] < (uint32_t)(Shutter.target_position[i]-Shutter.start_position[i])*Shutter.direction[i]*Shutter.max_pwm_frequency/2000) { - delay(1); - } - analogWrite(pin[GPIO_PWM1+i], 0); - Shutter.real_position[i] = ShutterCounterBasedPosition(i); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Real %d, pulsecount %d, start %d"), Shutter.real_position[i],RtcSettings.pulse_counter[i], Shutter.start_position[i]); - - if ((1 << (Settings.shutter_startrelay[i]-1)) & power) { - ExecuteCommandPower(Settings.shutter_startrelay[i], 0, SRC_SHUTTER); - ExecuteCommandPower(Settings.shutter_startrelay[i]+1, 0, SRC_SHUTTER); - } - break; - case SHT_OFF_ON__OPEN_CLOSE: - if ((1 << (Settings.shutter_startrelay[i]-1)) & power) { - ExecuteCommandPower(Settings.shutter_startrelay[i], 0, SRC_SHUTTER); - ExecuteCommandPower(Settings.shutter_startrelay[i]+1, 0, SRC_SHUTTER); - } - break; - case SHT_OFF_OPEN__OFF_CLOSE: - - if ((1 << (cur_relay-1)) & power) { - - ExecuteCommandPower(cur_relay, 0, SRC_SHUTTER); - } - break; - } - ShutterLimitRealAndTargetPositions(i); - Settings.shutter_position[i] = ShutterRealToPercentPosition(Shutter.real_position[i], i); - - ShutterLogPos(i); - - Shutter.start_position[i] = Shutter.real_position[i]; - - - snprintf_P(scommand, sizeof(scommand),PSTR(D_SHUTTER "%d"), i+1); - GetTopic_P(stopic, STAT, mqtt_topic, scommand); - Response_P("%d", (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]); - MqttPublish(stopic, Settings.flag.mqtt_power_retain); - - Shutter.direction[i] = 0; - ShutterReportPosition(true); - rules_flag.shutter_moved = 1; - XdrvRulesProcess(); - } - } - } -} - -bool ShutterState(uint32_t device) -{ - device--; - device &= 3; - return (Settings.flag3.shutter_mode && - (Shutter.mask & (1 << (Settings.shutter_startrelay[device]-1))) ); -} - -void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos) -{ - - if ( ( (1 == direction) && ((Shutter.open_max[i] - Shutter.real_position[i]) / 100 <= 2) ) - || ( (-1 == direction) && (Shutter.real_position[i] / Shutter.close_velocity[i] <= 2)) ) { - Shutter.skip_relay_change = 1; - } else { - if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) { - Shutter.pwm_frequency[i] = 0; - analogWriteFreq(Shutter.pwm_frequency[i]); - analogWrite(pin[GPIO_PWM1+i], 0); - RtcSettings.pulse_counter[i] = 0; - Shutter.accelerator[i] = Shutter.max_pwm_frequency / (Shutter.motordelay[i]>0 ? Shutter.motordelay[i] : 1); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Ramp up: %d"), Shutter.accelerator[i]); - } - Shutter.target_position[i] = target_pos; - Shutter.start_position[i] = Shutter.real_position[i]; - Shutter.time[i] = 0; - Shutter.skip_relay_change = 0; - Shutter.direction[i] = direction; - rules_flag.shutter_moving = 1; - rules_flag.shutter_moved = 0; - Shutter.start_reported = 0; - - } - -} - -void ShutterWaitForMotorStop(uint32_t i) -{ - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Wait for Motorstop..")); - if ((SHT_OFF_ON__OPEN_CLOSE == Shutter.mode) || (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode)) { - if (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode) { - - while (Shutter.pwm_frequency[i] > 0) { - - Shutter.pwm_frequency[i] = tmax(Shutter.pwm_frequency[i]-((Shutter.direction[i] == 1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i])/(Shutter.motordelay[i]+1)) , 0); - - analogWriteFreq(Shutter.pwm_frequency[i]); - analogWrite(pin[GPIO_PWM1+i], 50); - delay(50); - } - analogWrite(pin[GPIO_PWM1+i], 0); - Shutter.real_position[i] = ShutterCounterBasedPosition(i); - } else { - ExecuteCommandPower(Settings.shutter_startrelay[i], 0, SRC_SHUTTER); - delay(MOTOR_STOP_TIME); - } - } else { - delay(MOTOR_STOP_TIME); - } -} - -int32_t ShutterCounterBasedPosition(uint32_t i) -{ - return ((int32_t)RtcSettings.pulse_counter[i]*Shutter.direction[i]*2000 / Shutter.max_pwm_frequency)+Shutter.start_position[i]; -} - -void ShutterRelayChanged(void) -{ - - - - - char stemp1[10]; - - for (uint32_t i = 0; i < shutters_present; i++) { - power_t powerstate_local = (power >> (Settings.shutter_startrelay[i] -1)) & 3; - - uint8 manual_relays_changed = ((Shutter.switched_relay >> (Settings.shutter_startrelay[i] -1)) & 3) && SRC_SHUTTER != last_source && SRC_PULSETIMER != last_source ; - - if (manual_relays_changed) { - - ShutterLimitRealAndTargetPositions(i); - if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE || Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) { - ShutterWaitForMotorStop(i); - switch (powerstate_local) { - case 1: - ShutterStartInit(i, 1, Shutter.open_max[i]); - break; - case 3: - ShutterStartInit(i, -1, 0); - break; - default: - - Shutter.target_position[i] = Shutter.real_position[i]; - } - } else { - if (Shutter.direction[i] != 0 && (!powerstate_local || (powerstate_local && Shutter.mode == SHT_PULSE_OPEN__PULSE_CLOSE))) { - Shutter.target_position[i] = Shutter.real_position[i]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: Switch OFF motor. Target: %ld, source: %s, powerstate_local %ld, Shutter.switched_relay %d, manual change %d"), i+1, Shutter.target_position[i], GetTextIndexed(stemp1, sizeof(stemp1), last_source, kCommandSource), powerstate_local,Shutter.switched_relay,manual_relays_changed); - } else { - last_source = SRC_SHUTTER; - if (powerstate_local == 2) { - - ShutterWaitForMotorStop(i); - ShutterStartInit(i, -1, 0); - } else { - - ShutterWaitForMotorStop(i); - ShutterStartInit(i, 1, Shutter.open_max[i]); - } - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: Target: %ld, powerstatelocal %d"), i+1, Shutter.target_position[i], powerstate_local); - } - } - } -} - -bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) { - - uint32 min_shutterbutton_hold_timer = -1; - for (uint32_t i = 0; i < MAX_KEYS; i++) { - if ((button_index != i) && (Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (Button.hold_timer[i] < min_shutterbutton_hold_timer)) - min_shutterbutton_hold_timer = Button.hold_timer[i]; - } - return ((-1 != min_shutterbutton_hold_timer) && (min_shutterbutton_hold_timer > (Button.hold_timer[button_index]>>1))); -} - -void ShutterButtonHandler(void) -{ - uint8_t buttonState = SHT_NOT_PRESSED; - uint8_t button = XdrvMailbox.payload; - uint8_t press_index; - uint32_t button_index = XdrvMailbox.index; - uint8_t shutter_index = Settings.shutter_button[button_index] & 0x03; - uint16_t loops_per_second = 1000 / Settings.button_debounce; - - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - if (Settings.flag.button_single) { - buttonState = SHT_PRESSED_MULTI; - press_index = 1; - } else { - if ((Shutter.direction[shutter_index]) && (Button.press_counter[button_index]==0)) { - buttonState = SHT_PRESSED_IMMEDIATE; - press_index = 1; - Button.press_counter[button_index] = 99; - } else { - Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; - - Button.window_timer[button_index] = (loops_per_second >> 2) * 3; - } - } - blinks = 201; - } - - if (NOT_PRESSED == button) { - Button.hold_timer[button_index] = 0; - } else { - Button.hold_timer[button_index]++; - if (!Settings.flag.button_single) { - if (Settings.param[P_HOLD_IGNORE] > 0) { - if (Button.hold_timer[button_index] > loops_per_second * Settings.param[P_HOLD_IGNORE] / 10) { - Button.hold_timer[button_index] = 0; - Button.press_counter[button_index] = 0; - } - } - if ((Button.press_counter[button_index]<99) && (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10)) { - - if (ShutterButtonIsSimultaneousHold(button_index, shutter_index)) { - - for (uint32_t i = 0; i < MAX_KEYS; i++) - if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index)) - Button.press_counter[i] = 99; - press_index = 0; - buttonState = SHT_PRESSED_HOLD_SIMULTANEOUS; - } - if (Button.press_counter[button_index]<99) { - press_index = 0; - buttonState = SHT_PRESSED_HOLD; - } - Button.press_counter[button_index] = 0; - } - if ((Button.press_counter[button_index]==0) && (Button.hold_timer[button_index] == loops_per_second * IMMINENT_RESET_FACTOR * Settings.param[P_HOLD_TIME] / 10)) { - press_index = -1; - - if (ShutterButtonIsSimultaneousHold(button_index, shutter_index)) { - - buttonState = SHT_PRESSED_EXT_HOLD_SIMULTANEOUS; - } else { - buttonState = SHT_PRESSED_EXT_HOLD; - } - } - } - } - - if (!Settings.flag.button_single) { - if (Button.window_timer[button_index]) { - Button.window_timer[button_index]--; - } else { - if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0)) { - if (Button.press_counter[button_index]<99) { - - uint32 min_shutterbutton_press_counter = -1; - for (uint32_t i = 0; i < MAX_KEYS; i++) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Settings.shutter_button[i] %ld, shutter_index %d, Button.press_counter[i] %d, min_shutterbutton_press_counter %d, i %d"), Settings.shutter_button[i], shutter_index, Button.press_counter[i] , min_shutterbutton_press_counter, i); - if ((button_index != i) && (Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (i != button_index) && (Button.press_counter[i] < min_shutterbutton_press_counter)) { - min_shutterbutton_press_counter = Button.press_counter[i]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: min_shutterbutton_press_counter %d"), min_shutterbutton_press_counter); - } - } - if (min_shutterbutton_press_counter == Button.press_counter[button_index]) { - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: simultanous presss deteced")); - press_index = Button.press_counter[button_index]; - for (uint32_t i = 0; i < MAX_KEYS; i++) - if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) != shutter_index)) - Button.press_counter[i] = 99; - buttonState = SHT_PRESSED_MULTI_SIMULTANEOUS; - } - if ((buttonState != SHT_PRESSED_MULTI_SIMULTANEOUS) && (Button.press_counter[button_index]<99)) { - - press_index = Button.press_counter[button_index]; - buttonState = SHT_PRESSED_MULTI; - } - } - Button.press_counter[button_index] = 0; - } - } - } - - if (buttonState != SHT_NOT_PRESSED) { - if ((!Settings.flag.button_restrict) && (((press_index>=5) && (press_index<=7)) || (buttonState == SHT_PRESSED_EXT_HOLD) || (buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS))){ - - uint8_t shutter_index_num_buttons = 0; - for (uint32_t i = 0; i < MAX_KEYS; i++) { - if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index)) { - shutter_index_num_buttons++; - } - } - if ((buttonState == SHT_PRESSED_MULTI_SIMULTANEOUS) || ((shutter_index_num_buttons==1) && (buttonState == SHT_PRESSED_MULTI))){ - - - char scmnd[20]; - GetTextIndexed(scmnd, sizeof(scmnd), press_index -3, kCommands); - ExecuteCommand(scmnd, SRC_BUTTON); - return; - } else if ((buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS) || ((shutter_index_num_buttons==1) && (buttonState == SHT_PRESSED_EXT_HOLD))){ - - - char scmnd[20]; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - return; - } - } - if (buttonState <= SHT_PRESSED_IMMEDIATE) { - if (Settings.shutter_startrelay[shutter_index] && Settings.shutter_startrelay[shutter_index] <9) { - uint8_t pos_press_index = (buttonState == SHT_PRESSED_HOLD) ? 3 : (press_index-1); - if (pos_press_index>3) pos_press_index=3; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: shutter %d, button %d = %d (single=1, double=2, tripple=3, hold=4)"), shutter_index+1, button_index+1, pos_press_index+1); - XdrvMailbox.index = shutter_index +1; - last_source = SRC_BUTTON; - XdrvMailbox.data_len = 0; - char databuf[1] = ""; - XdrvMailbox.data = databuf; - XdrvMailbox.command = NULL; - if (buttonState == SHT_PRESSED_IMMEDIATE) { - XdrvMailbox.payload = XdrvMailbox.index; - CmndShutterStop(); - } else { - uint8_t position = (Settings.shutter_button[button_index]>>(6*pos_press_index + 2)) & 0x03f; - if (position) { - if (Shutter.direction[shutter_index]) { - XdrvMailbox.payload = XdrvMailbox.index; - CmndShutterStop(); - } else { - XdrvMailbox.payload = position = (position-1)<<1; - - if (102 == position) { - XdrvMailbox.payload = XdrvMailbox.index; - CmndShutterToggle(); - } else { - CmndShutterPosition(); - } - if (Settings.shutter_button[button_index] & ((0x01<<26)< 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - if (Shutter.direction[index]) { - CmndShutterStop(); - } else { - CmndShutterOpen(); - } - } -} - -void CmndShutterClose(void) -{ - - if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { - XdrvMailbox.index = XdrvMailbox.payload; - } - XdrvMailbox.payload = 0; - XdrvMailbox.data_len = 0; - last_source = SRC_WEBGUI; - CmndShutterPosition(); -} - -void CmndShutterStopClose(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - if (Shutter.direction[index]) { - CmndShutterStop(); - } else { - CmndShutterClose(); - } - } -} - -void CmndShutterToggle(void) -{ - - if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { - XdrvMailbox.index = XdrvMailbox.payload; - } - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - XdrvMailbox.payload = (50 < ShutterRealToPercentPosition(Shutter.real_position[index], index)) ? 0 : 100; - XdrvMailbox.data_len = 0; - last_source = SRC_WEBGUI; - CmndShutterPosition(); - } -} - -void CmndShutterStopToggle(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - if (Shutter.direction[index]) { - CmndShutterStop(); - } else { - CmndShutterToggle(); - } - } -} - -void CmndShutterStop(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (!(Settings.shutter_options[XdrvMailbox.index-1] & 2)) { - if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { - XdrvMailbox.index = XdrvMailbox.payload; - } - uint32_t i = XdrvMailbox.index -1; - if (Shutter.direction[i] != 0) { - - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Stop moving %d: dir: %d"), XdrvMailbox.index, Shutter.direction[i]); - - int32_t temp_realpos = Shutter.start_position[i] + ( (Shutter.time[i]+10) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i])); - XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i); - - last_source = SRC_WEBGUI; - CmndShutterPosition(); - } else { - if (XdrvMailbox.command) - ResponseCmndDone(); - } - } else { - if (XdrvMailbox.command) - ResponseCmndIdxChar("Locked"); - } - } -} - -void CmndShutterPosition(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (!(Settings.shutter_options[XdrvMailbox.index-1] & 2)) { - uint32_t index = XdrvMailbox.index-1; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Pos. in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, last_source ); - - - - if ((XdrvMailbox.data_len > 1) && (XdrvMailbox.payload <= 0)) { - - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_UP) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_OPEN) || ((Shutter.direction[index]==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPOPEN))) { - CmndShutterOpen(); - return; - } - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_DOWN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_CLOSE) || ((Shutter.direction[index]==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPCLOSE))) { - CmndShutterClose(); - return; - } - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLE)) { - CmndShutterToggle(); - return; - } - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOP) || ((Shutter.direction[index]) && (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPOPEN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPCLOSE)))) { - XdrvMailbox.payload = -99; - CmndShutterStop(); - return; - } - } - - int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? (XdrvMailbox.payload == -99 ? ShutterRealToPercentPosition(Shutter.real_position[index], index) : 0) : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload); - - target_pos_percent = ((Settings.shutter_options[index] & 1) && (SRC_WEBGUI != last_source)) ? 100 - target_pos_percent : target_pos_percent; - if (XdrvMailbox.payload != -99) { - - Shutter.target_position[index] = ShutterPercentToRealPosition(target_pos_percent, index); - - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: lastsource %d:, real %d, target %d, payload %d"), last_source, Shutter.real_position[index] ,Shutter.target_position[index],target_pos_percent); - } - if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && abs(Shutter.target_position[index] - Shutter.real_position[index] ) / Shutter.close_velocity[index] > 2) { - if (Settings.shutter_options[index] & 4) { - if (0 == target_pos_percent) Shutter.target_position[index] -= 1 * 2000; - if (100 == target_pos_percent) Shutter.target_position[index] += 1 * 2000; - } - int8_t new_shutterdirection = Shutter.real_position[index] < Shutter.target_position[index] ? 1 : -1; - if (Shutter.direction[index] == -new_shutterdirection) { - - if (SHT_PULSE_OPEN__PULSE_CLOSE == Shutter.mode) { - - ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 0 : 1), 1, SRC_SHUTTER); - delay(100); - } else { - if (SHT_OFF_OPEN__OFF_CLOSE == Shutter.mode) { - ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 1 : 0), 0, SRC_SHUTTER); - ShutterWaitForMotorStop(index); - } - } - } - if (Shutter.direction[index] != new_shutterdirection) { - if ((SHT_OFF_ON__OPEN_CLOSE == Shutter.mode) || (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode)) { - - ShutterWaitForMotorStop(index); - ExecuteCommandPower(Settings.shutter_startrelay[index], 0, SRC_SHUTTER); - ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]); - if (Shutter.skip_relay_change == 0) { - - ExecuteCommandPower(Settings.shutter_startrelay[index] +1, new_shutterdirection == 1 ? 0 : 1, SRC_SHUTTER); - - ExecuteCommandPower(Settings.shutter_startrelay[index], 1, SRC_SHUTTER); - } - } else { - - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start in dir %d"), Shutter.direction[index]); - ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]); - if (Shutter.skip_relay_change == 0) { - ExecuteCommandPower(Settings.shutter_startrelay[index] + (new_shutterdirection == 1 ? 0 : 1), 1, SRC_SHUTTER); - } - - } - Shutter.switched_relay = 0; - } - } else { - target_pos_percent = ShutterRealToPercentPosition(Shutter.real_position[index], index); - ShutterReportPosition(true); - } - XdrvMailbox.index = index +1; - if (XdrvMailbox.command) - ResponseCmndIdxNumber((Settings.shutter_options[index] & 1) ? 100 - target_pos_percent : target_pos_percent); - } else { - ShutterReportPosition(true); - if (XdrvMailbox.command) - ResponseCmndIdxChar("Locked"); - } - } -} - -void CmndShutterStopPosition(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - if (Shutter.direction[index]) { - XdrvMailbox.payload = -99; - CmndShutterStop(); - } else { - CmndShutterPosition(); - } - } -} -void CmndShutterOpenTime(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.data_len > 0) { - Settings.shutter_opentime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data)); - ShutterInit(); - } - char time_chr[10]; - dtostrfd((float)(Settings.shutter_opentime[XdrvMailbox.index -1]) / 10, 1, time_chr); - ResponseCmndIdxChar(time_chr); - } -} - -void CmndShutterCloseTime(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.data_len > 0) { - Settings.shutter_closetime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data)); - ShutterInit(); - } - char time_chr[10]; - dtostrfd((float)(Settings.shutter_closetime[XdrvMailbox.index -1]) / 10, 1, time_chr); - ResponseCmndIdxChar(time_chr); - } -} - -void CmndShutterMotorDelay(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.data_len > 0) { - Settings.shutter_motordelay[XdrvMailbox.index -1] = (uint16_t)(steps_per_second * CharToFloat(XdrvMailbox.data)); - ShutterInit(); - } - char time_chr[10]; - dtostrfd((float)(Settings.shutter_motordelay[XdrvMailbox.index -1]) / steps_per_second, 2, time_chr); - ResponseCmndIdxChar(time_chr); - } -} - -void CmndShutterRelay(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SHUTTERS)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 64)) { - Settings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload; - if (XdrvMailbox.payload > 0) { - Shutter.mask |= 3 << (XdrvMailbox.payload - 1); - } else { - Shutter.mask ^= 3 << (Settings.shutter_startrelay[XdrvMailbox.index -1] - 1); - } - Settings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload; - ShutterInit(); - - } - ResponseCmndIdxNumber(Settings.shutter_startrelay[XdrvMailbox.index -1]); - } -} - -void CmndShutterButton(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SHUTTERS)) { - uint32_t setting = 0; -# 1010 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_27_shutter.ino" - if (XdrvMailbox.data_len > 0) { - uint32_t i = 0; - uint32_t button_index = 0; - bool done = false; - bool isShortCommand = false; - char *str_ptr; - - char data_copy[strlen(XdrvMailbox.data) +1]; - strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); - - for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < (1+4+4+1); str = strtok_r(nullptr, " ", &str_ptr), i++) { - int field; - switch (str[0]) { - case '-': - field = -1; - break; - case 't': - field = 102; - break; - default: - field = atoi(str); - break; - } - switch (i) { - case 0: - if ((field >= -1) && (field<=4)) { - button_index = (field<=0)?(-1):field; - done = (button_index==-1); - } else - done = true; - break; - case 1: - if (!strcmp_P(str, PSTR("up"))) { - setting |= (((100>>1)+1)<<2) | (((50>>1)+1)<<8) | (((75>>1)+1)<<14) | (((100>>1)+1)<<20); - isShortCommand = true; - break; - } else if (!strcmp_P(str, PSTR("down"))) { - setting |= (((0>>1)+1)<<2) | (((50>>1)+1)<<8) | (((25>>1)+1)<<14) | (((0>>1)+1)<<20); - isShortCommand = true; - break; - } else if (!strcmp_P(str, PSTR("updown"))) { - setting |= (((100>>1)+1)<<2) | (((0>>1)+1)<<8) | (((50>>1)+1)<<14); - isShortCommand = true; - break; - } else if (!strcmp_P(str, PSTR("toggle"))) { - setting |= (((102>>1)+1)<<2) | (((50>>1)+1)<<8); - isShortCommand = true; - break; - } - case 2: - if (isShortCommand) { - if ((field==1) && (setting & (0x3F<<(2+6*3)))) - - setting |= (0x3<<29); - done = true; - break; - } - case 3: - case 4: - if ((field >= -1) && (field<=102)) - setting |= (((field>>1)+1)<<(i*6 + (2-6))); - break; - case 5: - case 6: - case 7: - case 8: - case 9: - if (field==1) - setting |= (1<<(i + (26-5))); - break; - } - if (done) break; - } - - if (button_index) { - if (button_index==-1) { - - for (uint32_t i=0 ; i < MAX_KEYS ; i++) - if ((Settings.shutter_button[i]&0x3) == (XdrvMailbox.index-1)) - Settings.shutter_button[i] = 0; - } else { - if (setting) { - - setting |= (1<<31); - setting |= (XdrvMailbox.index-1) & 0x3; - } - Settings.shutter_button[button_index-1] = setting; - } - } - } - char setting_chr[30*MAX_KEYS] = "-", *setting_chr_ptr = setting_chr; - for (uint32_t i=0 ; i < MAX_KEYS ; i++) { - setting = Settings.shutter_button[i]; - if ((setting&(1<<31)) && ((setting&0x3) == (XdrvMailbox.index-1))) { - if (*setting_chr_ptr == 0) - setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR("|")); - setting_chr_ptr += snprintf_P(setting_chr_ptr, 2, PSTR("%d"), i+1); - - for (uint32_t j=0 ; j < 4 ; j++) { - int8_t pos = (((setting>> (2+6*j))&(0x3f))-1)<<1; - if (0 <= pos) - if (102 == pos) { - setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" t")); - } else { - setting_chr_ptr += snprintf_P(setting_chr_ptr, 5, PSTR(" %d"), pos); - } - else - setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" -")); - } - for (uint32_t j=0 ; j < 5 ; j++) { - bool mqtt = ((setting>>(26+j))&(0x01)!=0); - if (mqtt) - setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" 1")); - else - setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" -")); - } - } - } - ResponseCmndIdxChar(setting_chr); - } -} - -void CmndShutterSetHalfway(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - Settings.shutter_set50percent[XdrvMailbox.index -1] = (Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - XdrvMailbox.payload : XdrvMailbox.payload; - ShutterInit(); - } - ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - Settings.shutter_set50percent[XdrvMailbox.index -1] : Settings.shutter_set50percent[XdrvMailbox.index -1]); - } -} - -void CmndShutterFrequency(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 20000)) { - Shutter.max_pwm_frequency = XdrvMailbox.payload; - if (shutters_present < 4) { - Settings.shuttercoeff[4][3] = Shutter.max_pwm_frequency; - } - ShutterInit(); - ResponseCmndNumber(XdrvMailbox.payload); - } else { - ResponseCmndNumber(Shutter.max_pwm_frequency); - } -} - -void CmndShutterSetClose(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - Shutter.real_position[XdrvMailbox.index -1] = 0; - ShutterStartInit(XdrvMailbox.index -1, 0, 0); - Settings.shutter_position[XdrvMailbox.index -1] = 0; - ResponseCmndIdxChar(D_CONFIGURATION_RESET); - } -} - -void CmndShutterInvert(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.payload == 0) { - Settings.shutter_options[XdrvMailbox.index -1] &= ~(1); - } else if (XdrvMailbox.payload == 1) { - Settings.shutter_options[XdrvMailbox.index -1] |= (1); - } - ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 1 : 0); - } -} - -void CmndShutterCalibration(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.data_len > 0) { - uint32_t i = 0; - char *str_ptr; - - char data_copy[strlen(XdrvMailbox.data) +1]; - strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); - - for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 5; str = strtok_r(nullptr, " ", &str_ptr), i++) { - int field = atoi(str); - - - if ((field <= 0) || (field > 30000) || ( (i>0) && (field <= messwerte[i-1]) ) ) { - break; - } - messwerte[i] = field; - } - for (i = 0; i < 5; i++) { - Settings.shuttercoeff[i][XdrvMailbox.index -1] = SHT_DIV_ROUND((uint32_t)messwerte[i] * 1000, messwerte[4]); - AddLog_P2(LOG_LEVEL_INFO, PSTR("Settings.shuttercoeff: %d, i: %d, value: %d, messwert %d"), i,XdrvMailbox.index -1,Settings.shuttercoeff[i][XdrvMailbox.index -1], messwerte[i]); - } - ShutterInit(); - ResponseCmndIdxChar(XdrvMailbox.data); - } else { - char setting_chr[30] = "0"; - snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), Settings.shuttercoeff[0][XdrvMailbox.index -1], Settings.shuttercoeff[1][XdrvMailbox.index -1], Settings.shuttercoeff[2][XdrvMailbox.index -1], Settings.shuttercoeff[3][XdrvMailbox.index -1], Settings.shuttercoeff[4][XdrvMailbox.index -1]); - ResponseCmndIdxChar(setting_chr); - } - } -} - -void CmndShutterLock(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.payload == 0) { - Settings.shutter_options[XdrvMailbox.index -1] &= ~(2); - } else if (XdrvMailbox.payload == 1) { - Settings.shutter_options[XdrvMailbox.index -1] |= (2); - } - ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 2) ? 1 : 0); - } -} - -void CmndShutterEnableEndStopTime(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.payload == 0) { - Settings.shutter_options[XdrvMailbox.index -1] &= ~(4); - } else if (XdrvMailbox.payload == 1) { - Settings.shutter_options[XdrvMailbox.index -1] |= (4); - } - ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 4) ? 1 : 0); - } -} - -void CmndShutterInvertWebButtons(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if (XdrvMailbox.payload == 0) { - Settings.shutter_options[XdrvMailbox.index -1] &= ~(8); - } else if (XdrvMailbox.payload == 1) { - Settings.shutter_options[XdrvMailbox.index -1] |= (8); - } - ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 8) ? 1 : 0); - } -} - - - - - -bool Xdrv27(uint8_t function) -{ - bool result = false; - - if (Settings.flag3.shutter_mode) { - switch (function) { - case FUNC_PRE_INIT: - ShutterInit(); - break; - case FUNC_EVERY_50_MSECOND: - ShutterUpdatePosition(); - break; - case FUNC_EVERY_SECOND: - - ShutterReportPosition(false); - break; - - case FUNC_COMMAND: - result = DecodeCommand(kShutterCommands, ShutterCommand); - break; - case FUNC_JSON_APPEND: - for (uint8_t i = 0; i < shutters_present; i++) { - uint8_t position = (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i] : Settings.shutter_position[i]; - uint8_t target = (Settings.shutter_options[i] & 1) ? 100 - ShutterRealToPercentPosition(Shutter.target_position[i], i) : ShutterRealToPercentPosition(Shutter.target_position[i], i); - - ResponseAppend_P(","); - ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter.direction[i],target); -#ifdef USE_DOMOTICZ - if ((0 == tele_period) && (0 == i)) { - DomoticzSensor(DZ_SHUTTER, position); - } -#endif - } - break; - case FUNC_SET_POWER: - char stemp1[10]; - - Shutter.switched_relay = XdrvMailbox.index ^ Shutter.old_power; - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Switched relay: %d by %s"), Shutter.switched_relay,GetTextIndexed(stemp1, sizeof(stemp1), last_source, kCommandSource)); - ShutterRelayChanged(); - Shutter.old_power = XdrvMailbox.index; - break; - case FUNC_SET_DEVICE_POWER: - if (Shutter.skip_relay_change ) { - uint8_t i; - for (i = 0; i < devices_present; i++) { - if (Shutter.switched_relay &1) { - break; - } - Shutter.switched_relay >>= 1; - } - - result = true; - Shutter.skip_relay_change = 0; - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"),i); - ExecuteCommandPower(i+1, 0, SRC_SHUTTER); - } - break; - case FUNC_BUTTON_PRESSED: - if (Settings.shutter_button[XdrvMailbox.index] & (1<<31)) { - ShutterButtonHandler(); - result = true; - } - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_28_pcf8574.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_28_pcf8574.ino" -#ifdef USE_I2C -#ifdef USE_PCF8574 - - - - - - - -#define XDRV_28 28 -#define XI2C_02 2 - -#define PCF8574_ADDR1 0x20 -#define PCF8574_ADDR2 0x38 - -struct PCF8574 { - int error; - uint8_t pin[64]; - uint8_t address[MAX_PCF8574]; - uint8_t pin_mask[MAX_PCF8574] = { 0 }; - uint8_t max_connected_ports = 0; - uint8_t max_devices = 0; - char stype[9]; - bool type = false; -} Pcf8574; - -void Pcf8574SwitchRelay(void) -{ - for (uint32_t i = 0; i < devices_present; i++) { - uint8_t relay_state = bitRead(XdrvMailbox.index, i); - - - - if (Pcf8574.max_devices > 0 && Pcf8574.pin[i] < 99) { - uint8_t board = Pcf8574.pin[i]>>3; - uint8_t oldpinmask = Pcf8574.pin_mask[board]; - uint8_t _val = bitRead(rel_inverted, i) ? !relay_state : relay_state; - - - - if (_val) { - Pcf8574.pin_mask[board] |= _val << (Pcf8574.pin[i]&0x7); - } else { - Pcf8574.pin_mask[board] &= ~(1 << (Pcf8574.pin[i]&0x7)); - } - if (oldpinmask != Pcf8574.pin_mask[board]) { - Wire.beginTransmission(Pcf8574.address[board]); - Wire.write(Pcf8574.pin_mask[board]); - Pcf8574.error = Wire.endTransmission(); - } - - } - } -} - -void Pcf8574Init(void) -{ - uint8_t pcf8574_address = PCF8574_ADDR1; - while ((Pcf8574.max_devices < MAX_PCF8574) && (pcf8574_address < PCF8574_ADDR2 +8)) { - -#ifdef USE_MCP230xx_ADDR - if (USE_MCP230xx_ADDR == pcf8574_address) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("PCF: Address 0x%02x reserved for MCP320xx skipped"), pcf8574_address); - pcf8574_address++; - if ((PCF8574_ADDR1 +7) == pcf8574_address) { - pcf8574_address = PCF8574_ADDR2 +1; - } - } -#endif - - - - if (I2cSetDevice(pcf8574_address)) { - Pcf8574.type = true; - - Pcf8574.address[Pcf8574.max_devices] = pcf8574_address; - Pcf8574.max_devices++; - - strcpy(Pcf8574.stype, "PCF8574"); - if (pcf8574_address >= PCF8574_ADDR2) { - strcpy(Pcf8574.stype, "PCF8574A"); - } - I2cSetActiveFound(pcf8574_address, Pcf8574.stype); - } - - pcf8574_address++; - if ((PCF8574_ADDR1 +7) == pcf8574_address) { - pcf8574_address = PCF8574_ADDR2 +1; - } - } - if (Pcf8574.type) { - for (uint32_t i = 0; i < sizeof(Pcf8574.pin); i++) { - Pcf8574.pin[i] = 99; - } - devices_present = devices_present - Pcf8574.max_connected_ports; - Pcf8574.max_connected_ports = 0; - for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PCF: Device %d config 0x%02x"), idx +1, Settings.pcf8574_config[idx]); - - for (uint32_t i = 0; i < 8; i++) { - uint8_t _result = Settings.pcf8574_config[idx] >> i &1; - - if (_result > 0) { - Pcf8574.pin[devices_present] = i + 8 * idx; - bitWrite(rel_inverted, devices_present, Settings.flag3.pcf8574_ports_inverted); - devices_present++; - Pcf8574.max_connected_ports++; - } - } - } - AddLog_P2(LOG_LEVEL_INFO, PSTR("PCF: Total devices %d, PCF8574 output ports %d"), Pcf8574.max_devices, Pcf8574.max_connected_ports); - } -} - - - - - -#ifdef USE_WEBSERVER - -#define WEB_HANDLE_PCF8574 "pcf" - -const char HTTP_BTN_MENU_PCF8574[] PROGMEM = - "

"; - -const char HTTP_FORM_I2C_PCF8574_1[] PROGMEM = - "
 " D_PCF8574_PARAMETERS " " - "
" - "


"; - -const char HTTP_FORM_I2C_PCF8574_2[] PROGMEM = - "" D_DEVICE " %d " D_PORT " %d"; - -void HandlePcf8574(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_PCF8574)); - - if (Webserver->hasArg("save")) { - Pcf8574SaveSettings(); - WebRestart(1); - return; - } - - WSContentStart_P(D_CONFIGURE_PCF8574); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings.flag3.pcf8574_ports_inverted) ? " checked" : ""); - WSContentSend_P(HTTP_TABLE100); - for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { - for (uint32_t idx2 = 0; idx2 < 8; idx2++) { - uint8_t helper = 1 << idx2; - WSContentSend_P(HTTP_FORM_I2C_PCF8574_2, - idx +1, idx2, - idx2 + 8*idx, - idx2 + 8*idx, - ((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? " selected " : " ", - ((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? " selected " : " " - ); - } - } - WSContentSend_P(PSTR("")); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void Pcf8574SaveSettings(void) -{ - char stemp[7]; - char tmp[100]; - - - - Settings.flag3.pcf8574_ports_inverted = Webserver->hasArg("b1"); - for (byte idx = 0; idx < Pcf8574.max_devices; idx++) { - byte count=0; - byte n = Settings.pcf8574_config[idx]; - while(n!=0) { - n = n&(n-1); - count++; - } - if (count <= devices_present) { - devices_present = devices_present - count; - } - for (byte i = 0; i < 8; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("i2cs%d"), i+8*idx); - WebGetArg(stemp, tmp, sizeof(tmp)); - byte _value = (!strlen(tmp)) ? 0 : atoi(tmp); - if (_value) { - Settings.pcf8574_config[idx] = Settings.pcf8574_config[idx] | 1 << i; - devices_present++; - Pcf8574.max_connected_ports++; - } else { - Settings.pcf8574_config[idx] = Settings.pcf8574_config[idx] & ~(1 << i ); - } - } - - - - } -} -#endif - - - - - -bool Xdrv28(uint8_t function) -{ - if (!I2cEnabled(XI2C_02)) { return false; } - - bool result = false; - - if (FUNC_PRE_INIT == function) { - Pcf8574Init(); - } - else if (Pcf8574.type) { - switch (function) { - case FUNC_SET_POWER: - Pcf8574SwitchRelay(); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_PCF8574); - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/" WEB_HANDLE_PCF8574, HandlePcf8574); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_29_deepsleep.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_29_deepsleep.ino" -#ifdef USE_DEEPSLEEP -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_29_deepsleep.ino" -#define XDRV_29 29 - -#define D_PRFX_DEEPSLEEP "DeepSleep" -#define D_CMND_DEEPSLEEP_TIME "Time" - -const uint32_t DEEPSLEEP_MAX = 10 * 366 * 24 * 60 * 60; -const uint32_t DEEPSLEEP_MAX_CYCLE = 60 * 60; -const uint32_t DEEPSLEEP_MIN_TIME = 5; -const uint32_t DEEPSLEEP_START_COUNTDOWN = 4; - -const char kDeepsleepCommands[] PROGMEM = D_PRFX_DEEPSLEEP "|" - D_CMND_DEEPSLEEP_TIME ; - -void (* const DeepsleepCommand[])(void) PROGMEM = { - &CmndDeepsleepTime }; - -uint32_t deepsleep_sleeptime = 0; -uint8_t deepsleep_flag = 0; - -bool DeepSleepEnabled(void) -{ - if ((Settings.deepsleep < 10) || (Settings.deepsleep > DEEPSLEEP_MAX)) { - Settings.deepsleep = 0; - return false; - } - - if (pin[GPIO_DEEPSLEEP] < 99) { - pinMode(pin[GPIO_DEEPSLEEP], INPUT_PULLUP); - return (digitalRead(pin[GPIO_DEEPSLEEP])); - } - - return true; -} - -void DeepSleepReInit(void) -{ - if ((ResetReason() == REASON_DEEP_SLEEP_AWAKE) && DeepSleepEnabled()) { - if ((RtcSettings.ultradeepsleep > DEEPSLEEP_MAX_CYCLE) && (RtcSettings.ultradeepsleep < 1700000000)) { - - RtcSettings.ultradeepsleep = RtcSettings.ultradeepsleep - DEEPSLEEP_MAX_CYCLE; - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DSL: Remain DeepSleep %d"), RtcSettings.ultradeepsleep); - RtcSettingsSave(); - RtcRebootReset(); - ESP.deepSleep(100 * RtcSettings.deepsleep_slip * (DEEPSLEEP_MAX_CYCLE < RtcSettings.ultradeepsleep ? DEEPSLEEP_MAX_CYCLE : RtcSettings.ultradeepsleep), WAKE_RF_DEFAULT); - yield(); - - } - } - - RtcSettings.ultradeepsleep = 0; -} - -void DeepSleepPrepare(void) -{ - - - - - if ((RtcSettings.nextwakeup == 0) || - (RtcSettings.deepsleep_slip < 9000) || - (RtcSettings.deepsleep_slip > 11000) || - (RtcSettings.nextwakeup > (UtcTime() + Settings.deepsleep))) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DSL: Reset wrong settings wakeup: %ld, slip %ld"), RtcSettings.nextwakeup, RtcSettings.deepsleep_slip ); - RtcSettings.nextwakeup = 0; - RtcSettings.deepsleep_slip = 10000; - } - - - - int16_t timeslip = (int16_t)(RtcSettings.nextwakeup + millis() / 1000 - UtcTime()) * 10; - - - - timeslip = (timeslip < -(int32_t)Settings.deepsleep) ? 0 : (timeslip > (int32_t)Settings.deepsleep) ? 0 : 1; - if (timeslip) { - RtcSettings.deepsleep_slip = (Settings.deepsleep + RtcSettings.nextwakeup - UtcTime()) * RtcSettings.deepsleep_slip / tmax((Settings.deepsleep - (millis() / 1000)),5); - - RtcSettings.deepsleep_slip = tmin(tmax(RtcSettings.deepsleep_slip, 9000), 11000); - RtcSettings.nextwakeup += Settings.deepsleep; - } - - - - if (RtcSettings.nextwakeup <= (UtcTime() - DEEPSLEEP_MIN_TIME)) { - - RtcSettings.nextwakeup += (((UtcTime() + DEEPSLEEP_MIN_TIME - RtcSettings.nextwakeup) / Settings.deepsleep) + 1) * Settings.deepsleep; - } - - String dt = GetDT(RtcSettings.nextwakeup + LocalTime() - UtcTime()); - - - deepsleep_sleeptime = tmin((uint32_t)DEEPSLEEP_MAX_CYCLE ,RtcSettings.nextwakeup - UtcTime()); - - - Response_P(PSTR("{\"" D_PRFX_DEEPSLEEP "\":{\"" D_JSON_TIME "\":\"%s\",\"Epoch\":%d}}"), (char*)dt.c_str(), RtcSettings.nextwakeup); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_STATUS)); - - - -} - -void DeepSleepStart(void) -{ - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "Sleeping")); - - WifiShutdown(); - RtcSettings.ultradeepsleep = RtcSettings.nextwakeup - UtcTime(); - RtcSettingsSave(); - - ESP.deepSleep(100 * RtcSettings.deepsleep_slip * deepsleep_sleeptime); - yield(); -} - -void DeepSleepEverySecond(void) -{ - if (!deepsleep_flag) { return; } - - if (DeepSleepEnabled()) { - if (DEEPSLEEP_START_COUNTDOWN == deepsleep_flag) { - SettingsSaveAll(); - DeepSleepPrepare(); - } - deepsleep_flag--; - if (deepsleep_flag <= 0) { - DeepSleepStart(); - } - } else { - deepsleep_flag = 0; - } -} - - - - - -void CmndDeepsleepTime(void) -{ - if ((0 == XdrvMailbox.payload) || - ((XdrvMailbox.payload > 10) && (XdrvMailbox.payload < DEEPSLEEP_MAX))) { - Settings.deepsleep = XdrvMailbox.payload; - RtcSettings.nextwakeup = 0; - deepsleep_flag = (0 == XdrvMailbox.payload) ? 0 : DEEPSLEEP_START_COUNTDOWN; - if (deepsleep_flag) { - if (!Settings.tele_period) { - Settings.tele_period = TELE_PERIOD; - } - } - } - Response_P(S_JSON_COMMAND_NVALUE, XdrvMailbox.command, Settings.deepsleep); -} - - - - - -bool Xdrv29(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_SECOND: - DeepSleepEverySecond(); - break; - case FUNC_AFTER_TELEPERIOD: - if (DeepSleepEnabled() && !deepsleep_flag && (Settings.tele_period == 10 || Settings.tele_period == 300 || UpTime() > Settings.tele_period)) { - deepsleep_flag = DEEPSLEEP_START_COUNTDOWN; - } - break; - case FUNC_COMMAND: - result = DecodeCommand(kDeepsleepCommands, DeepsleepCommand); - break; - case FUNC_PRE_INIT: - DeepSleepReInit(); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_30_exs_dimmer.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_30_exs_dimmer.ino" -#ifdef USE_LIGHT -#ifdef USE_EXS_DIMMER - - - - - - - -#define XDRV_30 30 - -#define EXS_GATE_1_ON 0x20 -#define EXS_GATE_1_OFF 0x21 -#define EXS_DIMM_1_ON 0x22 -#define EXS_DIMM_1_OFF 0x23 -#define EXS_DIMM_1_TBL 0x24 -#define EXS_DIMM_1_VAL 0x25 -#define EXS_GATE_2_ON 0x30 -#define EXS_GATE_2_OFF 0x31 -#define EXS_DIMM_2_ON 0x32 -#define EXS_DIMM_2_OFF 0x33 -#define EXS_DIMM_2_TBL 0x34 -#define EXS_DIMM_2_VAL 0x35 -#define EXS_GATES_ON 0x40 -#define EXS_GATES_OFF 0x41 -#define EXS_DIMMS_ON 0x50 -#define EXS_DIMMS_OFF 0x51 -#define EXS_CH_LOCK 0x60 -#define EXS_GET_VALUES 0xFA -#define EXS_WRITE_EE 0xFC -#define EXS_READ_EE 0xFD -#define EXS_GET_VERSION 0xFE -#define EXS_RESET 0xFF - -#define EXS_BUFFER_SIZE 256 -#define EXS_ACK_TIMEOUT 200 - -#include - -TasmotaSerial *ExsSerial = nullptr; - -typedef struct -{ - uint8_t on = 0; - uint8_t bright_tbl = 0; - uint8_t dimm = 0; - uint8_t impuls_start = 0; - uint32_t impuls_len = 0; -} CHANNEL; - -typedef struct -{ - uint8_t version_major = 0; - uint8_t version_minor = 0; - CHANNEL channel[2]; - uint8_t gate_lock = 0; -} DIMMER; - -struct EXS -{ - uint8_t *buffer = nullptr; - int byte_counter = 0; - int cmd_status = 0; - uint8_t power = 0; - uint8_t dimm[2] = {0, 0}; - DIMMER dimmer; -} Exs; - - - - - -uint8_t crc8(const uint8_t *p, uint8_t len) -{ - const uint8_t table[] = { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, - 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D}; - - const uint8_t table_rev[] = { - 0x00, 0x70, 0xE0, 0x90, 0xC1, 0xB1, 0x21, 0x51, - 0x83, 0xF3, 0x63, 0x13, 0x42, 0x32, 0xA2, 0xD2}; - - uint8_t offset; - uint8_t temp, crc8_temp; - uint8_t crc8 = 0; - - for (int i = 0; i < len; i++) - { - temp = *(p + i); - offset = temp ^ crc8; - offset >>= 4; - crc8_temp = crc8 & 0x0f; - crc8 = crc8_temp ^ table_rev[offset]; - offset = crc8 ^ temp; - offset &= 0x0f; - crc8_temp = crc8 & 0xf0; - crc8 = crc8_temp ^ table[offset]; - } - return crc8 ^ 0x55; -} - -void ExsSerialSend(const uint8_t data[] = nullptr, uint16_t len = 0) -{ - int retries = 3; - char rc; - -#ifdef EXS_DEBUG - snprintf_P(log_data, sizeof(log_data), PSTR("EXS: Tx Packet: \"")); - for (uint32_t i = 0; i < len; i++) - { - snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, data[i]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data); - AddLog(LOG_LEVEL_DEBUG_MORE); -#endif - - while (retries) - { - retries--; - - ExsSerial->write(data, len); - ExsSerial->flush(); - - - uint32_t snd_time = millis(); - while ((TimePassedSince(snd_time) < EXS_ACK_TIMEOUT) && - (!ExsSerial->available())) - ; - - if (!ExsSerial->available()) - { - -#ifdef EXS_DEBUG - AddLog_P(LOG_LEVEL_DEBUG, PSTR("ESX: serial send timeout")); -#endif - continue; - } - - rc = ExsSerial->read(); - if (rc == 0xFF) - break; - } -} - -void ExsSendCmd(uint8_t cmd, uint8_t value) -{ - uint8_t buffer[8]; - uint16_t len; - - buffer[0] = 0x7b; - buffer[3] = cmd; - - switch (cmd) - { - case EXS_GATE_1_ON: - case EXS_GATE_1_OFF: - case EXS_DIMM_1_ON: - case EXS_DIMM_1_OFF: - case EXS_GATE_2_ON: - case EXS_GATE_2_OFF: - case EXS_DIMM_2_ON: - case EXS_DIMM_2_OFF: - case EXS_GATES_ON: - case EXS_GATES_OFF: - case EXS_DIMMS_ON: - case EXS_DIMMS_OFF: - case EXS_GET_VALUES: - case EXS_GET_VERSION: - case EXS_RESET: - buffer[2] = 1; - len = 4; - break; - - case EXS_CH_LOCK: - case EXS_DIMM_1_TBL: - case EXS_DIMM_1_VAL: - case EXS_DIMM_2_TBL: - case EXS_DIMM_2_VAL: - buffer[2] = 2; - buffer[4] = value; - len = 5; - break; - } - buffer[1] = crc8(&buffer[3], buffer[2]); - - ExsSerialSend(buffer, len); -} - -uint8_t ExsSetPower(uint8_t device, uint8_t power) -{ - Exs.dimmer.channel[device].dimm = power; - ExsSendCmd(EXS_DIMM_1_ON + 0x10 * device + power ^ 1, 0); -} - -uint8_t ExsSetBri(uint8_t device, uint8_t bri) -{ - Exs.dimmer.channel[device].bright_tbl = bri; - ExsSendCmd(EXS_DIMM_1_TBL + 0x10 * device, bri); -} - -uint8_t ExsSyncState(uint8_t device) -{ -#ifdef EXS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Channel %d Power Want %d, Is %d"), - device, bitRead(Exs.power, device), Exs.dimmer.channel[device].dimm); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Set Channel %d Brightness Want %d, Is %d"), - device, Exs.dimm[device], Exs.dimmer.channel[device].bright_tbl); -#endif - - if (bitRead(Exs.power, device) && - Exs.dimm[device] != Exs.dimmer.channel[device].bright_tbl) { - ExsSetBri(device, Exs.dimm[device]); - } - - if (!Exs.dimm[device]) { - Exs.dimmer.channel[device].dimm = 0; - } else if (Exs.dimmer.channel[device].dimm != bitRead(Exs.power, device)) { - ExsSetPower(device, bitRead(Exs.power, device)); - } -} - -bool ExsSyncState() -{ -#ifdef EXS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Serial %p, Cmd %d"), ExsSerial, Exs.cmd_status); -#endif - - if (!ExsSerial || Exs.cmd_status != 0) - return false; - - ExsSyncState(0); - ExsSyncState(1); -} - -void ExsDebugState() -{ -#ifdef EXS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: MCU v%d.%d, c0: On:%d,Dim:%d,Tbl:%d(%d%%), c1: On:%d,Dim:%d,Tbl:%d(%d%%), ChLock: %d"), - Exs.dimmer.version_major, Exs.dimmer.version_minor, - Exs.dimmer.channel[0].on, Exs.dimmer.channel[0].dimm, - Exs.dimmer.channel[0].bright_tbl, - changeUIntScale(Exs.dimmer.channel[0].bright_tbl, 0, 255, 0, 100), - Exs.dimmer.channel[1].on, Exs.dimmer.channel[1].dimm, - Exs.dimmer.channel[1].bright_tbl, - changeUIntScale(Exs.dimmer.channel[1].bright_tbl, 0, 255, 0, 100), - Exs.dimmer.gate_lock); -#endif -} - -void ExsPacketProcess(void) -{ - uint8_t len = Exs.buffer[1]; - uint8_t cmd = Exs.buffer[2]; - - switch (cmd) - { - case EXS_GET_VALUES: -# 294 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_30_exs_dimmer.ino" - if (len > 9) - { - Exs.dimmer.version_major = Exs.buffer[3]; - Exs.dimmer.version_minor = Exs.buffer[4]; - - - Exs.dimmer.channel[0].on = Exs.buffer[6]; - Exs.dimmer.channel[0].dimm = Exs.buffer[6]; - Exs.dimmer.channel[0].bright_tbl = Exs.buffer[7]; - - - Exs.dimmer.channel[1].on = Exs.buffer[9]; - Exs.dimmer.channel[1].dimm = Exs.buffer[9]; - Exs.dimmer.channel[1].bright_tbl = Exs.buffer[10]; - - Exs.dimmer.gate_lock = Exs.buffer[11]; - } - else -# 327 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_30_exs_dimmer.ino" - { - Exs.dimmer.version_major = 1; - Exs.dimmer.version_minor = 0; - - - Exs.dimmer.channel[0].on = Exs.buffer[4] - 48; - Exs.dimmer.channel[0].dimm = Exs.buffer[4] - 48; - Exs.dimmer.channel[0].bright_tbl = Exs.buffer[5] - 48; - - - Exs.dimmer.channel[1].on = Exs.buffer[7] - 48; - Exs.dimmer.channel[1].dimm = Exs.buffer[7] - 48; - Exs.dimmer.channel[1].bright_tbl = Exs.buffer[8] - 48; - - Exs.dimmer.gate_lock = Exs.buffer[9] - 48; - } - - ExsDebugState(); - ExsSyncState(); - ExsDebugState(); - break; - default: - break; - } -} - - - -bool ExsModuleSelected(void) -{ - Settings.light_correction = 0; - Settings.flag.mqtt_serial = 0; - Settings.flag3.pwm_multi_channels = 1; - SetSeriallog(LOG_LEVEL_NONE); - - devices_present = +2; - light_type = LT_SERIAL2; - return true; -} - -bool ExsSetChannels(void) -{ -#ifdef EXS_DEBUG - snprintf_P(log_data, sizeof(log_data), PSTR("EXS: SetChannels: \"")); - for (int i = 0; i < XdrvMailbox.data_len; i++) - { - snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, ((uint8_t *)XdrvMailbox.data)[i]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data); - AddLog(LOG_LEVEL_DEBUG_MORE); -#endif - - Exs.dimm[0] = ((uint8_t *)XdrvMailbox.data)[0]; - Exs.dimm[1] = ((uint8_t *)XdrvMailbox.data)[1]; - return ExsSyncState(); -} - -bool ExsSetPower(void) -{ - AddLog_P2(LOG_LEVEL_INFO, PSTR("EXS: Set Power, Device %d, Power 0x%02x"), - active_device, XdrvMailbox.index); - - Exs.power = XdrvMailbox.index; - return ExsSyncState(); -} - -void EsxMcuStart(void) -{ - int retries = 3; - -#ifdef EXS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EXS: Request MCU configuration, PIN %d to Low"), pin[GPIO_EXS_ENABLE]); -#endif - - pinMode(pin[GPIO_EXS_ENABLE], OUTPUT); - digitalWrite(pin[GPIO_EXS_ENABLE], LOW); - - delay(1); - - while (ExsSerial->available()) - { - - ExsSerial->read(); - } -} - -void ExsInit(void) -{ -#ifdef EXS_DEBUG - AddLog_P2(LOG_LEVEL_INFO, PSTR("EXS: Starting Tx %d Rx %d"), pin[GPIO_TXD], pin[GPIO_RXD]); -#endif - - Exs.buffer = (uint8_t *)malloc(EXS_BUFFER_SIZE); - if (Exs.buffer != nullptr) - { - ExsSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2); - if (ExsSerial->begin(9600)) - { - if (ExsSerial->hardwareSerial()) - { - ClaimSerial(); - } - ExsSerial->flush(); - EsxMcuStart(); - ExsSendCmd(EXS_CH_LOCK, 0); - ExsSendCmd(EXS_GET_VALUES, 0); - } - } -} - -void ExsSerialInput(void) -{ - while (ExsSerial->available()) - { - yield(); - uint8_t serial_in_byte = ExsSerial->read(); - - AddLog_P2(LOG_LEVEL_INFO, PSTR("EXS: Serial In Byte 0x%02x"), serial_in_byte); - - if (Exs.cmd_status == 0 && - serial_in_byte == 0x7B) - { - Exs.cmd_status = 1; - Exs.byte_counter = 0; - } - else if (Exs.byte_counter >= EXS_BUFFER_SIZE) - { - Exs.cmd_status = 0; - } - else if (Exs.cmd_status == 1) - { - Exs.buffer[Exs.byte_counter++] = serial_in_byte; - - if (Exs.byte_counter > 2 && Exs.byte_counter == Exs.buffer[1] + 2) - { - uint8_t crc = crc8(&Exs.buffer[2], Exs.buffer[1]); - - - Exs.cmd_status = 0; - -#ifdef EXS_DEBUG - snprintf_P(log_data, sizeof(log_data), PSTR("EXS: RX Packet: \"")); - for (uint32_t i = 0; i < Exs.byte_counter; i++) - { - snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, Exs.buffer[i]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s\", CRC: 0x%02x"), log_data, crc); - AddLog(LOG_LEVEL_DEBUG_MORE); -#endif - - if (Exs.buffer[0] == crc) - { - ExsSerial->write(0xFF); - ExsPacketProcess(); - } - else - { - ExsSerial->write(0x00); - } - - } - } - } -} - - - - - -#ifdef EXS_MCU_CMNDS - -#define D_PRFX_EXS "Exs" -#define D_CMND_EXS_DIMM "Dimm" -#define D_CMND_EXS_DIMM_TBL "DimmTbl" -#define D_CMND_EXS_DIMM_VAL "DimmVal" -#define D_CMND_EXS_DIMMS "Dimms" -#define D_CMND_EXS_CH_LOCK "ChLock" -#define D_CMND_EXS_STATE "State" - -const char kExsCommands[] PROGMEM = D_PRFX_EXS "|" - D_CMND_EXS_DIMM "|" D_CMND_EXS_DIMM_TBL "|" D_CMND_EXS_DIMM_VAL "|" - D_CMND_EXS_DIMMS "|" D_CMND_EXS_CH_LOCK "|" - D_CMND_EXS_STATE; - -void (* const ExsCommand[])(void) PROGMEM = { - &CmndExsDimm, &CmndExsDimmTbl, &CmndExsDimmVal, - &CmndExsDimms, &CmndExsChLock, - &CmndExsState }; - -void CmndExsDimm(void) -{ - if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && - (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1)) { - ExsSendCmd(EXS_DIMM_1_ON + 0x10 * (XdrvMailbox.index - 1) + - XdrvMailbox.payload ^ 1, 0); - } - CmndExsState(); -} - -void CmndExsDimmTbl(void) -{ - if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && - (XdrvMailbox.payload > 0 || XdrvMailbox.payload <= 255)) { - ExsSendCmd(EXS_DIMM_1_TBL + 0x10 * (XdrvMailbox.index - 1), - XdrvMailbox.payload); - } - CmndExsState(); -} - -void CmndExsDimmVal(void) -{ - if ((XdrvMailbox.index == 1 || XdrvMailbox.index == 2) && - (XdrvMailbox.payload > 0 || XdrvMailbox.payload <= 255)) { - ExsSendCmd(EXS_DIMM_1_VAL + 0x10 * (XdrvMailbox.index - 1), - XdrvMailbox.payload); - } - CmndExsState(); -} - -void CmndExsDimms(void) -{ - if (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1) { - ExsSendCmd(EXS_DIMMS_ON + XdrvMailbox.payload ^ 1, 0); - } - CmndExsState(); -} - -void CmndExsChLock(void) -{ - if (XdrvMailbox.payload == 0 || XdrvMailbox.payload == 1) { - ExsSendCmd(EXS_CH_LOCK, XdrvMailbox.payload); - } - CmndExsState(); -} - -void CmndExsState(void) -{ - ExsSendCmd(EXS_GET_VALUES, 0); - - - uint32_t snd_time = millis(); - while ((TimePassedSince(snd_time) < EXS_ACK_TIMEOUT) && - (!ExsSerial->available())) - ; - ExsSerialInput(); - - Response_P(PSTR("{\"" D_CMND_EXS_STATE "\":{")); - ResponseAppend_P(PSTR("\"McuVersion\":\"%d.%d\"," - "\"Channels\":["), - Exs.dimmer.version_major, Exs.dimmer.version_minor); - - for (uint32_t i = 0; i < 2; i++) { - if (i != 0) { - ResponseAppend_P(PSTR(",")); - } - ResponseAppend_P(PSTR("{\"On\":\"%d\"," - "\"BrightProz\":\"%d\"," - "\"BrightTab\":\"%d\"," - "\"Dimm\":\"%d\"}"), - Exs.dimmer.channel[i].on, - changeUIntScale(Exs.dimmer.channel[i].bright_tbl, 0, 255, 0, 100), - Exs.dimmer.channel[i].bright_tbl, - Exs.dimmer.channel[i].dimm); - } - ResponseAppend_P(PSTR("],")); - ResponseAppend_P(PSTR("\"GateLock\":\"%d\""), Exs.dimmer.gate_lock); - ResponseJsonEndEnd(); -} - -#endif - - - - - -bool Xdrv30(uint8_t function) -{ - bool result = false; - - if (EXS_DIMMER == my_module_type) - { - switch (function) - { - case FUNC_LOOP: - if (ExsSerial) - ExsSerialInput(); - break; - case FUNC_MODULE_INIT: - result = ExsModuleSelected(); - break; - case FUNC_INIT: - ExsInit(); - break; - case FUNC_SET_DEVICE_POWER: - result = ExsSetPower(); - break; - case FUNC_SET_CHANNELS: - result = ExsSetChannels(); - break; -#ifdef EXS_MCU_CMNDS - case FUNC_COMMAND: - result = DecodeCommand(kExsCommands, ExsCommand); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_31_tasmota_slave.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_31_tasmota_slave.ino" -#ifdef USE_TASMOTA_SLAVE - - - - -#define XDRV_31 31 - -#define CONST_STK_CRC_EOP 0x20 - -#define CMND_STK_GET_SYNC 0x30 -#define CMND_STK_SET_DEVICE 0x42 -#define CMND_STK_SET_DEVICE_EXT 0x45 -#define CMND_STK_ENTER_PROGMODE 0x50 -#define CMND_STK_LEAVE_PROGMODE 0x51 -#define CMND_STK_LOAD_ADDRESS 0x55 -#define CMND_STK_PROG_PAGE 0x64 - - - - - -#define CMND_START 0xFC -#define CMND_END 0xFD - -#define CMND_FEATURES 0x01 -#define CMND_JSON 0x02 -#define CMND_FUNC_EVERY_SECOND 0x03 -#define CMND_FUNC_EVERY_100_MSECOND 0x04 -#define CMND_SLAVE_SEND 0x05 -#define CMND_PUBLISH_TELE 0x06 -#define CMND_EXECUTE_CMND 0x07 - -#define PARAM_DATA_START 0xFE -#define PARAM_DATA_END 0xFF - -#include - - - - - -class SimpleHexParse { - public: - SimpleHexParse(void); - uint8_t parseLine(char *hexline); - uint8_t ptr_l = 0; - uint8_t ptr_h = 0; - bool PageIsReady = false; - bool firstrun = true; - bool EndOfFile = false; - uint8_t FlashPage[128]; - uint8_t FlashPageIdx = 0; - uint8_t layoverBuffer[16]; - uint8_t layoverIdx = 0; - uint8_t getByte(char *hexline, uint8_t idx); -}; - -SimpleHexParse::SimpleHexParse(void) -{ - -} - -uint8_t SimpleHexParse::parseLine(char *hexline) -{ - if (layoverIdx) { - memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx); - FlashPageIdx = layoverIdx; - layoverIdx = 0; - } - uint8_t len = getByte(hexline, 1); - uint8_t addr_h = getByte(hexline, 2); - uint8_t addr_l = getByte(hexline, 3); - uint8_t rectype = getByte(hexline, 4); - for (uint8_t idx = 0; idx < len; idx++) { - if (FlashPageIdx < 128) { - FlashPage[FlashPageIdx] = getByte(hexline, idx+5); - FlashPageIdx++; - } else { - layoverBuffer[layoverIdx] = getByte(hexline, idx+5); - layoverIdx++; - } - } - if (1 == rectype) { - EndOfFile = true; - while (FlashPageIdx < 128) { - FlashPage[FlashPageIdx] = 0xFF; - FlashPageIdx++; - } - } - if (FlashPageIdx == 128) { - if (firstrun) { - firstrun = false; - } else { - ptr_l += 0x40; - if (ptr_l == 0) { - ptr_l = 0; - ptr_h++; - } - } - firstrun = false; - PageIsReady = true; - } - return 0; -} - -uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx) -{ - char buff[3]; - buff[3] = '\0'; - memcpy(&buff, &hexline[(idx*2)-1], 2); - return strtol(buff, 0, 16); -} - - - - - -struct TSLAVE { - uint32_t spi_hex_size = 0; - uint32_t spi_sector_counter = 0; - uint8_t spi_sector_cursor = 0; - uint8_t inverted = LOW; - bool type = false; - bool flashing = false; - bool SerialEnabled = false; - uint8_t waitstate = 0; - bool unsupported = false; -} TSlave; - -typedef union { - uint32_t data; - struct { - uint32_t func_json_append : 1; - uint32_t func_every_second : 1; - uint32_t func_every_100_msecond : 1; - uint32_t func_slave_send : 1; - uint32_t spare4 : 1; - uint32_t spare5 : 1; - uint32_t spare6 : 1; - uint32_t spare7 : 1; - uint32_t spare8 : 1; - uint32_t spare9 : 1; - uint32_t spare10 : 1; - uint32_t spare11 : 1; - uint32_t spare12 : 1; - uint32_t spare13 : 1; - uint32_t spare14 : 1; - uint32_t spare15 : 1; - uint32_t spare16 : 1; - uint32_t spare17 : 1; - uint32_t spare18 : 1; - uint32_t spare19 : 1; - uint32_t spare20 : 1; - uint32_t spare21 : 1; - uint32_t spare22 : 1; - uint32_t spare23 : 1; - uint32_t spare24 : 1; - uint32_t spare25 : 1; - uint32_t spare26 : 1; - uint32_t spare27 : 1; - uint32_t spare28 : 1; - uint32_t spare29 : 1; - uint32_t spare30 : 1; - uint32_t spare31 : 1; - }; -} TSlaveFeatureCfg; - - - - - - -struct TSLAVE_FEATURES { - uint32_t features_version; - TSlaveFeatureCfg features; -} TSlaveSettings; - -struct TSLAVE_COMMAND { - uint8_t command; - uint8_t parameter; - uint8_t unused2; - uint8_t unused3; -} TSlaveCommand; - -TasmotaSerial *TasmotaSlave_Serial; - -uint32_t TasmotaSlave_FlashStart(void) -{ - return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; -} - -uint8_t TasmotaSlave_UpdateInit(void) -{ - TSlave.spi_hex_size = 0; - TSlave.spi_sector_counter = TasmotaSlave_FlashStart(); - TSlave.spi_sector_cursor = 0; - return 0; -} - -void TasmotaSlave_Reset(void) -{ - if (TSlave.SerialEnabled) { - digitalWrite(pin[GPIO_TASMOTASLAVE_RST], !TSlave.inverted); - delay(1); - digitalWrite(pin[GPIO_TASMOTASLAVE_RST], TSlave.inverted); - delay(1); - digitalWrite(pin[GPIO_TASMOTASLAVE_RST], !TSlave.inverted); - delay(5); - } -} - -uint8_t TasmotaSlave_waitForSerialData(int dataCount, int timeout) -{ - int timer = 0; - while (timer < timeout) { - if (TasmotaSlave_Serial->available() >= dataCount) { - return 1; - } - delay(1); - timer++; - } - return 0; -} - -uint8_t TasmotaSlave_sendBytes(uint8_t* bytes, int count) -{ - TasmotaSlave_Serial->write(bytes, count); - TasmotaSlave_waitForSerialData(2, 250); - uint8_t sync = TasmotaSlave_Serial->read(); - uint8_t ok = TasmotaSlave_Serial->read(); - if ((sync == 0x14) && (ok == 0x10)) { - return 1; - } - return 0; -} - -uint8_t TasmotaSlave_execCmd(uint8_t cmd) -{ - uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP }; - return TasmotaSlave_sendBytes(bytes, 2); -} - -uint8_t TasmotaSlave_execParam(uint8_t cmd, uint8_t* params, int count) -{ - uint8_t bytes[32]; - bytes[0] = cmd; - int i = 0; - while (i < count) { - bytes[i + 1] = params[i]; - i++; - } - bytes[i + 1] = CONST_STK_CRC_EOP; - return TasmotaSlave_sendBytes(bytes, i + 2); -} - -uint8_t TasmotaSlave_exitProgMode(void) -{ - return TasmotaSlave_execCmd(CMND_STK_LEAVE_PROGMODE); -} - -uint8_t TasmotaSlave_SetupFlash(void) -{ - uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00}; - uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00}; - TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_FLASH_SPEED); - if (TasmotaSlave_Serial->hardwareSerial()) { - ClaimSerial(); - } - - TasmotaSlave_Reset(); - - uint8_t timeout = 0; - uint8_t no_error = 0; - while (50 > timeout) { - if (TasmotaSlave_execCmd(CMND_STK_GET_SYNC)) { - timeout = 200; - no_error = 1; - } - timeout++; - delay(1); - } - if (no_error) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Found bootloader")); - } else { - no_error = 0; - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Bootloader could not be found")); - } - if (no_error) { - if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) { - } else { - no_error = 0; - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (1)")); - } - } - if (no_error) { - if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) { - } else { - no_error = 0; - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (2)")); - } - } - if (no_error) { - if (TasmotaSlave_execCmd(CMND_STK_ENTER_PROGMODE)) { - } else { - no_error = 0; - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Failed to put bootloader into programming mode")); - } - } - return no_error; -} - -uint8_t TasmotaSlave_loadAddress(uint8_t adrHi, uint8_t adrLo) -{ - uint8_t params[] = { adrLo, adrHi }; - return TasmotaSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params)); -} - -void TasmotaSlave_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data) -{ - uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46}; - TasmotaSlave_loadAddress(addr_h, addr_l); - TasmotaSlave_Serial->write(Header, 4); - for (int i = 0; i < 128; i++) { - TasmotaSlave_Serial->write(data[i]); - } - TasmotaSlave_Serial->write(CONST_STK_CRC_EOP); - TasmotaSlave_waitForSerialData(2, 250); - TasmotaSlave_Serial->read(); - TasmotaSlave_Serial->read(); -} - -void TasmotaSlave_Flash(void) -{ - bool reading = true; - uint32_t read = 0; - uint32_t processed = 0; - char thishexline[50]; - uint8_t position = 0; - char* flash_buffer; - - SimpleHexParse hexParse = SimpleHexParse(); - - if (!TasmotaSlave_SetupFlash()) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flashing aborted!")); - TSlave.flashing = false; - restart_flag = 2; - return; - } - - flash_buffer = new char[SPI_FLASH_SEC_SIZE]; - uint32_t flash_start = TasmotaSlave_FlashStart() * SPI_FLASH_SEC_SIZE; - while (reading) { - ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE); - read = read + SPI_FLASH_SEC_SIZE; - if (read >= TSlave.spi_hex_size) { - reading = false; - } - for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) { - processed++; - if ((processed <= TSlave.spi_hex_size) && (!hexParse.EndOfFile)) { - if (':' == flash_buffer[ca]) { - position = 0; - } - if (0x0D == flash_buffer[ca]) { - thishexline[position] = 0; - hexParse.parseLine(thishexline); - if (hexParse.PageIsReady) { - TasmotaSlave_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage); - hexParse.PageIsReady = false; - hexParse.FlashPageIdx = 0; - } - } else { - if (0x0A != flash_buffer[ca]) { - thishexline[position] = flash_buffer[ca]; - position++; - } - } - } - } - } - TasmotaSlave_exitProgMode(); - AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flash done!")); - TSlave.flashing = false; - restart_flag = 2; -} - -void TasmotaSlave_SetFlagFlashing(bool value) -{ - TSlave.flashing = value; -} - -bool TasmotaSlave_GetFlagFlashing(void) -{ - return TSlave.flashing; -} - -void TasmotaSlave_WriteBuffer(uint8_t *buf, size_t size) -{ - if (0 == TSlave.spi_sector_cursor) { - ESP.flashEraseSector(TSlave.spi_sector_counter); - } - TSlave.spi_sector_cursor++; - ESP.flashWrite((TSlave.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TSlave.spi_sector_cursor-1)*2048), (uint32_t*)buf, size); - TSlave.spi_hex_size = TSlave.spi_hex_size + size; - if (2 == TSlave.spi_sector_cursor) { - TSlave.spi_sector_cursor = 0; - TSlave.spi_sector_counter++; - } -} - -void TasmotaSlave_Init(void) -{ - if (TSlave.type) { - return; - } - if (10 > TSlave.waitstate) { - TSlave.waitstate++; - return; - } - if (!TSlave.SerialEnabled) { - if ((pin[GPIO_TASMOTASLAVE_RXD] < 99) && (pin[GPIO_TASMOTASLAVE_TXD] < 99) && - ((pin[GPIO_TASMOTASLAVE_RST] < 99) || (pin[GPIO_TASMOTASLAVE_RST_INV] < 99))) { - TasmotaSlave_Serial = new TasmotaSerial(pin[GPIO_TASMOTASLAVE_RXD], pin[GPIO_TASMOTASLAVE_TXD], 1, 0, 200); - if (TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_SERIAL_SPEED)) { - if (TasmotaSlave_Serial->hardwareSerial()) { - ClaimSerial(); - } - TasmotaSlave_Serial->setTimeout(50); - if (pin[GPIO_TASMOTASLAVE_RST_INV] < 99) { - pin[GPIO_TASMOTASLAVE_RST] = pin[GPIO_TASMOTASLAVE_RST_INV]; - pin[GPIO_TASMOTASLAVE_RST_INV] = 99; - TSlave.inverted = HIGH; - } - pinMode(pin[GPIO_TASMOTASLAVE_RST], OUTPUT); - TSlave.SerialEnabled = true; - TasmotaSlave_Reset(); - AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Enabled")); - } - } - } - if (TSlave.SerialEnabled) { - TasmotaSlave_sendCmnd(CMND_FEATURES, 0); - char buffer[32]; - TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)); - uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)); - memcpy(&TSlaveSettings, &buffer, sizeof(TSlaveSettings)); - if (20191129 == TSlaveSettings.features_version) { - TSlave.type = true; - AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u"), TSlaveSettings.features_version); - } else { - if ((!TSlave.unsupported) && (TSlaveSettings.features_version > 0)) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u not supported!"), TSlaveSettings.features_version); - TSlave.unsupported = true; - } - } - } -} - -void TasmotaSlave_Show(void) -{ - if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) { - char buffer[100]; - TasmotaSlave_sendCmnd(CMND_JSON, 0); - TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1); - uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1); - buffer[len] = '\0'; - ResponseAppend_P(PSTR(",\"TasmotaSlave\":%s"), buffer); - } -} - -void TasmotaSlave_sendCmnd(uint8_t cmnd, uint8_t param) -{ - TSlaveCommand.command = cmnd; - TSlaveCommand.parameter = param; - char buffer[sizeof(TSlaveCommand)+2]; - buffer[0] = CMND_START; - memcpy(&buffer[1], &TSlaveCommand, sizeof(TSlaveCommand)); - buffer[sizeof(TSlaveCommand)+1] = CMND_END; - for (uint8_t ca = 0; ca < sizeof(buffer); ca++) { - TasmotaSlave_Serial->write(buffer[ca]); - } -} - -#define D_PRFX_SLAVE "Slave" -#define D_CMND_SLAVE_RESET "Reset" -#define D_CMND_SLAVE_SEND "Send" - -const char kTasmotaSlaveCommands[] PROGMEM = D_PRFX_SLAVE "|" - D_CMND_SLAVE_RESET "|" D_CMND_SLAVE_SEND; - -void (* const TasmotaSlaveCommand[])(void) PROGMEM = { - &CmndTasmotaSlaveReset, &CmndTasmotaSlaveSend }; - -void CmndTasmotaSlaveReset(void) -{ - TasmotaSlave_Reset(); - TSlave.type = false; - TSlave.waitstate = 7; - TSlave.unsupported = false; - ResponseCmndDone(); -} - -void CmndTasmotaSlaveSend(void) -{ - if (0 < XdrvMailbox.data_len) { - TasmotaSlave_sendCmnd(CMND_SLAVE_SEND, XdrvMailbox.data_len); - TasmotaSlave_Serial->write(char(PARAM_DATA_START)); - for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) { - TasmotaSlave_Serial->write(XdrvMailbox.data[idx]); - } - TasmotaSlave_Serial->write(char(PARAM_DATA_END)); - } - ResponseCmndDone(); -} - -void TasmotaSlave_ProcessIn(void) -{ - uint8_t cmnd = TasmotaSlave_Serial->read(); - switch (cmnd) { - case CMND_START: - TasmotaSlave_waitForSerialData(sizeof(TSlaveCommand),50); - uint8_t buffer[sizeof(TSlaveCommand)]; - for (uint8_t idx = 0; idx < sizeof(TSlaveCommand); idx++) { - buffer[idx] = TasmotaSlave_Serial->read(); - } - TasmotaSlave_Serial->read(); - memcpy(&TSlaveCommand, &buffer, sizeof(TSlaveCommand)); - char inbuf[TSlaveCommand.parameter+1]; - TasmotaSlave_waitForSerialData(TSlaveCommand.parameter, 50); - TasmotaSlave_Serial->read(); - for (uint8_t idx = 0; idx < TSlaveCommand.parameter; idx++) { - inbuf[idx] = TasmotaSlave_Serial->read(); - } - TasmotaSlave_Serial->read(); - inbuf[TSlaveCommand.parameter] = '\0'; - - if (CMND_PUBLISH_TELE == TSlaveCommand.command) { - Response_P(PSTR("{\"TasmotaSlave\":")); - ResponseAppend_P("%s", inbuf); - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data); - XdrvRulesProcess(); - } - if (CMND_EXECUTE_CMND == TSlaveCommand.command) { - ExecuteCommand(inbuf, SRC_IGNORE); - } - break; - default: - break; - } -} - - - - - - -bool Xdrv31(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_100_MSECOND: - if (TSlave.type) { - if (TasmotaSlave_Serial->available()) { - TasmotaSlave_ProcessIn(); - } - if (TSlaveSettings.features.func_every_100_msecond) { - TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0); - } - } - break; - case FUNC_EVERY_SECOND: - if ((TSlave.type) && (TSlaveSettings.features.func_every_second)) { - TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_SECOND, 0); - } - TasmotaSlave_Init(); - break; - case FUNC_JSON_APPEND: - if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) { - TasmotaSlave_Show(); - } - break; - case FUNC_COMMAND: - result = DecodeCommand(kTasmotaSlaveCommands, TasmotaSlaveCommand); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_32_hotplug.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_32_hotplug.ino" -#ifdef USE_HOTPLUG - - - - - - - -#define XDRV_32 32 - -const uint32_t HOTPLUG_MAX = 254; - -const char kHotPlugCommands[] PROGMEM = "|" - D_CMND_HOTPLUG; - -void (* const HotPlugCommand[])(void) PROGMEM = { - &CmndHotPlugTime }; - -struct { - - bool enabled = false; - uint8_t timeout = 0; -} Hotplug; - -void HotPlugInit(void) -{ - - if (Settings.hotplug_scan == 0xFF) { Settings.hotplug_scan = 0; } - if (Settings.hotplug_scan != 0) { - Hotplug.enabled = true; - Hotplug.timeout = 1; - } else - Hotplug.enabled = false; -} - -void HotPlugEverySecond(void) -{ - if (Hotplug.enabled) { - if (Hotplug.timeout == 0) { - XsnsCall(FUNC_HOTPLUG_SCAN); - Hotplug.timeout = Settings.hotplug_scan; - } - Hotplug.timeout--; - } -} - - - - - -void CmndHotPlugTime(void) -{ - if (XdrvMailbox.payload <= HOTPLUG_MAX) { - Settings.hotplug_scan = XdrvMailbox.payload; - HotPlugInit(); - } - ResponseCmndNumber(Settings.hotplug_scan); -} - - - - - -bool Xdrv32(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_SECOND: - HotPlugEverySecond(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kHotPlugCommands, HotPlugCommand); - break; - case FUNC_PRE_INIT: - HotPlugInit(); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_33_nrf24l01.ino" -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_33_nrf24l01.ino" -#ifdef USE_SPI -#ifdef USE_NRF24 - - - - - - - -#define XDRV_33 33 - -#define MOSI 13 -#define MISO 12 -#define SCK 14 - -#include -#include - -const char NRF24type[] PROGMEM = "NRF24"; - -const char HTTP_NRF24[] PROGMEM = - "{s}%sL01%c: " "{m}started{e}"; - -struct { - uint8_t chipType = 0; -} NRF24; - - - -RF24 NRF24radio; - -bool NRF24initRadio() -{ - NRF24radio.begin(pin[GPIO_SPI_CS],pin[GPIO_SPI_DC]); - NRF24radio.powerUp(); - - if(NRF24radio.isChipConnected()){ - DEBUG_DRIVER_LOG(PSTR("NRF24 chip connected")); - return true; - } - DEBUG_DRIVER_LOG(PSTR("NRF24 chip NOT !!!! connected")); - return false; -} - -bool NRF24Detect(void) -{ - if ((pin[GPIO_SPI_CS]<99) && (pin[GPIO_SPI_DC]<99)){ - SPI.pins(SCK,MOSI,MISO,-1); - if(NRF24initRadio()){ - NRF24.chipType = 32; - AddLog_P2(LOG_LEVEL_INFO,PSTR("NRF24L01 initialized")); - if(NRF24radio.isPVariant()){ - NRF24.chipType = 43; - AddLog_P2(LOG_LEVEL_INFO,PSTR("NRF24L01+ detected")); - } - return true; - } - } - return false; -} - - - - - -bool Xdrv33(uint8_t function) -{ - bool result = false; - - if (FUNC_INIT == function) { - result = NRF24Detect(); - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_34_wemos_motor_v1.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_34_wemos_motor_v1.ino" -#ifdef USE_I2C -#ifdef USE_WEMOS_MOTOR_V1 -# 45 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_34_wemos_motor_v1.ino" -#define XDRV_34 34 -#define XI2C_44 44 - -#ifndef WEMOS_MOTOR_V1_ADDR -#define WEMOS_MOTOR_V1_ADDR 0x30 -#endif -#ifndef WEMOS_MOTOR_V1_FREQ -#define WEMOS_MOTOR_V1_FREQ 1000 -#endif - -#define MOTOR_A 0 -#define MOTOR_B 1 - -#define SHORT_BRAKE 0 -#define CCW 1 -#define CW 2 -#define STOP 3 -#define STANDBY 4 - -struct WMOTORV1 { - bool detected = false; - uint8_t motor; -} WMotorV1; - -void WMotorV1Detect(void) -{ - if (I2cSetDevice(WEMOS_MOTOR_V1_ADDR)) { - WMotorV1.detected = true; - I2cSetActiveFound(WEMOS_MOTOR_V1_ADDR, "WEMOS_MOTOR_V1"); - WMotorV1Reset(); - } -} - -void WMotorV1Reset(void) -{ - - WMotorV1SetFrequency(WEMOS_MOTOR_V1_FREQ); -} - -void WMotorV1SetFrequency(uint32_t freq) -{ - Wire.beginTransmission(WEMOS_MOTOR_V1_ADDR); - Wire.write(((byte)(freq >> 16)) & (byte)0x0f); - Wire.write((byte)(freq >> 16)); - Wire.write((byte)(freq >> 8)); - Wire.write((byte)freq); - Wire.endTransmission(); - -} - -void WMotorV1SetMotor(uint8_t motor, uint8_t dir, float pwm_val) -{ - Wire.beginTransmission(WEMOS_MOTOR_V1_ADDR); - Wire.write(motor | (byte)0x10); - Wire.write(dir); - - uint16_t _pwm_val = uint16_t(pwm_val * 100); - if (_pwm_val > 10000) { - _pwm_val = 10000; - } - - Wire.write((byte)(_pwm_val >> 8)); - Wire.write((byte)_pwm_val); - Wire.endTransmission(); - -} - -bool WMotorV1Command(void) -{ - uint8_t args_count = 0; - - if (XdrvMailbox.data_len > 0) { - args_count = 1; - } else { - return false; - } - - for (uint32_t idx = 0; idx < XdrvMailbox.data_len; idx++) { - if (' ' == XdrvMailbox.data[idx]) { - XdrvMailbox.data[idx] = ','; - } - if (',' == XdrvMailbox.data[idx]) { - args_count++; - } - } - UpperCase(XdrvMailbox.data, XdrvMailbox.data); - - char *command = strtok(XdrvMailbox.data, ","); - - if (strcmp(command, "RESET") == 0) { - WMotorV1Reset(); - Response_P(PSTR("{\"WEMOS_MOTOR_V1\":{\"RESET\":\"OK\"}}")); - return true; - } - - if (strcmp(command, "SETMOTOR") == 0) { - if (args_count >= 3) { - - int motor = atoi(strtok(NULL, ",")); - int dir = atoi(strtok(NULL, ",")); - int duty = 100; - if (args_count == 4) { - duty = atoi(strtok(NULL, ",")); - } - - WMotorV1SetMotor(motor, dir, duty); - Response_P(PSTR("{\"WEMOS_MOTOR_V1\":{\"SETMOTOR\":\"OK\"}}")); - return true; - } - } - return false; -} - - - - - -bool Xdrv34(uint8_t function) -{ - if (!I2cEnabled(XI2C_44)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - WMotorV1Detect(); - } - else if (WMotorV1.detected) { - switch (function) { - case FUNC_COMMAND_DRIVER: - if (XI2C_44 == XdrvMailbox.index) { - result = WMotorV1Command(); - } - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_35_pwm_dimmer.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_35_pwm_dimmer.ino" -#ifdef USE_PWM_DIMMER -# 33 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_35_pwm_dimmer.ino" -#define XDRV_35 35 - -const char kPWMDimmerCommands[] PROGMEM = "|" - D_CMND_BRI_PRESET; - -void (* const PWMDimmerCommand[])(void) PROGMEM = { - &CmndBriPreset }; - -#ifdef USE_PWM_DIMMER_REMOTE -struct remote_pwm_dimmer { - power_t power; - uint8_t bri_power_on; - uint8_t bri_preset_low; - uint8_t bri_preset_high; - uint8_t fixed_color_index; - uint8_t bri; - bool power_button_increases_bri; -}; -#endif - -uint32_t last_button_press_time; -uint32_t button_hold_time[3]; -uint8_t led_timeout_seconds = 0; -uint8_t restore_powered_off_led_counter = 0; -uint8_t power_button_index = 0; -uint8_t down_button_index = 1; -uint8_t buttons_pressed = 0; -uint8_t tap_count = 0; -bool down_button_tapped = false; -bool power_button_increases_bri = true; -bool invert_power_button_bri_direction = false; -bool restore_brightness_leds = false; -bool button_pressed[3] = { false, false, false }; -bool button_hold_sent[3]; -bool button_hold_processed[3]; -#ifdef USE_PWM_DIMMER_REMOTE -struct remote_pwm_dimmer * remote_pwm_dimmers; -struct remote_pwm_dimmer * active_remote_pwm_dimmer; -uint8_t remote_pwm_dimmer_count; -bool active_device_is_local; -#endif - -void PWMModulePreInit(void) -{ - Settings.seriallog_level = 0; - Settings.flag.mqtt_serial = 0; - Settings.ledstate = 0; - - - if (Settings.last_module != Settings.module) { - Settings.flag.pwm_control = true; - Settings.param[P_HOLD_TIME] = 5; - Settings.bri_power_on = Settings.bri_preset_low = Settings.bri_preset_high = 0; - Settings.last_module = Settings.module; - } - - - if (!Settings.bri_power_on) Settings.bri_power_on = 128; - if (!Settings.bri_preset_low) Settings.bri_preset_low = 10; - if (Settings.bri_preset_high < Settings.bri_preset_low) Settings.bri_preset_high = 255; - - PWMDimmerSetPoweredOffLed(); - - - if (!power && pin[GPIO_REL1] < 99) digitalWrite(pin[GPIO_REL1], bitRead(rel_inverted, 0) ? 1 : 0); - -#ifdef USE_PWM_DIMMER_REMOTE - - - if (Settings.flag4.remote_device_mode) { - Settings.flag4.device_groups_enabled = true; - - device_group_count = 0; - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { - if (pin[GPIO_KEY1 + button_index] < 99) device_group_count++; - } - - remote_pwm_dimmer_count = device_group_count - 1; - if (remote_pwm_dimmer_count) { - if ((remote_pwm_dimmers = (struct remote_pwm_dimmer *) calloc(remote_pwm_dimmer_count, sizeof(struct remote_pwm_dimmer))) == nullptr) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("PWMDimmer: error allocating PWM dimmer array")); - Settings.flag4.remote_device_mode = false; - } - else { - for (uint8_t i = 0; i < remote_pwm_dimmer_count; i++) { - active_remote_pwm_dimmer = &remote_pwm_dimmers[i]; - active_remote_pwm_dimmer->bri_power_on = 128; - active_remote_pwm_dimmer->bri_preset_low = 10; - active_remote_pwm_dimmer->bri_preset_high = 255; - } - } - } - } - active_device_is_local = true; -#endif -} - - -void PWMDimmerSetBrightnessLeds(int32_t operation) -{ - if (leds_present) { - uint32_t step = (!operation ? 256 / (leds_present + 1) : operation < 0 ? 256 : 0); - uint32_t current_bri = (Light.power ? light_state.getBri() : 0); - uint32_t level = step; - SetLedPowerIdx(0, current_bri >= level); - if (leds_present > 1) { - level += step; - SetLedPowerIdx(1, current_bri >= level); - if (leds_present > 2) { - level += step; - SetLedPowerIdx(2, current_bri >= level); - if (leds_present > 3) { - level += step; - SetLedPowerIdx(3, current_bri >= level); - } - } - } - - - if (!operation) led_timeout_seconds = (current_bri && Settings.flag4.led_timeout ? 5 : 0); - } -} - -void PWMDimmerSetPoweredOffLed(void) -{ - - if (pin[GPIO_LEDLNK] < 99) { - bool power_off_led_on = !power && Settings.flag4.powered_off_led; - if (ledlnk_inverted) power_off_led_on ^= 1; - digitalWrite(pin[GPIO_LEDLNK], power_off_led_on); - } -} - -void PWMDimmerSetPower(void) -{ - DigitalWrite(GPIO_REL1, bitRead(rel_inverted, 0) ? !power : power); - PWMDimmerSetBrightnessLeds(0); - PWMDimmerSetPoweredOffLed(); -} - -#ifdef USE_DEVICE_GROUPS -void PWMDimmerHandleDevGroupItem(void) -{ - uint32_t value = XdrvMailbox.payload; -#ifdef USE_PWM_DIMMER_REMOTE - uint8_t device_group_index = *(uint8_t *)XdrvMailbox.topic; - if (device_group_index > remote_pwm_dimmer_count) return; - bool device_is_local = device_groups[device_group_index].local; - struct remote_pwm_dimmer * remote_pwm_dimmer = &remote_pwm_dimmers[device_group_index]; -#else - if (*(uint8_t *)XdrvMailbox.topic) return; -#endif - - switch (XdrvMailbox.command_code) { -#ifdef USE_PWM_DIMMER_REMOTE - case DGR_ITEM_LIGHT_BRI: - if (!device_is_local) remote_pwm_dimmer->bri = value; - break; - case DGR_ITEM_POWER: - if (!device_is_local) { - remote_pwm_dimmer->power = value; - remote_pwm_dimmer->power_button_increases_bri = (remote_pwm_dimmer->bri < 128); - } - break; - case DGR_ITEM_LIGHT_FIXED_COLOR: - if (!device_is_local) remote_pwm_dimmer->fixed_color_index = value; - break; -#endif - case DGR_ITEM_BRI_POWER_ON: -#ifdef USE_PWM_DIMMER_REMOTE - if (!device_is_local) - remote_pwm_dimmer->bri_power_on = value; - else -#endif - Settings.bri_power_on = value; - break; - case DGR_ITEM_BRI_PRESET_LOW: -#ifdef USE_PWM_DIMMER_REMOTE - if (!device_is_local) - remote_pwm_dimmer->bri_preset_low = value; - else -#endif - Settings.bri_preset_low = value; - break; - case DGR_ITEM_BRI_PRESET_HIGH: -#ifdef USE_PWM_DIMMER_REMOTE - if (!device_is_local) - remote_pwm_dimmer->bri_preset_high = value; - else -#endif - Settings.bri_preset_high = value; - break; - case DGR_ITEM_STATUS: -#ifdef USE_PWM_DIMMER_REMOTE - if (device_is_local) -#endif - SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_BRI_POWER_ON, Settings.bri_power_on, - DGR_ITEM_BRI_PRESET_LOW, Settings.bri_preset_low, DGR_ITEM_BRI_PRESET_HIGH, Settings.bri_preset_high); - break; - } -} -#endif - -void PWMDimmerHandleButton(void) -{ -# 268 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_35_pwm_dimmer.ino" - if (XdrvMailbox.payload && !button_pressed[XdrvMailbox.index]) { - - - if (last_button_press_time && !buttons_pressed && millis() - last_button_press_time > 400) { - last_button_press_time = 0; - tap_count = 0; - } - return; - } - - bool state_updated = false; - int8_t bri_offset = 0; - uint8_t power_on_bri = 0; - uint8_t dgr_item = 0; - uint8_t dgr_value; - uint8_t dgr_more_to_come = false; - uint32_t button_index = XdrvMailbox.index; - uint32_t now = millis(); - - -#ifdef USE_PWM_DIMMER_REMOTE - bool power_is_on = (!active_device_is_local ? active_remote_pwm_dimmer->power : power); - bool is_power_button = (button_index == power_button_index); -#else - bool power_is_on = power; - bool is_power_button = !button_index; -#endif - bool is_down_button = (button_index == down_button_index); - - - if (!XdrvMailbox.payload) { - - - - if (!button_pressed[button_index]) { - last_button_press_time = now; - button_pressed[button_index] = true; - button_hold_time[button_index] = now + Settings.param[P_HOLD_TIME] * 100; - button_hold_sent[button_index] = false; - buttons_pressed++; - -#ifdef USE_PWM_DIMMER_REMOTE - - - if (buttons_pressed == 1 && Settings.flag4.remote_device_mode) { - power_button_index = button_index; - down_button_index = (button_index ? 0 : 1); - active_device_is_local = device_groups[power_button_index].local; - if (!active_device_is_local) active_remote_pwm_dimmer = &remote_pwm_dimmers[power_button_index - 1]; - } -#endif - - return; - } - - - if (button_hold_time[button_index] < now) { - - - - if (!button_pressed[power_button_index] && now - button_hold_time[button_index] > 10000) { - button_hold_time[button_index] = now + 90000; - char scmnd[20]; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); - ExecuteCommand(scmnd, SRC_BUTTON); - return; - } - - - - if (!button_hold_sent[button_index]) { - button_hold_sent[button_index] = true; - button_hold_processed[button_index] = (!is_power_button && tap_count ? false : SendKey(KEY_BUTTON, button_index + 1, POWER_HOLD)); - } - if (!button_hold_processed[button_index]) { - - - if (is_power_button) { - - - if (buttons_pressed == 1) { - - - - - if (power_is_on) { -#ifdef USE_PWM_DIMMER_REMOTE - bri_offset = (!active_device_is_local ? (active_remote_pwm_dimmer->power_button_increases_bri ? 1 : -1) : (power_button_increases_bri ? 1 : -1)); -#else - bri_offset = (power_button_increases_bri ? 1 : -1); -#endif - invert_power_button_bri_direction = true; - } - - - - else { -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - power_on_bri = active_remote_pwm_dimmer->bri = active_remote_pwm_dimmer->bri_preset_low; - else -#endif - power_on_bri = Settings.bri_preset_low; - button_hold_time[button_index] = now + 500; - } - } - } - - - else { - - - - - if (power_is_on && !tap_count) { - bri_offset = (is_down_button ? -1 : 1); - } - - else { - uint8_t mqtt_trigger = 0; - - - - if (tap_count) { - - - if (down_button_tapped) { -#ifdef USE_DEVICE_GROUPS - uint8_t uint8_value; -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - uint8_value = active_remote_pwm_dimmer->fixed_color_index; - else -#endif - uint8_value = Light.fixed_color_index; - if (is_down_button) - uint8_value--; - else - uint8_value++; -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - active_remote_pwm_dimmer->fixed_color_index = uint8_value; - else -#endif - Light.fixed_color_index = uint8_value; - dgr_item = DGR_ITEM_LIGHT_FIXED_COLOR; - dgr_value = uint8_value; - dgr_more_to_come = true; -#endif - ; - } - - - else { - mqtt_trigger = (is_down_button ? 3 : 4); - } - } - - - else if (!power_is_on) { - mqtt_trigger = (is_down_button ? 1 : 2); - } - - - if (mqtt_trigger) { - char topic[TOPSZ]; - sprintf_P(mqtt_data, PSTR("Trigger%u"), mqtt_trigger); -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) { - snprintf_P(topic, sizeof(topic), PSTR("cmnd/%s/Event"), device_groups[power_button_index].group_name); - MqttPublish(topic); - } - else -#endif - MqttPublishPrefixTopic_P(CMND, PSTR("Event")); - } - - button_hold_time[button_index] = now + 500; - } - } - } - } - } - - - else { - bool button_was_held = button_hold_sent[button_index]; - - - - if (!(button_hold_sent[button_index] ? button_hold_processed[button_index] : SendKey(KEY_BUTTON, button_index + 1, POWER_TOGGLE))) { - - - if (is_power_button) { - - - if (button_was_held) { - - - - if (invert_power_button_bri_direction) { - invert_power_button_bri_direction = false; -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - active_remote_pwm_dimmer->power_button_increases_bri ^= 1; - else -#endif - power_button_increases_bri ^= 1; -#ifdef USE_PWM_DIMMER_REMOTE - dgr_item = 255; - state_updated = true; -#endif - } - - - else if (tap_count) { - - - - if (!button_was_held) { - -#ifdef USE_PWM_DIMMER_REMOTE - if (active_device_is_local) { -#endif - - - if (down_button_tapped) { - Settings.flag4.led_timeout ^= 1; - if (Light.power) PWMDimmerSetBrightnessLeds(Settings.flag4.led_timeout ? -1 : 0); - } - - - else { - Settings.flag4.powered_off_led ^= 1; - PWMDimmerSetPoweredOffLed(); - } -#ifdef USE_PWM_DIMMER_REMOTE - } -#endif - } - - - - else if (down_button_tapped) { - dgr_item = 255; - } - } - } - - - else { -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - power_on_bri = active_remote_pwm_dimmer->bri_power_on; - else -#endif - power_on_bri = Settings.bri_power_on; - } - } - - - else { - - if (restore_brightness_leds) { - restore_brightness_leds = false; - PWMDimmerSetBrightnessLeds(Settings.flag4.led_timeout ? -1 : 0); - } - - - - if (!button_was_held && button_pressed[power_button_index]) { - down_button_tapped = is_down_button; - tap_count++; - } - - - if (!tap_count) { - - - if (power_is_on) { - - - - if (button_hold_time[button_index] >= now) { - bri_offset = (is_down_button ? -10 : 10); - dgr_item = 255; - } - - - - - else if (!button_hold_processed[button_index]) { - dgr_item = 255; - state_updated = true; - } - } - - - - else { -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - power_on_bri = active_remote_pwm_dimmer->bri = (is_down_button ? active_remote_pwm_dimmer->bri_preset_low : active_remote_pwm_dimmer->bri_preset_high); - else -#endif - power_on_bri = (is_down_button ? Settings.bri_preset_low : Settings.bri_preset_high); - } - } - } - } - - - button_pressed[button_index] = false; - buttons_pressed--; - } - - - if (bri_offset) { - int32_t bri; -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - bri = active_remote_pwm_dimmer->bri; - else -#endif - bri = light_state.getBri(); - int32_t new_bri; - bri_offset *= (Settings.light_correction ? 4 : bri / 16 + 1); - new_bri = bri + bri_offset; - if (bri_offset > 0) { - if (new_bri > 255) new_bri = 255; - } - else { - if (new_bri < 1) new_bri = 1; - } - if (new_bri != bri) { -#ifdef USE_DEVICE_GROUPS - SendDeviceGroupMessage(power_button_index, (dgr_item ? DGR_MSGTYP_UPDATE : DGR_MSGTYP_UPDATE_MORE_TO_COME), DGR_ITEM_LIGHT_BRI, new_bri); -#endif -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - active_remote_pwm_dimmer->bri_power_on = active_remote_pwm_dimmer->bri = new_bri; - else { -#endif - skip_light_fade = true; - light_state.setBri(new_bri); - LightAnimate(); - skip_light_fade = false; - Settings.bri_power_on = new_bri; -#ifdef USE_PWM_DIMMER_REMOTE - } -#endif - } - else { - PWMDimmerSetBrightnessLeds(0); - } - } - - - else if (power_on_bri) { - power_t new_power; -#ifdef USE_DEVICE_GROUPS -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) { - active_remote_pwm_dimmer->power ^= 1; - new_power = active_remote_pwm_dimmer->power; - } - else { -#endif - new_power = power ^ 1; -#ifdef USE_PWM_DIMMER_REMOTE - } -#endif - if (new_power) - SendDeviceGroupMessage(power_button_index, DGR_MSGTYP_UPDATE, DGR_ITEM_LIGHT_BRI, power_on_bri, DGR_ITEM_POWER, new_power); - else - SendDeviceGroupMessage(power_button_index, DGR_MSGTYP_UPDATE, DGR_ITEM_POWER, new_power); -#endif - -#ifdef USE_PWM_DIMMER_REMOTE - if (!active_device_is_local) - active_remote_pwm_dimmer->power_button_increases_bri = (power_on_bri < 128); - else { -#endif - light_state.setBri(power_on_bri); - ExecuteCommandPower(1, POWER_TOGGLE, SRC_RETRY); -#ifdef USE_PWM_DIMMER_REMOTE - } -#endif - } - - - - else if (dgr_item) { -#ifdef USE_DEVICE_GROUPS - if (dgr_item == 255) dgr_item = 0; - SendDeviceGroupMessage(power_button_index, (dgr_more_to_come ? DGR_MSGTYP_UPDATE_MORE_TO_COME : DGR_MSGTYP_UPDATE_DIRECT), dgr_item, dgr_value); -#endif -#ifdef USE_PWM_DIMMER_REMOTE - if (active_device_is_local) { -#endif - light_controller.saveSettings(); - if (state_updated && Settings.flag3.hass_tele_on_power) { - MqttPublishTeleState(); - } -#ifdef USE_PWM_DIMMER_REMOTE - } -#endif - } -} - - - - - -void CmndBriPreset(void) -{ - if (XdrvMailbox.data_len > 0) { - bool valid = true; - uint32_t value; - uint8_t parm[2]; - parm[0] = Settings.bri_preset_low; - parm[1] = Settings.bri_preset_high; - char * ptr = XdrvMailbox.data; - for (uint32_t i = 0; i < 2; i++) { - while (*ptr == ' ') ptr++; - if (*ptr == '+') { - if (parm[i] < 255) parm[i]++; - } - else if (*ptr == '-') { - if (parm[i] > 1) parm[i]--; - } - else { - value = strtoul(ptr, &ptr, 0); - if (value < 1 || value > 255) { - valid = false; - break; - } - parm[i] = value; - if (*ptr != ',') break; - } - ptr++; - } - if (valid && !*ptr) { - if (parm[0] < parm[1]) { - Settings.bri_preset_low = parm[0]; - Settings.bri_preset_high = parm[1]; - } else - { - Settings.bri_preset_low = parm[1]; - Settings.bri_preset_high = parm[0]; - } -#ifdef USE_DEVICE_GROUPS - SendLocalDeviceGroupMessage(DGR_MSGTYP_UPDATE, DGR_ITEM_BRI_PRESET_LOW, Settings.bri_preset_low, DGR_ITEM_BRI_PRESET_HIGH, Settings.bri_preset_high); -#endif - } - } - Response_P(PSTR("{\"" D_CMND_BRI_PRESET "\":{\"Low\":%d,\"High\":%d}}"), Settings.bri_preset_low, Settings.bri_preset_high); -} - - - - - -bool Xdrv35(uint8_t function) -{ - bool result = false; - - if (PWM_DIMMER != my_module_type) return result; - - switch (function) { - case FUNC_EVERY_SECOND: - - if (led_timeout_seconds && !led_timeout_seconds--) { - PWMDimmerSetBrightnessLeds(-1); - } - - - - - - if (global_state.data) - restore_powered_off_led_counter = 5; - else if (restore_powered_off_led_counter) { - PWMDimmerSetPoweredOffLed(); - restore_powered_off_led_counter--; - } - break; - - case FUNC_BUTTON_PRESSED: - PWMDimmerHandleButton(); - result = true; - break; - -#ifdef USE_DEVICE_GROUPS - case FUNC_DEVICE_GROUP_ITEM: - PWMDimmerHandleDevGroupItem(); - break; -#endif - - case FUNC_COMMAND: - result = DecodeCommand(kPWMDimmerCommands, PWMDimmerCommand); - break; - - case FUNC_SET_DEVICE_POWER: - - - if (XdrvMailbox.index) { - PWMDimmerSetPower(); - - - power_button_increases_bri = (light_state.getBri() < 128); - } - - - - else - result = true; - break; - - case FUNC_PRE_INIT: - PWMModulePreInit(); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_36_keeloq.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_36_keeloq.ino" -#ifdef USE_KEELOQ -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_36_keeloq.ino" -#define XDRV_36 36 - -#include "cc1101.h" -#include - -#define SYNC_WORD 199 - -#define Lowpulse 400 -#define Highpulse 800 - -const char kJaroliftCommands[] PROGMEM = "Keeloq|" - "SendRaw|SendButton|Set"; - -void (* const jaroliftCommand[])(void) PROGMEM = { - &CmndSendRaw, &CmdSendButton, &CmdSet}; - -CC1101 cc1101; - -struct JAROLIFT_DEVICE { - int device_key_msb = 0x0; - int device_key_lsb = 0x0; - uint64_t button = 0x0; - int disc = 0x0100; - uint32_t enc = 0x0; - uint64_t pack = 0; - int count = 0; - uint32_t serial = 0x0; - uint8_t port_tx; - uint8_t port_rx; -} jaroliftDevice; - -void CmdSet(void) -{ - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload > 0) { - char *p; - uint32_t i = 0; - uint32_t param[4] = { 0 }; - for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 4; str = strtok_r(nullptr, ", ", &p)) { - param[i] = strtoul(str, nullptr, 0); - i++; - } - for (uint32_t i = 0; i < 3; i++) { - if (param[i] < 1) { param[i] = 1; } - } - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("params: %08x %08x %08x %08x"), param[0], param[1], param[2], param[3]); - Settings.keeloq_master_msb = param[0]; - Settings.keeloq_master_lsb = param[1]; - Settings.keeloq_serial = param[2]; - Settings.keeloq_count = param[3]; - - jaroliftDevice.serial = param[2]; - jaroliftDevice.count = param[3]; - - GenerateDeviceCryptKey(); - ResponseCmndDone(); - } else { - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("no payload")); - } - } else { - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("no param")); - } -} - -void GenerateDeviceCryptKey() -{ - Keeloq k(Settings.keeloq_master_msb, Settings.keeloq_master_lsb); - jaroliftDevice.device_key_msb = k.decrypt(jaroliftDevice.serial | 0x60000000L); - jaroliftDevice.device_key_lsb = k.decrypt(jaroliftDevice.serial | 0x20000000L); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("generated device keys: %08x %08x"), jaroliftDevice.device_key_msb, jaroliftDevice.device_key_lsb); -} - -void CmdSendButton(void) -{ - noInterrupts(); - entertx(); - - if (XdrvMailbox.data_len > 0) - { - if (XdrvMailbox.payload > 0) - { - jaroliftDevice.button = strtoul(XdrvMailbox.data, nullptr, 0); - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("msb: %08x"), jaroliftDevice.device_key_msb); - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("lsb: %08x"), jaroliftDevice.device_key_lsb); - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("serial: %08x"), jaroliftDevice.serial); - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("disc: %08x"), jaroliftDevice.disc); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("KLQ: count: %08x"), jaroliftDevice.count); - - CreateKeeloqPacket(); - jaroliftDevice.count++; - Settings.keeloq_count = jaroliftDevice.count; - - for(int repeat = 0; repeat <= 1; repeat++) - { - uint64_t bitsToSend = jaroliftDevice.pack; - digitalWrite(jaroliftDevice.port_tx, LOW); - delayMicroseconds(1150); - SendSyncPreamble(13); - delayMicroseconds(3500); - for(int i=72; i>0; i--) - { - SendBit(bitsToSend & 0x0000000000000001); - bitsToSend >>= 1; - } - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("finished sending bits at %d"), micros()); - - delay(16); - } - } - } - - interrupts(); - enterrx(); - - ResponseCmndDone(); -} - -void SendBit(byte bitToSend) -{ - if (bitToSend==1) - { - digitalWrite(jaroliftDevice.port_tx, LOW); - delayMicroseconds(Lowpulse); - digitalWrite(jaroliftDevice.port_tx, HIGH); - delayMicroseconds(Highpulse); - } - else - { - digitalWrite(jaroliftDevice.port_tx, LOW); - delayMicroseconds(Highpulse); - digitalWrite(jaroliftDevice.port_tx, HIGH); - delayMicroseconds(Lowpulse); - } -} - -void CmndSendRaw(void) -{ - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("cmd send called at %d"), micros()); - noInterrupts(); - entertx(); - for(int repeat = 0; repeat <= 1; repeat++) - { - if (XdrvMailbox.data_len > 0) - { - digitalWrite(jaroliftDevice.port_tx, LOW); - delayMicroseconds(1150); - SendSyncPreamble(13); - delayMicroseconds(3500); - - for(int i=XdrvMailbox.data_len-1; i>=0; i--) - { - SendBit(XdrvMailbox.data[i] == '1'); - } - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("finished sending bits at %d"), micros()); - - delay(16); - } - interrupts(); - } - enterrx(); - ResponseCmndDone(); -} - -void enterrx() { - unsigned char marcState = 0; - cc1101.setRxState(); - delay(2); - unsigned long rx_time = micros(); - while (((marcState = cc1101.readStatusReg(CC1101_MARCSTATE)) & 0x1F) != 0x0D ) - { - if (micros() - rx_time > 50000) break; - } -} - -void entertx() { - unsigned char marcState = 0; - cc1101.setTxState(); - delay(2); - unsigned long rx_time = micros(); - while (((marcState = cc1101.readStatusReg(CC1101_MARCSTATE)) & 0x1F) != 0x13 && 0x14 && 0x15) - { - if (micros() - rx_time > 50000) break; - } -} - -void SendSyncPreamble(int l) -{ - for (int i = 0; i < l; ++i) - { - digitalWrite(jaroliftDevice.port_tx, LOW); - delayMicroseconds(400); - digitalWrite(jaroliftDevice.port_tx, HIGH); - delayMicroseconds(380); - } -} - -void CreateKeeloqPacket() -{ - Keeloq k(jaroliftDevice.device_key_msb, jaroliftDevice.device_key_lsb); - unsigned int result = (jaroliftDevice.disc << 16) | jaroliftDevice.count; - jaroliftDevice.pack = (uint64_t)0; - jaroliftDevice.pack |= jaroliftDevice.serial & 0xfffffffL; - jaroliftDevice.pack |= (jaroliftDevice.button & 0xfL) << 28; - jaroliftDevice.pack <<= 32; - - jaroliftDevice.enc = k.encrypt(result); - jaroliftDevice.pack |= jaroliftDevice.enc; - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("pack high: %08x"), jaroliftDevice.pack>>32); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("pack low: %08x"), jaroliftDevice.pack); -} - -void KeeloqInit() -{ - jaroliftDevice.port_tx = pin[GPIO_CC1101_GDO2]; - jaroliftDevice.port_rx = pin[GPIO_CC1101_GDO0]; - - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("cc1101.init()")); - delay(100); - cc1101.init(); - AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("CC1101 done.")); - cc1101.setSyncWord(SYNC_WORD, false); - cc1101.setCarrierFreq(CFREQ_433); - cc1101.disableAddressCheck(); - - pinMode(jaroliftDevice.port_tx, OUTPUT); - pinMode(jaroliftDevice.port_rx, INPUT_PULLUP); - - jaroliftDevice.serial = Settings.keeloq_serial; - jaroliftDevice.count = Settings.keeloq_count; - GenerateDeviceCryptKey(); -} - - - - -bool Xdrv36(uint8_t function) -{ - if ((99 == pin[GPIO_CC1101_GDO0]) || (99 == pin[GPIO_CC1101_GDO2])) { return false; } - - bool result = false; - - switch (function) { - case FUNC_COMMAND: - AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("calling command")); - result = DecodeCommand(kJaroliftCommands, jaroliftCommand); - break; - case FUNC_INIT: - KeeloqInit(); - DEBUG_DRIVER_LOG(LOG_LEVEL_DEBUG_MORE, PSTR("init done.")); - break; - } - - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_37_sonoff_d1.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_37_sonoff_d1.ino" -#ifdef USE_SONOFF_D1 -# 34 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_37_sonoff_d1.ino" -#define XDRV_37 37 - -struct SONOFFD1 { - uint8_t receive_len = 0; - uint8_t power = 255; - uint8_t dimmer = 255; -} SnfD1; - - - -void SonoffD1Received(void) -{ - if (serial_in_byte_counter < 8) { return; } - - uint8_t action = serial_in_buffer[6] & 1; - if (action != SnfD1.power) { - SnfD1.power = action; - - - - ExecuteCommandPower(1, action, SRC_SWITCH); - } - - uint8_t dimmer = serial_in_buffer[7]; - if (dimmer != SnfD1.dimmer) { - SnfD1.dimmer = dimmer; - - - - char scmnd[20]; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), SnfD1.dimmer); - ExecuteCommand(scmnd, SRC_SWITCH); - } -# 78 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_37_sonoff_d1.ino" -} - -bool SonoffD1SerialInput(void) -{ - if (0xAA == serial_in_byte) { - serial_in_byte_counter = 0; - SnfD1.receive_len = 7; - } - if (SnfD1.receive_len) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (6 == serial_in_byte_counter) { - SnfD1.receive_len += serial_in_byte; - } - if (serial_in_byte_counter == SnfD1.receive_len) { -# 101 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_37_sonoff_d1.ino" - AddLogSerial(LOG_LEVEL_DEBUG); - uint8_t crc = 0; - for (uint32_t i = 2; i < SnfD1.receive_len -1; i++) { - crc += serial_in_buffer[i]; - } - if (crc == serial_in_buffer[SnfD1.receive_len -1]) { - SonoffD1Received(); - SnfD1.receive_len = 0; - return true; - } - } - serial_in_byte = 0; - } - return false; -} - - - -void SonoffD1Send() -{ - - uint8_t buffer[17] = { 0xAA,0x55,0x01,0x04,0x00,0x0A,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00 }; - - buffer[6] = SnfD1.power; - buffer[7] = SnfD1.dimmer; - - for (uint32_t i = 0; i < sizeof(buffer); i++) { - if ((i > 1) && (i < sizeof(buffer) -1)) { buffer[16] += buffer[i]; } - Serial.write(buffer[i]); - } -} - -bool SonoffD1SendPower(void) -{ - uint8_t action = XdrvMailbox.index &1; - if (action != SnfD1.power) { - SnfD1.power = action; - - - - SonoffD1Send(); - } - return true; -} - -bool SonoffD1SendDimmer(void) -{ - uint8_t dimmer = LightGetDimmer(1); - dimmer = (dimmer < Settings.dimmer_hw_min) ? Settings.dimmer_hw_min : dimmer; - dimmer = (dimmer > Settings.dimmer_hw_max) ? Settings.dimmer_hw_max : dimmer; - if (dimmer != SnfD1.dimmer) { - SnfD1.dimmer = dimmer; - - - - SonoffD1Send(); - } - return true; -} - -bool SonoffD1ModuleSelected(void) -{ - SetSerial(9600, TS_SERIAL_8N1); - - devices_present++; - light_type = LT_SERIAL1; - - return true; -} - - - - - -bool Xdrv37(uint8_t function) -{ - bool result = false; - - if (SONOFF_D1 == my_module_type) { - switch (function) { - case FUNC_SERIAL: - result = SonoffD1SerialInput(); - break; - case FUNC_SET_DEVICE_POWER: - result = SonoffD1SendPower(); - break; - case FUNC_SET_CHANNELS: - result = SonoffD1SendDimmer(); - break; - case FUNC_MODULE_INIT: - result = SonoffD1ModuleSelected(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_38_ping.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_38_ping.ino" -#ifdef USE_PING - -#define XDRV_38 38 - -#include "lwip/icmp.h" -#include "lwip/inet_chksum.h" -#include "lwip/raw.h" -#include "lwip/timeouts.h" - -const char kPingCommands[] PROGMEM = "|" - D_CMND_PING - ; - -void (* const PingCommand[])(void) PROGMEM = { - &CmndPing, - }; - -extern "C" { - - extern uint32 system_relative_time(uint32 time); - extern void ets_bzero(void *s, size_t n); - - const uint16_t Ping_ID = 0xAFAF; - const size_t Ping_data_size = 32; - const uint32_t Ping_timeout_ms = 1000; - const uint32_t Ping_coarse = 1000; - - typedef struct Ping_t { - uint32 ip; - Ping_t *next; - uint16_t seq_num; - uint16_t seqno; - uint8_t success_count; - uint8_t timeout_count; - uint8_t to_send_count; - uint32_t ping_time_sent; - uint32_t min_time; - uint32_t max_time; - uint32_t sum_time; - bool done; - bool fast; - } Ping_t; - - - Ping_t *ping_head = nullptr; - struct raw_pcb *t_ping_pcb = nullptr; - - - - - - - - Ping_t ICACHE_FLASH_ATTR * t_ping_find(uint32_t ip) { - Ping_t *ping = ping_head; - while (ping != nullptr) { - if (ping->ip == ip) { - return ping; - } - ping = ping->next; - } - return nullptr; - } -# 91 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_38_ping.ino" - void ICACHE_FLASH_ATTR t_ping_timeout(void* arg) { - Ping_t *ping = (Ping_t*) arg; - ping->timeout_count++; - } - - - - - - - void ICACHE_FLASH_ATTR t_ping_prepare_echo(struct icmp_echo_hdr *iecho, uint16_t len, Ping_t *ping) { - size_t data_len = len - sizeof(struct icmp_echo_hdr); - - ICMPH_TYPE_SET(iecho, ICMP_ECHO); - ICMPH_CODE_SET(iecho, 0); - iecho->chksum = 0; - iecho->id = Ping_ID; - ping->seq_num++; - if (ping->seq_num == 0x7fff) { ping->seq_num = 0; } - - iecho->seqno = htons(ping->seq_num); - - - for (uint32_t i = 0; i < data_len; i++) { - ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; - } - - iecho->chksum = inet_chksum(iecho, len); - } - - - - void ICACHE_FLASH_ATTR t_ping_send(struct raw_pcb *raw, Ping_t *ping) { - struct pbuf *p; - uint16_t ping_size = sizeof(struct icmp_echo_hdr) + Ping_data_size; - - ping->ping_time_sent = system_get_time(); - p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM); - if (!p) { return; } - if ((p->len == p->tot_len) && (p->next == nullptr)) { - ip_addr_t ping_target; - struct icmp_echo_hdr *iecho; - - ping_target.addr = ping->ip; - iecho = (struct icmp_echo_hdr *) p->payload; - - t_ping_prepare_echo(iecho, ping_size, ping); - raw_sendto(raw, p, &ping_target); - } - pbuf_free(p); - } - - - - - - static void ICACHE_FLASH_ATTR t_ping_coarse_tmr(void *arg) { - Ping_t *ping = (Ping_t*) arg; - if (ping->to_send_count > 0) { - ping->to_send_count--; - - t_ping_send(t_ping_pcb, ping); - - sys_timeout(Ping_timeout_ms, t_ping_timeout, ping); - sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping); - } else { - sys_untimeout(t_ping_coarse_tmr, ping); - ping->done = true; - } - } - - - - - - - - static uint8_t ICACHE_FLASH_ATTR t_ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { - Ping_t *ping = t_ping_find(addr->addr); - - if (nullptr == ping) { - return 0; - } - - if (pbuf_header( p, -PBUF_IP_HLEN)==0) { - struct icmp_echo_hdr *iecho; - iecho = (struct icmp_echo_hdr *)p->payload; - - if ((iecho->id == Ping_ID) && (iecho->seqno == htons(ping->seq_num)) && iecho->type == ICMP_ER) { - - if (iecho->seqno != ping->seqno){ - - sys_untimeout(t_ping_timeout, ping); - uint32_t delay = system_relative_time(ping->ping_time_sent); - delay /= 1000; - - ping->sum_time += delay; - if (delay < ping->min_time) { ping->min_time = delay; } - if (delay > ping->max_time) { ping->max_time = delay; } - - ping->success_count++; - ping->seqno = iecho->seqno; - if (ping->fast) { - sys_untimeout(t_ping_coarse_tmr, ping); - ping->done = true; - ping->to_send_count = 0; - } - } - - pbuf_free(p); - return 1; - } - } - - return 0; - } - - - - - - void t_ping_register_pcb(void) { - if (nullptr == t_ping_pcb) { - t_ping_pcb = raw_new(IP_PROTO_ICMP); - - raw_recv(t_ping_pcb, t_ping_recv, nullptr); - raw_bind(t_ping_pcb, IP_ADDR_ANY); - } - } - - - void t_ping_deregister_pcb(void) { - if (nullptr == ping_head) { - raw_remove(t_ping_pcb); - t_ping_pcb = nullptr; - } - } - - - - - bool t_ping_start(uint32_t ip, uint32_t count) { - - if (t_ping_find(ip)) { - return false; - } - - Ping_t *ping = new Ping_t(); - if (0 == count) { - count = 4; - ping->fast = true; - } - ping->min_time = UINT32_MAX; - ping->ip = ip; - ping->to_send_count = count - 1; - - - ping->next = ping_head; - ping_head = ping; - - t_ping_register_pcb(); - t_ping_send(t_ping_pcb, ping); - - - sys_timeout(Ping_timeout_ms, t_ping_timeout, ping); - sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping); - } - -} - - -void PingResponsePoll(void) { - Ping_t *ping = ping_head; - Ping_t **prev_link = &ping_head; - - while (ping != nullptr) { - if (ping->done) { - uint32_t success = ping->success_count; - uint32_t ip = ping->ip; - - Response_P(PSTR("{\"" D_JSON_PING "\":{\"%d.%d.%d.%d\":{" - "\"Reachable\":%s" - ",\"Success\":%d" - ",\"Timeout\":%d" - ",\"MinTime\":%d" - ",\"MaxTime\":%d" - ",\"AvgTime\":%d" - "}}}"), - ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24, - success ? "true" : "false", - success, ping->timeout_count, - success ? ping->min_time : 0, ping->max_time, - success ? ping->sum_time / success : 0 - ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_PING)); - XdrvRulesProcess(); - - - *prev_link = ping->next; - - Ping_t *ping_to_delete = ping; - ping = ping->next; - delete ping_to_delete; - } else { - prev_link = &ping->next; - ping = ping->next; - } - } -} - - - - - -void CmndPing(void) { - uint32_t count = XdrvMailbox.index; - IPAddress ip; - - RemoveSpace(XdrvMailbox.data); - if (count > 10) { count = 8; } - - if (WiFi.hostByName(XdrvMailbox.data, ip)) { - bool ok = t_ping_start(ip, count); - if (ok) { - ResponseCmndDone(); - } else { - ResponseCmndChar_P(PSTR("Ping already ongoing for this IP")); - } - } else { - ResponseCmndChar_P(PSTR("Unable to resolve IP address")); - } -} - - - - - - -bool Xdrv38(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - PingResponsePoll(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kPingCommands, PingCommand); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_39_thermostat.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_39_thermostat.ino" -#ifdef USE_THERMOSTAT - -#define XDRV_39 39 - - -#define DEBUG_THERMOSTAT - -#ifdef DEBUG_THERMOSTAT -#define DOMOTICZ_IDX1 791 -#define DOMOTICZ_IDX2 792 -#define DOMOTICZ_IDX3 793 -#endif - - -#define D_CMND_THERMOSTATMODESET "ThermostatModeSet" -#define D_CMND_TEMPFROSTPROTECTSET "TempFrostProtectSet" -#define D_CMND_CONTROLLERMODESET "ControllerModeSet" -#define D_CMND_INPUTSWITCHSET "InputSwitchSet" -#define D_CMND_OUTPUTRELAYSET "OutputRelaySet" -#define D_CMND_TIMEALLOWRAMPUPSET "TimeAllowRampupSet" -#define D_CMND_TEMPMEASUREDSET "TempMeasuredSet" -#define D_CMND_TEMPTARGETSET "TempTargetSet" -#define D_CMND_TEMPTARGETREAD "TempTargetRead" -#define D_CMND_TEMPMEASUREDREAD "TempMeasuredRead" -#define D_CMND_TEMPMEASUREDGRDREAD "TempMeasuredGrdRead" -#define D_CMND_TEMPSENSNUMBERSET "TempSensNumberSet" -#define D_CMND_STATEEMERGENCYSET "StateEmergencySet" -#define D_CMND_POWERMAXSET "PowerMaxSet" -#define D_CMND_TIMEMANUALTOAUTOSET "TimeManualToAutoSet" -#define D_CMND_TIMEONLIMITSET "TimeOnLimitSet" -#define D_CMND_PROPBANDSET "PropBandSet" -#define D_CMND_TIMERESETSET "TimeResetSet" -#define D_CMND_TIMEPICYCLESET "TimePiCycleSet" -#define D_CMND_TEMPANTIWINDUPRESETSET "TempAntiWindupResetSet" -#define D_CMND_TEMPHYSTSET "TempHystSet" -#define D_CMND_TIMEMAXACTIONSET "TimeMaxActionSet" -#define D_CMND_TIMEMINACTIONSET "TimeMinActionSet" -#define D_CMND_TIMEMINTURNOFFACTIONSET "TimeMinTurnoffActionSet" -#define D_CMND_TEMPRUPDELTINSET "TempRupDeltInSet" -#define D_CMND_TEMPRUPDELTOUTSET "TempRupDeltOutSet" -#define D_CMND_TIMERAMPUPMAXSET "TimeRampupMaxSet" -#define D_CMND_TIMERAMPUPCYCLESET "TimeRampupCycleSet" -#define D_CMND_TEMPRAMPUPPIACCERRSET "TempRampupPiAccErrSet" -#define D_CMND_TIMEPIPROPORTREAD "TimePiProportRead" -#define D_CMND_TIMEPIINTEGRREAD "TimePiIntegrRead" -#define D_CMND_TIMESENSLOSTSET "TimeSensLostSet" - -enum ThermostatModes { THERMOSTAT_OFF, THERMOSTAT_AUTOMATIC_OP, THERMOSTAT_MANUAL_OP, THERMOSTAT_MODES_MAX }; -enum ControllerModes { CTR_HYBRID, CTR_PI, CTR_RAMP_UP, CTR_MODES_MAX }; -enum ControllerHybridPhases { CTR_HYBRID_RAMP_UP, CTR_HYBRID_PI }; -enum InterfaceStates { IFACE_OFF, IFACE_ON }; -enum CtrCycleStates { CYCLE_OFF, CYCLE_ON }; -enum EmergencyStates { EMERGENCY_OFF, EMERGENCY_ON }; -enum ThermostatSupportedInputSwitches { - THERMOSTAT_INPUT_NONE, - THERMOSTAT_INPUT_SWT1 = 1, - THERMOSTAT_INPUT_SWT2, - THERMOSTAT_INPUT_SWT3, - THERMOSTAT_INPUT_SWT4 -}; -enum ThermostatSupportedOutputRelays { - THERMOSTAT_OUTPUT_NONE, - THERMOSTAT_OUTPUT_REL1 = 1, - THERMOSTAT_OUTPUT_REL2, - THERMOSTAT_OUTPUT_REL3, - THERMOSTAT_OUTPUT_REL4, - THERMOSTAT_OUTPUT_REL5, - THERMOSTAT_OUTPUT_REL6, - THERMOSTAT_OUTPUT_REL7, - THERMOSTAT_OUTPUT_REL8 -}; - -typedef union { - uint16_t data; - struct { - uint16_t thermostat_mode : 2; - uint16_t controller_mode : 2; - uint16_t sensor_alive : 1; - uint16_t command_output : 1; - uint16_t phase_hybrid_ctr : 1; - uint16_t status_output : 1; - uint16_t status_cycle_active : 1; - uint16_t state_emergency : 1; - uint16_t counter_seconds : 6; - }; -} ThermostatBitfield; - -#ifdef DEBUG_THERMOSTAT -const char DOMOTICZ_MES[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\"}"; -#endif - -const char kThermostatCommands[] PROGMEM = "|" D_CMND_THERMOSTATMODESET "|" D_CMND_TEMPFROSTPROTECTSET "|" - D_CMND_CONTROLLERMODESET "|" D_CMND_INPUTSWITCHSET "|" D_CMND_OUTPUTRELAYSET "|" D_CMND_TIMEALLOWRAMPUPSET "|" - D_CMND_TEMPMEASUREDSET "|" D_CMND_TEMPTARGETSET "|" D_CMND_TEMPTARGETREAD "|" - D_CMND_TEMPMEASUREDREAD "|" D_CMND_TEMPMEASUREDGRDREAD "|" D_CMND_TEMPSENSNUMBERSET "|" - D_CMND_STATEEMERGENCYSET "|" D_CMND_POWERMAXSET "|" D_CMND_TIMEMANUALTOAUTOSET "|" D_CMND_TIMEONLIMITSET "|" - D_CMND_PROPBANDSET "|" D_CMND_TIMERESETSET "|" D_CMND_TIMEPICYCLESET "|" D_CMND_TEMPANTIWINDUPRESETSET "|" - D_CMND_TEMPHYSTSET "|" D_CMND_TIMEMAXACTIONSET "|" D_CMND_TIMEMINACTIONSET "|" D_CMND_TIMEMINTURNOFFACTIONSET "|" - D_CMND_TEMPRUPDELTINSET "|" D_CMND_TEMPRUPDELTOUTSET "|" D_CMND_TIMERAMPUPMAXSET "|" D_CMND_TIMERAMPUPCYCLESET "|" - D_CMND_TEMPRAMPUPPIACCERRSET "|" D_CMND_TIMEPIPROPORTREAD "|" D_CMND_TIMEPIINTEGRREAD "|" D_CMND_TIMESENSLOSTSET; - -void (* const ThermostatCommand[])(void) PROGMEM = { - &CmndThermostatModeSet, &CmndTempFrostProtectSet, &CmndControllerModeSet, &CmndInputSwitchSet, &CmndOutputRelaySet, - &CmndTimeAllowRampupSet, &CmndTempMeasuredSet, &CmndTempTargetSet, &CmndTempTargetRead, - &CmndTempMeasuredRead, &CmndTempMeasuredGrdRead, &CmndTempSensNumberSet, &CmndStateEmergencySet, - &CmndPowerMaxSet, &CmndTimeManualToAutoSet, &CmndTimeOnLimitSet, &CmndPropBandSet, &CmndTimeResetSet, - &CmndTimePiCycleSet, &CmndTempAntiWindupResetSet, &CmndTempHystSet, &CmndTimeMaxActionSet, - &CmndTimeMinActionSet, &CmndTimeMinTurnoffActionSet, &CmndTempRupDeltInSet, &CmndTempRupDeltOutSet, - &CmndTimeRampupMaxSet, &CmndTimeRampupCycleSet, &CmndTempRampupPiAccErrSet, &CmndTimePiProportRead, - &CmndTimePiIntegrRead, &CmndTimeSensLostSet }; - -struct THERMOSTAT { - uint32_t timestamp_temp_measured_update = 0; - uint32_t timestamp_temp_meas_change_update = 0; - uint32_t timestamp_output_off = 0; - uint32_t timestamp_input_on = 0; - uint32_t time_thermostat_total = 0; - uint32_t time_ctr_checkpoint = 0; - uint32_t time_ctr_changepoint = 0; - int32_t temp_measured_gradient = 0; - int16_t temp_target_level = THERMOSTAT_TEMP_INIT; - int16_t temp_target_level_ctr = THERMOSTAT_TEMP_INIT; - int16_t temp_pi_accum_error = 0; - int16_t temp_pi_error = 0; - int32_t time_proportional_pi; - int32_t time_integral_pi; - int32_t time_total_pi; - uint16_t kP_pi = 0; - uint16_t kI_pi = 0; - int32_t temp_rampup_meas_gradient = 0; - uint32_t timestamp_rampup_start = 0; - uint32_t time_rampup_deadtime = 0; - uint32_t time_rampup_nextcycle = 0; - int16_t temp_measured = 0; - uint8_t time_output_delay = THERMOSTAT_TIME_OUTPUT_DELAY; - uint8_t counter_rampup_cycles = 0; - uint8_t output_relay_number = THERMOSTAT_RELAY_NUMBER; - uint8_t input_switch_number = THERMOSTAT_SWITCH_NUMBER; - uint8_t temp_sens_number = THERMOSTAT_TEMP_SENS_NUMBER; - uint8_t temp_rampup_pi_acc_error = THERMOSTAT_TEMP_PI_RAMPUP_ACC_E; - uint8_t temp_rampup_delta_out = THERMOSTAT_TEMP_RAMPUP_DELTA_OUT; - uint8_t temp_rampup_delta_in = THERMOSTAT_TEMP_RAMPUP_DELTA_IN; - int16_t temp_rampup_output_off = 0; - int16_t temp_rampup_start = 0; - int16_t temp_rampup_cycle = 0; - uint16_t time_rampup_max = THERMOSTAT_TIME_RAMPUP_MAX; - uint16_t time_rampup_cycle = THERMOSTAT_TIME_RAMPUP_CYCLE; - uint16_t time_allow_rampup = THERMOSTAT_TIME_ALLOW_RAMPUP; - uint16_t time_sens_lost = THERMOSTAT_TIME_SENS_LOST; - uint16_t time_manual_to_auto = THERMOSTAT_TIME_MANUAL_TO_AUTO; - uint16_t time_on_limit = THERMOSTAT_TIME_ON_LIMIT; - uint32_t time_reset = THERMOSTAT_TIME_RESET; - uint16_t time_pi_cycle = THERMOSTAT_TIME_PI_CYCLE; - uint16_t time_max_action = THERMOSTAT_TIME_MAX_ACTION; - uint16_t time_min_action = THERMOSTAT_TIME_MIN_ACTION; - uint16_t time_min_turnoff_action = THERMOSTAT_TIME_MIN_TURNOFF_ACTION; - uint8_t val_prop_band = THERMOSTAT_PROP_BAND; - uint8_t temp_reset_anti_windup = THERMOSTAT_TEMP_RESET_ANTI_WINDUP; - int8_t temp_hysteresis = THERMOSTAT_TEMP_HYSTERESIS; - uint8_t temp_frost_protect = THERMOSTAT_TEMP_FROST_PROTECT; - uint16_t power_max = THERMOSTAT_POWER_MAX; - ThermostatBitfield status; -} Thermostat; - - - -void ThermostatInit(void) -{ - ExecuteCommandPower(Thermostat.output_relay_number, POWER_OFF, SRC_THERMOSTAT); - - Thermostat.status.thermostat_mode = THERMOSTAT_OFF; - Thermostat.status.controller_mode = CTR_HYBRID; - Thermostat.status.sensor_alive = IFACE_OFF; - Thermostat.status.command_output = IFACE_OFF; - Thermostat.status.phase_hybrid_ctr = CTR_HYBRID_PI; - Thermostat.status.status_output = IFACE_OFF; - Thermostat.status.status_cycle_active = CYCLE_OFF; - Thermostat.status.state_emergency = EMERGENCY_OFF; - Thermostat.status.counter_seconds = 0; -} - -bool ThermostatMinuteCounter(void) -{ - bool result = false; - Thermostat.status.counter_seconds++; - - if ((Thermostat.status.counter_seconds % 60) == 0) { - result = true; - Thermostat.status.counter_seconds = 0; - } - return result; -} - -inline bool ThermostatSwitchIdValid(uint8_t switchId) -{ - return (switchId >= THERMOSTAT_INPUT_SWT1 && switchId <= THERMOSTAT_INPUT_SWT4); -} - -inline bool ThermostatRelayIdValid(uint8_t relayId) -{ - return (relayId >= THERMOSTAT_OUTPUT_REL1 && relayId <= THERMOSTAT_OUTPUT_REL8); -} - -uint8_t ThermostatSwitchStatus(uint8_t input_switch) -{ - bool ifId = ThermostatSwitchIdValid(input_switch); - if(ifId) { - return(SwitchGetVirtual(ifId - THERMOSTAT_INPUT_SWT1)); - } - else return 255; -} - -void ThermostatSignalProcessingSlow(void) -{ - if ((uptime - Thermostat.timestamp_temp_measured_update) > ((uint32_t)Thermostat.time_sens_lost * 60)) { - Thermostat.status.sensor_alive = IFACE_OFF; - Thermostat.temp_measured_gradient = 0; - Thermostat.temp_measured = 0; - } -} - -void ThermostatSignalProcessingFast(void) -{ - if (ThermostatSwitchStatus(Thermostat.input_switch_number)) { - Thermostat.timestamp_input_on = uptime; - } -} - -void ThermostatCtrState(void) -{ - switch (Thermostat.status.controller_mode) { - case CTR_HYBRID: - ThermostatHybridCtrPhase(); - break; - case CTR_PI: - break; - case CTR_RAMP_UP: - break; - } -} - -void ThermostatHybridCtrPhase(void) -{ - if (Thermostat.status.controller_mode == CTR_HYBRID) { - switch (Thermostat.status.phase_hybrid_ctr) { - case CTR_HYBRID_RAMP_UP: - - - if((Thermostat.time_ctr_checkpoint != 0) - && (uptime >= Thermostat.time_ctr_checkpoint)) { - - Thermostat.time_ctr_checkpoint = 0; - - Thermostat.time_ctr_changepoint = 0; - - Thermostat.status.phase_hybrid_ctr = CTR_HYBRID_PI; - } - break; - case CTR_HYBRID_PI: - - - - - if (((uptime - Thermostat.timestamp_output_off) > (60 * (uint32_t)Thermostat.time_allow_rampup)) - && (Thermostat.temp_target_level != Thermostat.temp_target_level_ctr) - &&((Thermostat.temp_target_level - Thermostat.temp_measured) > Thermostat.temp_rampup_delta_in)) { - Thermostat.timestamp_rampup_start = uptime; - Thermostat.temp_rampup_start = Thermostat.temp_measured; - Thermostat.temp_rampup_meas_gradient = 0; - Thermostat.time_rampup_deadtime = 0; - Thermostat.counter_rampup_cycles = 1; - Thermostat.time_ctr_changepoint = 0; - Thermostat.time_ctr_checkpoint = 0; - Thermostat.status.phase_hybrid_ctr = CTR_HYBRID_RAMP_UP; - } - break; - } - } -#ifdef DEBUG_THERMOSTAT - ThermostatVirtualSwitchCtrState(); -#endif -} - -bool HeatStateAutoToManual(void) -{ - bool change_state = false; - - - - - if ((ThermostatSwitchStatus(Thermostat.input_switch_number) == 1) - || (Thermostat.status.sensor_alive == IFACE_OFF)) { - change_state = true; - } - return change_state; -} - -bool HeatStateManualToAuto(void) -{ - bool change_state; - - - - - - if ((ThermostatSwitchStatus(Thermostat.input_switch_number) == 0) - &&(Thermostat.status.sensor_alive == IFACE_ON) - && ((uptime - Thermostat.timestamp_input_on) > ((uint32_t)Thermostat.time_manual_to_auto * 60))) { - change_state = true; - } - return change_state; -} - -bool HeatStateAllToOff(void) -{ - bool change_state; - - - if (Thermostat.status.state_emergency == EMERGENCY_ON) { - Thermostat.status.thermostat_mode = THERMOSTAT_OFF; - } - return change_state; -} - -void ThermostatState(void) -{ - switch (Thermostat.status.thermostat_mode) { - case THERMOSTAT_OFF: - - break; - case THERMOSTAT_AUTOMATIC_OP: - if (HeatStateAllToOff()) { - Thermostat.status.thermostat_mode = THERMOSTAT_OFF; - } - if (HeatStateAutoToManual()) { - Thermostat.status.thermostat_mode = THERMOSTAT_MANUAL_OP; - } - ThermostatCtrState(); - break; - case THERMOSTAT_MANUAL_OP: - if (HeatStateAllToOff()) { - Thermostat.status.thermostat_mode = THERMOSTAT_OFF; - } - if (HeatStateManualToAuto()) { - Thermostat.status.thermostat_mode = THERMOSTAT_AUTOMATIC_OP; - } - break; - } -} - -void ThermostatOutputRelay(bool active) -{ - - - - - if ((active == true) - && (Thermostat.status.status_output == IFACE_OFF)) { - ExecuteCommandPower(Thermostat.output_relay_number, POWER_ON, SRC_THERMOSTAT); - Thermostat.status.status_output = IFACE_ON; -#ifdef DEBUG_THERMOSTAT - ThermostatVirtualSwitch(); -#endif - } - - - - else if ((active == false) && (Thermostat.status.status_output == IFACE_ON)) { - ExecuteCommandPower(Thermostat.output_relay_number, POWER_OFF, SRC_THERMOSTAT); - Thermostat.timestamp_output_off = uptime; - Thermostat.status.status_output = IFACE_OFF; -#ifdef DEBUG_THERMOSTAT - ThermostatVirtualSwitch(); -#endif - } -} - -void ThermostatCalculatePI(void) -{ - int32_t aux_time_error; - - - aux_time_error = (int32_t)(Thermostat.temp_target_level_ctr - Thermostat.temp_measured) * 10; - - - if (aux_time_error <= (int32_t)(INT16_MIN)) { - Thermostat.temp_pi_error = (int16_t)(INT16_MIN); - } - else if (aux_time_error >= (int32_t)INT16_MAX) { - Thermostat.temp_pi_error = (int16_t)INT16_MAX; - } - else { - Thermostat.temp_pi_error = (int16_t)aux_time_error; - } - - - Thermostat.kP_pi = 100 / (uint16_t)(Thermostat.val_prop_band); - - Thermostat.time_proportional_pi = ((int32_t)(Thermostat.temp_pi_error * (int16_t)Thermostat.kP_pi) * ((int32_t)Thermostat.time_pi_cycle * 60)) / 10000; - - - - - - if ((Thermostat.time_proportional_pi < abs(((int32_t)Thermostat.time_min_action * 60))) - && (Thermostat.time_proportional_pi > 0)) { - Thermostat.time_proportional_pi = ((int32_t)Thermostat.time_min_action * 60); - } - - if (Thermostat.time_proportional_pi < 0) { - Thermostat.time_proportional_pi = 0; - } - else if (Thermostat.time_proportional_pi > ((int32_t)Thermostat.time_pi_cycle * 60)) { - Thermostat.time_proportional_pi = ((int32_t)Thermostat.time_pi_cycle * 60); - } - - - - Thermostat.kI_pi = (uint16_t)((((uint32_t)Thermostat.kP_pi * (uint32_t)Thermostat.time_pi_cycle * 6000)) / (uint32_t)Thermostat.time_reset); - - - - - if (abs((Thermostat.temp_pi_error) / 10) > Thermostat.temp_reset_anti_windup) { - Thermostat.time_integral_pi = 0; - Thermostat.temp_pi_accum_error = 0; - } - - - - else { -# 459 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_39_thermostat.ino" - aux_time_error = (int32_t)Thermostat.temp_pi_accum_error + (int32_t)Thermostat.temp_pi_error; - - - if (aux_time_error <= (int32_t)INT16_MIN) { - Thermostat.temp_pi_accum_error = INT16_MIN; - } - else if (aux_time_error >= (int32_t)INT16_MAX) { - Thermostat.temp_pi_accum_error = INT16_MAX; - } - else { - Thermostat.temp_pi_accum_error = (int16_t)aux_time_error; - } - - - - - if ((Thermostat.temp_pi_error >= 0) - && (abs((Thermostat.temp_pi_error) / 10) <= (int16_t)Thermostat.temp_hysteresis) - && (Thermostat.temp_measured_gradient > 0)) { - - Thermostat.temp_pi_accum_error *= 0.8; - } - - - else if ((Thermostat.temp_pi_error < 0) - && (Thermostat.temp_measured_gradient > 0)) { - - Thermostat.temp_pi_accum_error *= 0.8; - } - - - if (Thermostat.temp_pi_accum_error < 0) { - Thermostat.temp_pi_accum_error = 0; - } - - - Thermostat.time_integral_pi = (((int32_t)Thermostat.temp_pi_accum_error * (int32_t)Thermostat.kI_pi) * (int32_t)((uint32_t)Thermostat.time_pi_cycle * 60)) / 1000000; - - - - - if (Thermostat.time_integral_pi > ((uint32_t)Thermostat.time_pi_cycle * 60)) { - Thermostat.time_integral_pi = ((uint32_t)Thermostat.time_pi_cycle * 60); - } - } - - - Thermostat.time_total_pi = Thermostat.time_proportional_pi + Thermostat.time_integral_pi; - - - - - if (Thermostat.time_total_pi >= ((int32_t)Thermostat.time_pi_cycle * 60)) { - - Thermostat.time_total_pi = ((int32_t)Thermostat.time_pi_cycle * 60); - } - else if (Thermostat.time_total_pi < 0) { - Thermostat.time_total_pi = 0; - } - - - - if (Thermostat.temp_pi_error <= 0) { - - if ((abs((Thermostat.temp_pi_error) / 10) > Thermostat.temp_hysteresis) - || (Thermostat.temp_measured_gradient >= 0)) { - Thermostat.time_total_pi = 0; - } - } - - - - - else if ((Thermostat.temp_pi_error > 0) - && (abs((Thermostat.temp_pi_error) / 10) <= Thermostat.temp_hysteresis) - && (Thermostat.temp_measured_gradient > 0)) { - Thermostat.time_total_pi = 0; - } - - - - if ((Thermostat.time_total_pi <= abs(((uint32_t)Thermostat.time_min_action * 60))) - && (Thermostat.time_total_pi != 0)) { - Thermostat.time_total_pi = ((int32_t)Thermostat.time_min_action * 60); - } - - - else if (Thermostat.time_total_pi > abs(((int32_t)Thermostat.time_max_action * 60))) { - Thermostat.time_total_pi = ((int32_t)Thermostat.time_max_action * 60); - } - - else if (Thermostat.time_total_pi > (((int32_t)Thermostat.time_pi_cycle * 60) - ((int32_t)Thermostat.time_min_turnoff_action * 60))) { - Thermostat.time_total_pi = ((int32_t)Thermostat.time_pi_cycle * 60); - } - - - Thermostat.time_ctr_changepoint = uptime + (uint32_t)Thermostat.time_total_pi; - - Thermostat.time_ctr_checkpoint = uptime + ((uint32_t)Thermostat.time_pi_cycle * 60); -} - -void ThermostatWorkAutomaticPI(void) -{ - char result_chr[FLOATSZ]; - - if ((uptime >= Thermostat.time_ctr_checkpoint) - || (Thermostat.temp_target_level != Thermostat.temp_target_level_ctr) - || ((Thermostat.temp_measured < Thermostat.temp_target_level) - && (Thermostat.temp_measured_gradient < 0) - && (Thermostat.status.status_cycle_active == CYCLE_OFF))) { - Thermostat.temp_target_level_ctr = Thermostat.temp_target_level; - ThermostatCalculatePI(); - - Thermostat.status.status_cycle_active = CYCLE_OFF; - } - if (uptime < Thermostat.time_ctr_changepoint) { - Thermostat.status.status_cycle_active = CYCLE_ON; - Thermostat.status.command_output = IFACE_ON; - } - else { - Thermostat.status.command_output = IFACE_OFF; - } -} - -void ThermostatWorkAutomaticRampUp(void) -{ - int32_t aux_temp_delta; - uint32_t time_in_rampup; - int16_t temp_delta_rampup; - - - if (Thermostat.temp_measured < Thermostat.temp_rampup_start) { - Thermostat.temp_rampup_start = Thermostat.temp_measured; - } - - - time_in_rampup = uptime - Thermostat.timestamp_rampup_start; - temp_delta_rampup = Thermostat.temp_measured - Thermostat.temp_rampup_start; - - Thermostat.status.command_output = IFACE_ON; - - Thermostat.temp_target_level_ctr = Thermostat.temp_target_level; - - - - if ((time_in_rampup <= (60 * (uint32_t)Thermostat.time_rampup_max)) - && (Thermostat.temp_measured < Thermostat.temp_target_level)) { - - - - if ((temp_delta_rampup >= Thermostat.temp_rampup_delta_out) - && (Thermostat.time_rampup_deadtime == 0)) { - - - int32_t time_aux; - time_aux = ((time_in_rampup / 2) - Thermostat.time_output_delay); - if (time_aux >= Thermostat.time_output_delay) { - Thermostat.time_rampup_deadtime = (uint32_t)time_aux; - } - else { - Thermostat.time_rampup_deadtime = Thermostat.time_output_delay; - } - - Thermostat.temp_rampup_meas_gradient = (int32_t)((360000 * (int32_t)temp_delta_rampup) / (int32_t)time_in_rampup); - Thermostat.time_rampup_nextcycle = uptime + (uint32_t)Thermostat.time_rampup_cycle; - - Thermostat.temp_rampup_cycle = Thermostat.temp_measured; - Thermostat.time_ctr_changepoint = uptime + (60 * (uint32_t)Thermostat.time_rampup_max); - Thermostat.temp_rampup_output_off = Thermostat.temp_target_level_ctr; - } - - else if ((Thermostat.time_rampup_deadtime > 0) && (uptime >= Thermostat.time_rampup_nextcycle)) { - - - temp_delta_rampup = Thermostat.temp_measured - Thermostat.temp_rampup_cycle; - uint32_t time_total_rampup = (uint32_t)Thermostat.time_rampup_cycle * Thermostat.counter_rampup_cycles; - - Thermostat.temp_rampup_meas_gradient = int32_t((360000 * (int32_t)temp_delta_rampup) / (int32_t)time_total_rampup); - if (Thermostat.temp_rampup_meas_gradient > 0) { - - - - - - - - aux_temp_delta = (int32_t)(Thermostat.temp_target_level_ctr - Thermostat.temp_rampup_cycle); - - - if ((aux_temp_delta < 0) - ||(temp_delta_rampup <= 0)) { - Thermostat.time_ctr_changepoint = uptime + (uint32_t)(60 * Thermostat.time_rampup_max); - } - else { - Thermostat.time_ctr_changepoint = (uint32_t)(uint32_t)(((uint32_t)(aux_temp_delta) * (uint32_t)(time_total_rampup)) / (uint32_t)temp_delta_rampup) + (uint32_t)Thermostat.time_rampup_nextcycle - (uint32_t)time_total_rampup - (uint32_t)Thermostat.time_rampup_deadtime; - } - - - - - Thermostat.temp_rampup_output_off = (int16_t)(((float)temp_delta_rampup * (float)(Thermostat.time_ctr_changepoint - (uptime - (time_total_rampup)))) / (float)(time_total_rampup * Thermostat.counter_rampup_cycles)) + Thermostat.temp_rampup_cycle; - - Thermostat.time_rampup_nextcycle = uptime + (uint32_t)Thermostat.time_rampup_cycle; - Thermostat.temp_rampup_cycle = Thermostat.temp_measured; - - Thermostat.counter_rampup_cycles = 1; - } - else { - - Thermostat.counter_rampup_cycles++; - - Thermostat.time_rampup_nextcycle = uptime + (uint32_t)Thermostat.time_rampup_cycle; - - Thermostat.time_ctr_changepoint = uptime + (60 * (uint32_t)Thermostat.time_rampup_max) - time_in_rampup; - Thermostat.temp_rampup_output_off = Thermostat.temp_target_level_ctr; - } - - Thermostat.time_ctr_checkpoint = Thermostat.time_ctr_changepoint + Thermostat.time_rampup_deadtime; - } - - - - - - - if ((Thermostat.time_rampup_deadtime == 0) - || (Thermostat.time_ctr_checkpoint == 0) - || (uptime < Thermostat.time_ctr_changepoint) - || (Thermostat.temp_measured < Thermostat.temp_rampup_output_off) - || (Thermostat.temp_rampup_meas_gradient <= 0)) { - Thermostat.status.command_output = IFACE_ON; - } - else { - Thermostat.status.command_output = IFACE_OFF; - } - } - else { - - if (Thermostat.temp_measured < Thermostat.temp_target_level_ctr) { - Thermostat.temp_pi_accum_error = Thermostat.temp_rampup_pi_acc_error; - } - - Thermostat.time_ctr_checkpoint = uptime; - - Thermostat.status.command_output = IFACE_OFF; - } -} - -void ThermostatCtrWork(void) -{ - switch (Thermostat.status.controller_mode) { - case CTR_HYBRID: - switch (Thermostat.status.phase_hybrid_ctr) { - case CTR_HYBRID_RAMP_UP: - ThermostatWorkAutomaticRampUp(); - break; - case CTR_HYBRID_PI: - ThermostatWorkAutomaticPI(); - break; - } - break; - case CTR_PI: - ThermostatWorkAutomaticPI(); - break; - case CTR_RAMP_UP: - ThermostatWorkAutomaticRampUp(); - break; - } -} - -void ThermostatWork(void) -{ - switch (Thermostat.status.thermostat_mode) { - case THERMOSTAT_OFF: - Thermostat.status.command_output = IFACE_OFF; - break; - case THERMOSTAT_AUTOMATIC_OP: - ThermostatCtrWork(); - break; - case THERMOSTAT_MANUAL_OP: - Thermostat.time_ctr_checkpoint = 0; - if (ThermostatSwitchStatus(Thermostat.input_switch_number) == 1) { - Thermostat.status.command_output = IFACE_ON; - } - else { - Thermostat.status.command_output = IFACE_OFF; - } - break; - } - bool output_command; - if (Thermostat.status.command_output == IFACE_OFF) { - output_command = false; - } - else { - output_command = true; - } - ThermostatOutputRelay(output_command); -} - -void ThermostatDiagnostics(void) -{ - - - - -} - -void ThermostatController(void) -{ - ThermostatState(); - ThermostatWork(); -} - -bool ThermostatTimerArm(int16_t tempVal) -{ - bool result = false; - - if ((tempVal >= -1000) - && (tempVal <= 1000) - && (tempVal >= (int16_t)Thermostat.temp_frost_protect)) { - Thermostat.temp_target_level = tempVal; - Thermostat.status.thermostat_mode = THERMOSTAT_AUTOMATIC_OP; - result = true; - } - - return result; -} - -void ThermostatTimerDisarm(void) -{ - Thermostat.temp_target_level = THERMOSTAT_TEMP_INIT; - Thermostat.status.thermostat_mode = THERMOSTAT_OFF; -} - -#ifdef DEBUG_THERMOSTAT -void ThermostatVirtualSwitch(void) -{ - char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; - Response_P(DOMOTICZ_MES, DOMOTICZ_IDX1, (0 == Thermostat.status.status_output) ? 0 : 1, ""); - MqttPublish(domoticz_in_topic); -} - -void ThermostatVirtualSwitchCtrState(void) -{ - char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; - Response_P(DOMOTICZ_MES, DOMOTICZ_IDX2, (0 == Thermostat.status.phase_hybrid_ctr) ? 0 : 1, ""); - MqttPublish(domoticz_in_topic); - - - -} -#endif - - - - - -void CmndThermostatModeSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(CharToFloat(XdrvMailbox.data)); - if ((value >= THERMOSTAT_OFF) && (value < THERMOSTAT_MODES_MAX)) { - Thermostat.status.thermostat_mode = value; - Thermostat.timestamp_input_on = 0; - } - } - ResponseCmndNumber((int)Thermostat.status.thermostat_mode); -} - -void CmndTempFrostProtectSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= 0) && (value <= 255)) { - Thermostat.temp_frost_protect = value; - } - } - ResponseCmndFloat((float)(Thermostat.temp_frost_protect) / 10, 1); -} - -void CmndControllerModeSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(XdrvMailbox.payload); - if ((value >= 0) && (value < CTR_MODES_MAX)) { - Thermostat.status.controller_mode = value; - } - } - ResponseCmndNumber((int)Thermostat.status.controller_mode); -} - -void CmndInputSwitchSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(XdrvMailbox.payload); - if (ThermostatSwitchIdValid(value)) { - Thermostat.input_switch_number = value; - Thermostat.timestamp_input_on = uptime; - } - } - ResponseCmndNumber((int)Thermostat.input_switch_number); -} - -void CmndOutputRelaySet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(XdrvMailbox.payload); - if (ThermostatRelayIdValid(value)) { - Thermostat.output_relay_number = value; - } - } - ResponseCmndNumber((int)Thermostat.output_relay_number); -} - -void CmndTimeAllowRampupSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value < 86400)) { - Thermostat.time_allow_rampup = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_allow_rampup * 60)); -} - -void CmndTempMeasuredSet(void) -{ - if (XdrvMailbox.data_len > 0) { - int16_t value = (int16_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= -1000) && (value <= 1000)) { - uint32_t timestamp = uptime; - - if (value != Thermostat.temp_measured) { - int32_t temp_delta = (value - Thermostat.temp_measured); - uint32_t time_delta = (timestamp - Thermostat.timestamp_temp_meas_change_update); - Thermostat.temp_measured_gradient = (int32_t)((360000 * temp_delta) / ((int32_t)time_delta)); - Thermostat.temp_measured = value; - Thermostat.timestamp_temp_meas_change_update = timestamp; - } - Thermostat.timestamp_temp_measured_update = timestamp; - Thermostat.status.sensor_alive = IFACE_ON; - } - } - ResponseCmndFloat(((float)Thermostat.temp_measured) / 10, 1); -} - -void CmndTempTargetSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint16_t value = (uint16_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= -1000) - && (value <= 1000) - && (value >= (int16_t)Thermostat.temp_frost_protect)) { - Thermostat.temp_target_level = value; - } - } - ResponseCmndFloat(((float)Thermostat.temp_target_level) / 10, 1); -} - -void CmndTempTargetRead(void) -{ - ResponseCmndFloat(((float)Thermostat.temp_target_level) / 10, 1); -} - -void CmndTempMeasuredRead(void) -{ - ResponseCmndFloat((float)(Thermostat.temp_measured) / 10, 1); -} - -void CmndTempMeasuredGrdRead(void) -{ - ResponseCmndFloat((float)(Thermostat.temp_measured_gradient) / 1000, 1); -} - -void CmndTempSensNumberSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 255)) { - Thermostat.temp_sens_number = value; - } - } - ResponseCmndNumber((int)Thermostat.temp_sens_number); -} - -void CmndStateEmergencySet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 1)) { - Thermostat.status.state_emergency = (uint16_t)value; - } - } - ResponseCmndNumber((int)Thermostat.status.state_emergency); -} - -void CmndPowerMaxSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint16_t value = (uint16_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 1300)) { - Thermostat.power_max = value; - } - } - ResponseCmndNumber((int)Thermostat.power_max); -} - -void CmndTimeManualToAutoSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_manual_to_auto = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_manual_to_auto * 60)); -} - -void CmndTimeOnLimitSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_on_limit = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_on_limit * 60)); -} - -void CmndPropBandSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 20)) { - Thermostat.val_prop_band = value; - } - } - ResponseCmndNumber((int)Thermostat.val_prop_band); -} - -void CmndTimeResetSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_reset = value; - } - } - ResponseCmndNumber((int)Thermostat.time_reset); -} - -void CmndTimePiCycleSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_pi_cycle = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_pi_cycle * 60)); -} - -void CmndTempAntiWindupResetSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= (float)(0)) && (value <= (float)(100.0))) { - Thermostat.temp_reset_anti_windup = value; - } - } - ResponseCmndFloat((float)(Thermostat.temp_reset_anti_windup) / 10, 1); -} - -void CmndTempHystSet(void) -{ - if (XdrvMailbox.data_len > 0) { - int8_t value = (int8_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= -100) && (value <= 100)) { - Thermostat.temp_hysteresis = value; - } - } - ResponseCmndFloat((float)(Thermostat.temp_hysteresis) / 10, 1); -} - -void CmndTimeMaxActionSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_max_action = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_max_action * 60)); -} - -void CmndTimeMinActionSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_min_action = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_min_action * 60)); -} - -void CmndTimeSensLostSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_sens_lost = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_sens_lost * 60)); -} - -void CmndTimeMinTurnoffActionSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_min_turnoff_action = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)((uint32_t)Thermostat.time_min_turnoff_action * 60)); -} - -void CmndTempRupDeltInSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= 0) && (value <= 100)) { - Thermostat.temp_rampup_delta_in = value; - } - } - ResponseCmndFloat((float)(Thermostat.temp_rampup_delta_in) / 10, 1); -} - -void CmndTempRupDeltOutSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint8_t value = (uint8_t)(CharToFloat(XdrvMailbox.data) * 10); - if ((value >= 0) && (value <= 100)) { - Thermostat.temp_rampup_delta_out = value; - } - } - ResponseCmndFloat((float)(Thermostat.temp_rampup_delta_out) / 10, 1); -} - -void CmndTimeRampupMaxSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 86400)) { - Thermostat.time_rampup_max = (uint16_t)(value / 60); - } - } - ResponseCmndNumber((int)(((uint32_t)Thermostat.time_rampup_max) * 60)); -} - -void CmndTimeRampupCycleSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint32_t value = (uint32_t)(XdrvMailbox.payload); - if ((value >= 0) && (value <= 54000)) { - Thermostat.time_rampup_cycle = (uint16_t)value; - } - } - ResponseCmndNumber((int)Thermostat.time_rampup_cycle); -} - -void CmndTempRampupPiAccErrSet(void) -{ - if (XdrvMailbox.data_len > 0) { - uint16_t value = (uint8_t)(CharToFloat(XdrvMailbox.data) * 100); - if ((value >= 0) && (value <= 2500)) { - Thermostat.temp_rampup_pi_acc_error = value; - } - } - ResponseCmndFloat((float)(Thermostat.temp_rampup_pi_acc_error) / 100, 1); -} - -void CmndTimePiProportRead(void) -{ - ResponseCmndNumber((int)Thermostat.time_proportional_pi); -} - -void CmndTimePiIntegrRead(void) -{ - ResponseCmndNumber((int)Thermostat.time_integral_pi); -} - - - - - -bool Xdrv39(uint8_t function) -{ -#ifdef DEBUG_THERMOSTAT - char result_chr[FLOATSZ]; -#endif - bool result = false; - - switch (function) { - case FUNC_INIT: - ThermostatInit(); - break; - case FUNC_LOOP: - ThermostatSignalProcessingFast(); - ThermostatDiagnostics(); - break; - case FUNC_SERIAL: - break; - case FUNC_EVERY_SECOND: - if (ThermostatMinuteCounter()) { - ThermostatSignalProcessingSlow(); - ThermostatController(); -#ifdef DEBUG_THERMOSTAT - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("")); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("------ Thermostat Start ------")); - dtostrfd(Thermostat.status.counter_seconds, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.counter_seconds: %s"), result_chr); - dtostrfd(Thermostat.status.thermostat_mode, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.thermostat_mode: %s"), result_chr); - dtostrfd(Thermostat.status.controller_mode, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.controller_mode: %s"), result_chr); - dtostrfd(Thermostat.status.phase_hybrid_ctr, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.phase_hybrid_ctr: %s"), result_chr); - dtostrfd(Thermostat.status.sensor_alive, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.sensor_alive: %s"), result_chr); - dtostrfd(Thermostat.status.status_output, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.status_output: %s"), result_chr); - dtostrfd(Thermostat.status.status_cycle_active, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.status.status_cycle_active: %s"), result_chr); - dtostrfd(Thermostat.temp_pi_error, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.temp_pi_error: %s"), result_chr); - dtostrfd(Thermostat.temp_pi_accum_error, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.temp_pi_accum_error: %s"), result_chr); - dtostrfd(Thermostat.time_proportional_pi, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.time_proportional_pi: %s"), result_chr); - dtostrfd(Thermostat.time_integral_pi, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.time_integral_pi: %s"), result_chr); - dtostrfd(Thermostat.time_total_pi, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.time_total_pi: %s"), result_chr); - dtostrfd(Thermostat.temp_measured_gradient, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.temp_measured_gradient: %s"), result_chr); - dtostrfd(Thermostat.time_rampup_deadtime, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.time_rampup_deadtime: %s"), result_chr); - dtostrfd(Thermostat.temp_rampup_meas_gradient, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.temp_rampup_meas_gradient: %s"), result_chr); - dtostrfd(Thermostat.time_ctr_changepoint, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.time_ctr_changepoint: %s"), result_chr); - dtostrfd(Thermostat.temp_rampup_output_off, 0, result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Thermostat.temp_rampup_output_off: %s"), result_chr); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("------ Thermostat End ------")); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("")); -#endif - } - break; - case FUNC_COMMAND: - result = DecodeCommand(kThermostatCommands, ThermostatCommand); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_99_debug.ino" -# 22 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_99_debug.ino" -#ifdef DEBUG_THEO -#ifndef USE_DEBUG_DRIVER -#define USE_DEBUG_DRIVER -#endif -#endif - -#ifdef USE_DEBUG_DRIVER - - - - - - -#define XDRV_99 99 - -#ifndef CPU_LOAD_CHECK -#define CPU_LOAD_CHECK 1 -#endif - - - - - -#define D_CMND_CFGDUMP "CfgDump" -#define D_CMND_CFGPEEK "CfgPeek" -#define D_CMND_CFGPOKE "CfgPoke" -#define D_CMND_CFGSHOW "CfgShow" -#define D_CMND_CFGXOR "CfgXor" -#define D_CMND_CPUCHECK "CpuChk" -#define D_CMND_EXCEPTION "Exception" -#define D_CMND_FLASHDUMP "FlashDump" -#define D_CMND_FLASHMODE "FlashMode" -#define D_CMND_FREEMEM "FreeMem" -#define D_CMND_HELP "Help" -#define D_CMND_RTCDUMP "RtcDump" -#define D_CMND_SETSENSOR "SetSensor" -#define D_CMND_I2CWRITE "I2CWrite" -#define D_CMND_I2CREAD "I2CRead" -#define D_CMND_I2CSTRETCH "I2CStretch" -#define D_CMND_I2CCLOCK "I2CClock" - -const char kDebugCommands[] PROGMEM = "|" - D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" -#ifdef USE_WEBSERVER - D_CMND_CFGXOR "|" -#endif - D_CMND_CPUCHECK "|" -#ifdef DEBUG_THEO - D_CMND_EXCEPTION "|" -#endif - D_CMND_FLASHDUMP "|" D_CMND_FLASHMODE "|" D_CMND_FREEMEM"|" D_CMND_HELP "|" D_CMND_RTCDUMP "|" D_CMND_SETSENSOR "|" -#ifdef USE_I2C - D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK -#endif - ; - -void (* const DebugCommand[])(void) PROGMEM = { - &CmndCfgDump, &CmndCfgPeek, &CmndCfgPoke, -#ifdef USE_WEBSERVER - &CmndCfgXor, -#endif - &CmndCpuCheck, -#ifdef DEBUG_THEO - &CmndException, -#endif - &CmndFlashDump, &CmndFlashMode, &CmndFreemem, &CmndHelp, &CmndRtcDump, &CmndSetSensor, -#ifdef USE_I2C - &CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock -#endif - }; - -uint32_t CPU_loops = 0; -uint32_t CPU_last_millis = 0; -uint32_t CPU_last_loop_time = 0; -uint8_t CPU_load_check = 0; -uint8_t CPU_show_freemem = 0; - - - -#ifdef DEBUG_THEO -void ExceptionTest(uint8_t type) -{ -# 145 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_99_debug.ino" - if (1 == type) { - char svalue[10]; - snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); - } -# 159 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_99_debug.ino" - if (2 == type) { - while(1) delay(1000); - } -} - -#endif - - - -void CpuLoadLoop(void) -{ - CPU_last_loop_time = millis(); - if (CPU_load_check && CPU_last_millis) { - CPU_loops ++; - if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) { -#if defined(F_CPU) && (F_CPU == 160000000L) - int CPU_load = 100 - ( (CPU_loops*(1 + 30*ssleep)) / (CPU_load_check *800) ); - CPU_loops = CPU_loops / CPU_load_check; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops); -#else - int CPU_load = 100 - ( (CPU_loops*(1 + 30*ssleep)) / (CPU_load_check *400) ); - CPU_loops = CPU_loops / CPU_load_check; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops); -#endif - CPU_last_millis = CPU_last_loop_time; - CPU_loops = 0; - } - } -} - - - -#ifdef ESP8266 -#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) - - - -extern "C" { -#include - extern cont_t g_cont; -} - -void DebugFreeMem(void) -{ - register uint32_t *sp asm("a1"); - - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_cont.stack), XdrvMailbox.data); -} - -#else - - - - -extern "C" { -#include - extern cont_t* g_pcont; -} - -void DebugFreeMem(void) -{ - register uint32_t *sp asm("a1"); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_pcont->stack), XdrvMailbox.data); -} - -#endif - -#else - -void DebugFreeMem(void) -{ - register uint8_t *sp asm("a1"); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL), XdrvMailbox.data); -} - -#endif - - - -void DebugRtcDump(char* parms) -{ -#ifdef ESP8266 - #define CFG_COLS 16 - - uint16_t idx; - uint16_t maxrow; - uint16_t row; - uint16_t col; - char *p; -# 259 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_99_debug.ino" - uint8_t buffer[768]; - - system_rtc_mem_read(0, (uint32_t*)&buffer, sizeof(buffer)); - - maxrow = ((sizeof(buffer)+CFG_COLS)/CFG_COLS); - - uint16_t srow = strtol(parms, &p, 16) / CFG_COLS; - uint16_t mrow = strtol(p, &p, 10); - - - - if (0 == mrow) { - mrow = 8; - } - if (srow > maxrow) { - srow = maxrow - mrow; - } - if (mrow < (maxrow - srow)) { - maxrow = srow + mrow; - } - - for (row = srow; row < maxrow; row++) { - idx = row * CFG_COLS; - snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx); - for (col = 0; col < CFG_COLS; col++) { - if (!(col%4)) { - snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); - for (col = 0; col < CFG_COLS; col++) { - - - - snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); - AddLog(LOG_LEVEL_INFO); - } -#endif -} - - - -void DebugCfgDump(char* parms) -{ - #define CFG_COLS 16 - - uint16_t idx; - uint16_t maxrow; - uint16_t row; - uint16_t col; - char *p; - - uint8_t *buffer = (uint8_t *) &Settings; - maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS); - - uint16_t srow = strtol(parms, &p, 16) / CFG_COLS; - uint16_t mrow = strtol(p, &p, 10); - - - - if (0 == mrow) { - mrow = 8; - } - if (srow > maxrow) { - srow = maxrow - mrow; - } - if (mrow < (maxrow - srow)) { - maxrow = srow + mrow; - } - - for (row = srow; row < maxrow; row++) { - idx = row * CFG_COLS; - snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx); - for (col = 0; col < CFG_COLS; col++) { - if (!(col%4)) { - snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); - for (col = 0; col < CFG_COLS; col++) { - - - - snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); - AddLog(LOG_LEVEL_INFO); - delay(1); - } -} - -void DebugCfgPeek(char* parms) -{ - char *p; - - uint16_t address = strtol(parms, &p, 16); - if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4; - address = (address >> 2) << 2; - - uint8_t *buffer = (uint8_t *) &Settings; - uint8_t data8 = buffer[address]; - uint16_t data16 = (buffer[address +1] << 8) + buffer[address]; - uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + data16; - - snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), address); - for (uint32_t i = 0; i < 4; i++) { - snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[address +i]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); - for (uint32_t i = 0; i < 4; i++) { - snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[address +i] > 0x20) && (buffer[address +i] < 0x7F)) ? (char)buffer[address +i] : ' '); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s| 0x%02X (%d), 0x%04X (%d), 0x%0LX (%lu)"), log_data, data8, data8, data16, data16, data32, data32); - AddLog(LOG_LEVEL_INFO); -} - -void DebugCfgPoke(char* parms) -{ - char *p; - - uint16_t address = strtol(parms, &p, 16); - if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4; - address = (address >> 2) << 2; - - uint32_t data = strtol(p, &p, 16); - - uint8_t *buffer = (uint8_t *) &Settings; - uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address]; - - uint8_t *nbuffer = (uint8_t *) &data; - for (uint32_t i = 0; i < 4; i++) { buffer[address +i] = nbuffer[+i]; } - - uint32_t ndata32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address]; - - AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: 0x%0LX (%lu) poked to 0x%0LX (%lu)"), address, data32, data32, ndata32, ndata32); -} - -void SetFlashMode(uint8_t mode) -{ -#ifdef ESP8266 - uint8_t *_buffer; - uint32_t address; - - address = 0; - _buffer = new uint8_t[FLASH_SECTOR_SIZE]; - - if (ESP.flashRead(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE)) { - if (_buffer[2] != mode) { - _buffer[2] = mode; - if (ESP.flashEraseSector(address / FLASH_SECTOR_SIZE)) { - ESP.flashWrite(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); - } - } - } - delete[] _buffer; -#endif -} - - - - - -void CmndHelp(void) -{ - AddLog_P(LOG_LEVEL_INFO, PSTR("HLP: "), kDebugCommands); - ResponseCmndDone(); -} - -void CmndRtcDump(void) -{ - DebugRtcDump(XdrvMailbox.data); - ResponseCmndDone(); -} - -void CmndCfgDump(void) -{ - DebugCfgDump(XdrvMailbox.data); - ResponseCmndDone(); -} - -void CmndCfgPeek(void) -{ - DebugCfgPeek(XdrvMailbox.data); - ResponseCmndDone(); -} - -void CmndCfgPoke(void) -{ - DebugCfgPoke(XdrvMailbox.data); - ResponseCmndDone(); -} - -#ifdef USE_WEBSERVER -void CmndCfgXor(void) -{ - if (XdrvMailbox.data_len > 0) { - Web.config_xor_on_set = XdrvMailbox.payload; - } - ResponseCmndNumber(Web.config_xor_on_set); -} -#endif - -#ifdef DEBUG_THEO -void CmndException(void) -{ - if (XdrvMailbox.data_len > 0) { ExceptionTest(XdrvMailbox.payload); } - ResponseCmndDone(); -} -#endif - -void CmndCpuCheck(void) -{ - if (XdrvMailbox.data_len > 0) { - CPU_load_check = XdrvMailbox.payload; - CPU_last_millis = CPU_last_loop_time; - } - ResponseCmndNumber(CPU_load_check); -} - -void CmndFreemem(void) -{ - if (XdrvMailbox.data_len > 0) { - CPU_show_freemem = XdrvMailbox.payload; - } - ResponseCmndNumber(CPU_show_freemem); -} - -void CmndSetSensor(void) -{ - if (XdrvMailbox.index < MAX_XSNS_DRIVERS) { - if (XdrvMailbox.payload >= 0) { - bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1); - if (1 == XdrvMailbox.payload) { - restart_flag = 2; - } - } - Response_P(PSTR("{\"" D_CMND_SETSENSOR "\":")); - XsnsSensorState(); - ResponseJsonEnd(); - } -} - -void CmndFlashMode(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - SetFlashMode(XdrvMailbox.payload); - } - ResponseCmndNumber(ESP.getFlashChipMode()); -} - -uint32_t DebugSwap32(uint32_t x) { - return ((x << 24) & 0xff000000 ) | - ((x << 8) & 0x00ff0000 ) | - ((x >> 8) & 0x0000ff00 ) | - ((x >> 24) & 0x000000ff ); -} - -void CmndFlashDump(void) -{ -#ifdef ESP8266 - - - - const uint32_t flash_start = 0x40200000; - const uint8_t bytes_per_cols = 0x20; - const uint32_t max = (SPIFFS_END + 5) * SPI_FLASH_SEC_SIZE; - - uint32_t start = flash_start; - uint32_t rows = 8; - - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= (max - bytes_per_cols))) { - start += (XdrvMailbox.payload &0x7FFFFFFC); - - char *p; - uint32_t is_payload = strtol(XdrvMailbox.data, &p, 16); - rows = strtol(p, &p, 10); - if (0 == rows) { rows = 8; } - } - uint32_t end = start + (rows * bytes_per_cols); - if ((end - flash_start) > max) { - end = flash_start + max; - } - - for (uint32_t pos = start; pos < end; pos += bytes_per_cols) { - uint32_t* values = (uint32_t*)(pos); - AddLog_P2(LOG_LEVEL_INFO, PSTR("%06X: %08X %08X %08X %08X %08X %08X %08X %08X"), pos - flash_start, - DebugSwap32(values[0]), DebugSwap32(values[1]), DebugSwap32(values[2]), DebugSwap32(values[3]), - DebugSwap32(values[4]), DebugSwap32(values[5]), DebugSwap32(values[6]), DebugSwap32(values[7])); - } - ResponseCmndDone(); -#endif -} - -#ifdef USE_I2C -void CmndI2cWrite(void) -{ - - if (i2c_flg) { - char* parms = XdrvMailbox.data; - uint8_t buffer[100]; - uint32_t index = 0; - - char *p; - char *data = strtok_r(parms, " ,", &p); - while (data != NULL && index < sizeof(buffer)) { - buffer[index++] = strtol(data, nullptr, 16); - data = strtok_r(nullptr, " ,", &p); - } - - if (index > 1) { - AddLogBuffer(LOG_LEVEL_INFO, buffer, index); - - Wire.beginTransmission(buffer[0]); - for (uint32_t i = 1; i < index; i++) { - Wire.write(buffer[i]); - } - int result = Wire.endTransmission(); - AddLog_P2(LOG_LEVEL_INFO, PSTR("I2C: Result %d"), result); - } - } - ResponseCmndDone(); -} - -void CmndI2cRead(void) -{ - - if (i2c_flg) { - char* parms = XdrvMailbox.data; - uint8_t buffer[100]; - uint32_t index = 0; - - char *p; - char *data = strtok_r(parms, " ,", &p); - while (data != NULL && index < sizeof(buffer)) { - buffer[index++] = strtol(data, nullptr, 16); - data = strtok_r(nullptr, " ,", &p); - } - - if (index > 0) { - uint8_t size = 1; - if (index > 1) { - size = buffer[1]; - } - Wire.requestFrom(buffer[0], size); - index = 0; - while (Wire.available() && index < sizeof(buffer)) { - buffer[index++] = Wire.read(); - } - if (index > 0) { - AddLogBuffer(LOG_LEVEL_INFO, buffer, index); - } - } - } - ResponseCmndDone(); -} - -void CmndI2cStretch(void) -{ -#ifdef ESP8266 - if (i2c_flg && (XdrvMailbox.payload > 0)) { - Wire.setClockStretchLimit(XdrvMailbox.payload); - } - ResponseCmndDone(); -#endif -} - -void CmndI2cClock(void) -{ - if (i2c_flg && (XdrvMailbox.payload > 0)) { - Wire.setClock(XdrvMailbox.payload); - } - ResponseCmndDone(); -} -#endif - - - - - -bool Xdrv99(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_LOOP: - CpuLoadLoop(); - break; - case FUNC_FREE_MEM: - if (CPU_show_freemem) { DebugFreeMem(); } - break; - case FUNC_PRE_INIT: - CPU_last_millis = millis(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kDebugCommands, DebugCommand); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_interface.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdrv_interface.ino" -#ifdef XFUNC_PTR_IN_ROM -bool (* const xdrv_func_ptr[])(uint8_t) PROGMEM = { -#else -bool (* const xdrv_func_ptr[])(uint8_t) = { -#endif - -#ifdef XDRV_01 - &Xdrv01, -#endif - -#ifdef XDRV_02 - &Xdrv02, -#endif - -#ifdef XDRV_03 - &Xdrv03, -#endif - -#ifdef XDRV_04 - &Xdrv04, -#endif - -#ifdef XDRV_05 - &Xdrv05, -#endif - -#ifdef XDRV_06 - &Xdrv06, -#endif - -#ifdef XDRV_07 - &Xdrv07, -#endif - -#ifdef XDRV_08 - &Xdrv08, -#endif - -#ifdef XDRV_09 - &Xdrv09, -#endif - -#ifdef XDRV_10 - &Xdrv10, -#endif - -#ifdef XDRV_11 - &Xdrv11, -#endif - -#ifdef XDRV_12 - &Xdrv12, -#endif - -#ifdef XDRV_13 - &Xdrv13, -#endif - -#ifdef XDRV_14 - &Xdrv14, -#endif - -#ifdef XDRV_15 - &Xdrv15, -#endif - -#ifdef XDRV_16 - &Xdrv16, -#endif - -#ifdef XDRV_17 - &Xdrv17, -#endif - -#ifdef XDRV_18 - &Xdrv18, -#endif - -#ifdef XDRV_19 - &Xdrv19, -#endif - -#ifdef XDRV_20 - &Xdrv20, -#endif - -#ifdef XDRV_21 - &Xdrv21, -#endif - -#ifdef XDRV_22 - &Xdrv22, -#endif - -#ifdef XDRV_23 - &Xdrv23, -#endif - -#ifdef XDRV_24 - &Xdrv24, -#endif - -#ifdef XDRV_25 - &Xdrv25, -#endif - -#ifdef XDRV_26 - &Xdrv26, -#endif - -#ifdef XDRV_27 - &Xdrv27, -#endif - -#ifdef XDRV_28 - &Xdrv28, -#endif - -#ifdef XDRV_29 - &Xdrv29, -#endif - -#ifdef XDRV_30 - &Xdrv30, -#endif - -#ifdef XDRV_31 - &Xdrv31, -#endif - -#ifdef XDRV_32 - &Xdrv32, -#endif - -#ifdef XDRV_33 - &Xdrv33, -#endif - -#ifdef XDRV_34 - &Xdrv34, -#endif - -#ifdef XDRV_35 - &Xdrv35, -#endif - -#ifdef XDRV_36 - &Xdrv36, -#endif - -#ifdef XDRV_37 - &Xdrv37, -#endif - -#ifdef XDRV_38 - &Xdrv38, -#endif - -#ifdef XDRV_39 - &Xdrv39, -#endif - -#ifdef XDRV_40 - &Xdrv40, -#endif - -#ifdef XDRV_41 - &Xdrv41, -#endif - -#ifdef XDRV_42 - &Xdrv42, -#endif - -#ifdef XDRV_43 - &Xdrv43, -#endif - -#ifdef XDRV_44 - &Xdrv44, -#endif - -#ifdef XDRV_45 - &Xdrv45, -#endif - -#ifdef XDRV_46 - &Xdrv46, -#endif - -#ifdef XDRV_47 - &Xdrv47, -#endif - -#ifdef XDRV_48 - &Xdrv48, -#endif - -#ifdef XDRV_49 - &Xdrv49, -#endif - -#ifdef XDRV_50 - &Xdrv50, -#endif - -#ifdef XDRV_51 - &Xdrv51, -#endif - -#ifdef XDRV_52 - &Xdrv52, -#endif - -#ifdef XDRV_53 - &Xdrv53, -#endif - -#ifdef XDRV_54 - &Xdrv54, -#endif - -#ifdef XDRV_55 - &Xdrv55, -#endif - -#ifdef XDRV_56 - &Xdrv56, -#endif - -#ifdef XDRV_57 - &Xdrv57, -#endif - -#ifdef XDRV_58 - &Xdrv58, -#endif - -#ifdef XDRV_59 - &Xdrv59, -#endif - -#ifdef XDRV_60 - &Xdrv60, -#endif - -#ifdef XDRV_61 - &Xdrv61, -#endif - -#ifdef XDRV_62 - &Xdrv62, -#endif - -#ifdef XDRV_63 - &Xdrv63, -#endif - -#ifdef XDRV_64 - &Xdrv64, -#endif - -#ifdef XDRV_65 - &Xdrv65, -#endif - -#ifdef XDRV_66 - &Xdrv66, -#endif - -#ifdef XDRV_67 - &Xdrv67, -#endif - -#ifdef XDRV_68 - &Xdrv68, -#endif - -#ifdef XDRV_69 - &Xdrv69, -#endif - -#ifdef XDRV_70 - &Xdrv70, -#endif - -#ifdef XDRV_71 - &Xdrv71, -#endif - -#ifdef XDRV_72 - &Xdrv72, -#endif - -#ifdef XDRV_73 - &Xdrv73, -#endif - -#ifdef XDRV_74 - &Xdrv74, -#endif - -#ifdef XDRV_75 - &Xdrv75, -#endif - -#ifdef XDRV_76 - &Xdrv76, -#endif - -#ifdef XDRV_77 - &Xdrv77, -#endif - -#ifdef XDRV_78 - &Xdrv78, -#endif - -#ifdef XDRV_79 - &Xdrv79, -#endif - -#ifdef XDRV_80 - &Xdrv80, -#endif - -#ifdef XDRV_81 - &Xdrv81, -#endif - -#ifdef XDRV_82 - &Xdrv82, -#endif - -#ifdef XDRV_83 - &Xdrv83, -#endif - -#ifdef XDRV_84 - &Xdrv84, -#endif - -#ifdef XDRV_85 - &Xdrv85, -#endif - -#ifdef XDRV_86 - &Xdrv86, -#endif - -#ifdef XDRV_87 - &Xdrv87, -#endif - -#ifdef XDRV_88 - &Xdrv88, -#endif - -#ifdef XDRV_89 - &Xdrv89, -#endif - -#ifdef XDRV_90 - &Xdrv90, -#endif - -#ifdef XDRV_91 - &Xdrv91, -#endif - -#ifdef XDRV_92 - &Xdrv92, -#endif - -#ifdef XDRV_93 - &Xdrv93, -#endif - -#ifdef XDRV_94 - &Xdrv94, -#endif - -#ifdef XDRV_95 - &Xdrv95, -#endif - -#ifdef XDRV_96 - &Xdrv96, -#endif - -#ifdef XDRV_97 - &Xdrv97, -#endif - -#ifdef XDRV_98 - &Xdrv98, -#endif - -#ifdef XDRV_99 - &Xdrv99 -#endif -}; - -const uint8_t xdrv_present = sizeof(xdrv_func_ptr) / sizeof(xdrv_func_ptr[0]); - - - - - -#ifdef XFUNC_PTR_IN_ROM -const uint8_t kXdrvList[] PROGMEM = { -#else -const uint8_t kXdrvList[] = { -#endif - -#ifdef XDRV_01 - XDRV_01, -#endif - -#ifdef XDRV_02 - XDRV_02, -#endif - -#ifdef XDRV_03 - XDRV_03, -#endif - -#ifdef XDRV_04 - XDRV_04, -#endif - -#ifdef XDRV_05 - XDRV_05, -#endif - -#ifdef XDRV_06 - XDRV_06, -#endif - -#ifdef XDRV_07 - XDRV_07, -#endif - -#ifdef XDRV_08 - XDRV_08, -#endif - -#ifdef XDRV_09 - XDRV_09, -#endif - -#ifdef XDRV_10 - XDRV_10, -#endif - -#ifdef XDRV_11 - XDRV_11, -#endif - -#ifdef XDRV_12 - XDRV_12, -#endif - -#ifdef XDRV_13 - XDRV_13, -#endif - -#ifdef XDRV_14 - XDRV_14, -#endif - -#ifdef XDRV_15 - XDRV_15, -#endif - -#ifdef XDRV_16 - XDRV_16, -#endif - -#ifdef XDRV_17 - XDRV_17, -#endif - -#ifdef XDRV_18 - XDRV_18, -#endif - -#ifdef XDRV_19 - XDRV_19, -#endif - -#ifdef XDRV_20 - XDRV_20, -#endif - -#ifdef XDRV_21 - XDRV_21, -#endif - -#ifdef XDRV_22 - XDRV_22, -#endif - -#ifdef XDRV_23 - XDRV_23, -#endif - -#ifdef XDRV_24 - XDRV_24, -#endif - -#ifdef XDRV_25 - XDRV_25, -#endif - -#ifdef XDRV_26 - XDRV_26, -#endif - -#ifdef XDRV_27 - XDRV_27, -#endif - -#ifdef XDRV_28 - XDRV_28, -#endif - -#ifdef XDRV_29 - XDRV_29, -#endif - -#ifdef XDRV_30 - XDRV_30, -#endif - -#ifdef XDRV_31 - XDRV_31, -#endif - -#ifdef XDRV_32 - XDRV_32, -#endif - -#ifdef XDRV_33 - XDRV_33, -#endif - -#ifdef XDRV_34 - XDRV_34, -#endif - -#ifdef XDRV_35 - XDRV_35, -#endif - -#ifdef XDRV_36 - XDRV_36, -#endif - -#ifdef XDRV_37 - XDRV_37, -#endif - -#ifdef XDRV_38 - XDRV_38, -#endif - -#ifdef XDRV_39 - XDRV_39, -#endif - -#ifdef XDRV_40 - XDRV_40, -#endif - -#ifdef XDRV_41 - XDRV_41, -#endif - -#ifdef XDRV_42 - XDRV_42, -#endif - -#ifdef XDRV_43 - XDRV_43, -#endif - -#ifdef XDRV_44 - XDRV_44, -#endif - -#ifdef XDRV_45 - XDRV_45, -#endif - -#ifdef XDRV_46 - XDRV_46, -#endif - -#ifdef XDRV_47 - XDRV_47, -#endif - -#ifdef XDRV_48 - XDRV_48, -#endif - -#ifdef XDRV_49 - XDRV_49, -#endif - -#ifdef XDRV_50 - XDRV_50, -#endif - -#ifdef XDRV_51 - XDRV_51, -#endif - -#ifdef XDRV_52 - XDRV_52, -#endif - -#ifdef XDRV_53 - XDRV_53, -#endif - -#ifdef XDRV_54 - XDRV_54, -#endif - -#ifdef XDRV_55 - XDRV_55, -#endif - -#ifdef XDRV_56 - XDRV_56, -#endif - -#ifdef XDRV_57 - XDRV_57, -#endif - -#ifdef XDRV_58 - XDRV_58, -#endif - -#ifdef XDRV_59 - XDRV_59, -#endif - -#ifdef XDRV_60 - XDRV_60, -#endif - -#ifdef XDRV_61 - XDRV_61, -#endif - -#ifdef XDRV_62 - XDRV_62, -#endif - -#ifdef XDRV_63 - XDRV_63, -#endif - -#ifdef XDRV_64 - XDRV_64, -#endif - -#ifdef XDRV_65 - XDRV_65, -#endif - -#ifdef XDRV_66 - XDRV_66, -#endif - -#ifdef XDRV_67 - XDRV_67, -#endif - -#ifdef XDRV_68 - XDRV_68, -#endif - -#ifdef XDRV_69 - XDRV_69, -#endif - -#ifdef XDRV_70 - XDRV_70, -#endif - -#ifdef XDRV_71 - XDRV_71, -#endif - -#ifdef XDRV_72 - XDRV_72, -#endif - -#ifdef XDRV_73 - XDRV_73, -#endif - -#ifdef XDRV_74 - XDRV_74, -#endif - -#ifdef XDRV_75 - XDRV_75, -#endif - -#ifdef XDRV_76 - XDRV_76, -#endif - -#ifdef XDRV_77 - XDRV_77, -#endif - -#ifdef XDRV_78 - XDRV_78, -#endif - -#ifdef XDRV_79 - XDRV_79, -#endif - -#ifdef XDRV_80 - XDRV_80, -#endif - -#ifdef XDRV_81 - XDRV_81, -#endif - -#ifdef XDRV_82 - XDRV_82, -#endif - -#ifdef XDRV_83 - XDRV_83, -#endif - -#ifdef XDRV_84 - XDRV_84, -#endif - -#ifdef XDRV_85 - XDRV_85, -#endif - -#ifdef XDRV_86 - XDRV_86, -#endif - -#ifdef XDRV_87 - XDRV_87, -#endif - -#ifdef XDRV_88 - XDRV_88, -#endif - -#ifdef XDRV_89 - XDRV_89, -#endif - -#ifdef XDRV_90 - XDRV_90, -#endif - -#ifdef XDRV_91 - XDRV_91, -#endif - -#ifdef XDRV_92 - XDRV_92, -#endif - -#ifdef XDRV_93 - XDRV_93, -#endif - -#ifdef XDRV_94 - XDRV_94, -#endif - -#ifdef XDRV_95 - XDRV_95, -#endif - -#ifdef XDRV_96 - XDRV_96, -#endif - -#ifdef XDRV_97 - XDRV_97, -#endif - -#ifdef XDRV_98 - XDRV_98, -#endif - -#ifdef XDRV_99 - XDRV_99 -#endif -}; - - - -void XsnsDriverState(void) -{ - ResponseAppend_P(PSTR(",\"Drivers\":\"")); - for (uint32_t i = 0; i < sizeof(kXdrvList); i++) { -#ifdef XFUNC_PTR_IN_ROM - uint32_t driverid = pgm_read_byte(kXdrvList + i); -#else - uint32_t driverid = kXdrvList[i]; -#endif - ResponseAppend_P(PSTR("%s%d"), (i) ? "," : "", driverid); - } - ResponseAppend_P(PSTR("\"")); -} - - - -bool XdrvRulesProcess(void) -{ - return XdrvCallDriver(10, FUNC_RULES_PROCESS); -} - -#ifdef USE_DEBUG_DRIVER -void ShowFreeMem(const char *where) -{ - char stemp[30]; - snprintf_P(stemp, sizeof(stemp), where); - XdrvMailbox.data = stemp; - XdrvCall(FUNC_FREE_MEM); -} -#endif - - - - - -bool XdrvCallDriver(uint32_t driver, uint8_t Function) -{ - for (uint32_t x = 0; x < xdrv_present; x++) { -#ifdef XFUNC_PTR_IN_ROM - uint32_t listed = pgm_read_byte(kXdrvList + x); -#else - uint32_t listed = kXdrvList[x]; -#endif - if (driver == listed) { - return xdrv_func_ptr[x](Function); - } - } - return false; -} - - - - - -bool XdrvCall(uint8_t Function) -{ - bool result = false; - - DEBUG_TRACE_LOG(PSTR("DRV: %d"), Function); - - for (uint32_t x = 0; x < xdrv_present; x++) { - result = xdrv_func_ptr[x](Function); - - if (result && ((FUNC_COMMAND == Function) || - (FUNC_COMMAND_DRIVER == Function) || - (FUNC_MQTT_DATA == Function) || - (FUNC_RULES_PROCESS == Function) || - (FUNC_BUTTON_PRESSED == Function) || - (FUNC_SERIAL == Function) || - (FUNC_MODULE_INIT == Function) || - (FUNC_SET_CHANNELS == Function) || - (FUNC_PIN_STATE == Function) || - (FUNC_SET_DEVICE_POWER == Function) - )) { - break; - } - } - - return result; -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_01_lcd.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_01_lcd.ino" -#ifdef USE_I2C -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_LCD - -#define XDSP_01 1 -#define XI2C_03 3 - -#define LCD_ADDRESS1 0x27 -#define LCD_ADDRESS2 0x3F - -#include -#include - -LiquidCrystal_I2C *lcd; - - - -void LcdInitMode(void) -{ - lcd->init(); - lcd->clear(); -} - -void LcdInit(uint8_t mode) -{ - switch(mode) { - case DISPLAY_INIT_MODE: - LcdInitMode(); -#ifdef USE_DISPLAY_MODES1TO5 - DisplayClearScreenBuffer(); -#endif - break; - case DISPLAY_INIT_PARTIAL: - case DISPLAY_INIT_FULL: - break; - } -} - -void LcdInitDriver(void) -{ - if (!Settings.display_model) { - if (I2cSetDevice(LCD_ADDRESS1)) { - Settings.display_address[0] = LCD_ADDRESS1; - Settings.display_model = XDSP_01; - } - else if (I2cSetDevice(LCD_ADDRESS2)) { - Settings.display_address[0] = LCD_ADDRESS2; - Settings.display_model = XDSP_01; - } - } - - if (XDSP_01 == Settings.display_model) { - I2cSetActiveFound(Settings.display_address[0], "LCD"); - - Settings.display_width = Settings.display_cols[0]; - Settings.display_height = Settings.display_rows; - lcd = new LiquidCrystal_I2C(Settings.display_address[0], Settings.display_cols[0], Settings.display_rows); - -#ifdef USE_DISPLAY_MODES1TO5 - DisplayAllocScreenBuffer(); -#endif - - LcdInitMode(); - } -} - -void LcdDrawStringAt(void) -{ - if (dsp_flag) { - dsp_x--; - dsp_y--; - } - lcd->setCursor(dsp_x, dsp_y); - lcd->print(dsp_str); -} - -void LcdDisplayOnOff(uint8_t on) -{ - if (on) { - lcd->backlight(); - } else { - lcd->noBacklight(); - } -} - - - -#ifdef USE_DISPLAY_MODES1TO5 - -void LcdCenter(uint8_t row, char* txt) -{ - char line[Settings.display_cols[0] +2]; - - int len = strlen(txt); - int offset = 0; - if (len >= Settings.display_cols[0]) { - len = Settings.display_cols[0]; - } else { - offset = (Settings.display_cols[0] - len) / 2; - } - memset(line, 0x20, Settings.display_cols[0]); - line[Settings.display_cols[0]] = 0; - for (uint32_t i = 0; i < len; i++) { - line[offset +i] = txt[i]; - } - lcd->setCursor(0, row); - lcd->print(line); -} - -bool LcdPrintLog(void) -{ - bool result = false; - - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - - char* txt = DisplayLogBuffer('\337'); - if (txt != nullptr) { - uint8_t last_row = Settings.display_rows -1; - - for (uint32_t i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - lcd->setCursor(0, i); - lcd->print(disp_screen_buffer[i +1]); - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - - lcd->setCursor(0, last_row); - lcd->print(disp_screen_buffer[last_row]); - - result = true; - } - } - return result; -} - -void LcdTime(void) -{ - char line[Settings.display_cols[0] +1]; - - snprintf_P(line, sizeof(line), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - LcdCenter(0, line); - snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); - LcdCenter(1, line); -} - -void LcdRefresh(void) -{ - if (Settings.display_mode) { - switch (Settings.display_mode) { - case 1: - LcdTime(); - break; - case 2: - case 4: - LcdPrintLog(); - break; - case 3: - case 5: { - if (!LcdPrintLog()) { LcdTime(); } - break; - } - } - } -} - -#endif - - - - - -bool Xdsp01(uint8_t function) -{ - if (!I2cEnabled(XI2C_03)) { return false; } - - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - LcdInitDriver(); - } - else if (XDSP_01 == Settings.display_model) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_INIT: - LcdInit(dsp_init); - break; - case FUNC_DISPLAY_POWER: - LcdDisplayOnOff(disp_power); - break; - case FUNC_DISPLAY_CLEAR: - lcd->clear(); - break; -# 238 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_01_lcd.ino" - case FUNC_DISPLAY_DRAW_STRING: - LcdDrawStringAt(); - break; - case FUNC_DISPLAY_ONOFF: - LcdDisplayOnOff(dsp_on); - break; - - -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - LcdRefresh(); - break; -#endif - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_02_ssd1306.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_02_ssd1306.ino" -#ifdef USE_I2C -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_SSD1306 - -#define XDSP_02 2 -#define XI2C_04 4 - -#define OLED_RESET 4 - -#define SPRINT(A) char str[32];sprintf(str,"val: %d ",A);Serial.println((char*)str); - -#define OLED_ADDRESS1 0x3C -#define OLED_ADDRESS2 0x3D - -#define OLED_BUFFER_COLS 40 -#define OLED_BUFFER_ROWS 16 - -#define OLED_FONT_WIDTH 6 -#define OLED_FONT_HEIGTH 8 - -#include -#include -#include - -Adafruit_SSD1306 *oled1306; - -extern uint8_t *buffer; - - - -void SSD1306InitDriver(void) -{ - if (!Settings.display_model) { - if (I2cSetDevice(OLED_ADDRESS1)) { - Settings.display_address[0] = OLED_ADDRESS1; - Settings.display_model = XDSP_02; - } - else if (I2cSetDevice(OLED_ADDRESS2)) { - Settings.display_address[0] = OLED_ADDRESS2; - Settings.display_model = XDSP_02; - } - } - - if (XDSP_02 == Settings.display_model) { - I2cSetActiveFound(Settings.display_address[0], "SSD1306"); - - if ((Settings.display_width != 64) && (Settings.display_width != 96) && (Settings.display_width != 128)) { - Settings.display_width = 128; - } - if ((Settings.display_height != 16) && (Settings.display_height != 32) && (Settings.display_height != 48) && (Settings.display_height != 64)) { - Settings.display_height = 64; - } - - uint8_t reset_pin = -1; - if (pin[GPIO_OLED_RESET] < 99) { - reset_pin = pin[GPIO_OLED_RESET]; - } - - - if (buffer) { free(buffer); } - buffer = (unsigned char*)calloc((Settings.display_width * Settings.display_height) / 8,1); - if (!buffer) { return; } - - - - oled1306 = new Adafruit_SSD1306(Settings.display_width, Settings.display_height, &Wire, reset_pin); - oled1306->begin(SSD1306_SWITCHCAPVCC, Settings.display_address[0], reset_pin >= 0); - renderer = oled1306; - renderer->DisplayInit(DISPLAY_INIT_MODE, Settings.display_size, Settings.display_rotate, Settings.display_font); - renderer->setTextColor(1,0); - -#ifdef SHOW_SPLASH - renderer->setTextFont(0); - renderer->setTextSize(2); - renderer->setCursor(20,20); - renderer->println(F("SSD1306")); - renderer->Updateframe(); - renderer->DisplayOnff(1); -#endif - - } -} - - -#ifdef USE_DISPLAY_MODES1TO5 - -void Ssd1306PrintLog(void) -{ - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - - char* txt = DisplayLogBuffer('\370'); - if (txt != NULL) { - uint8_t last_row = Settings.display_rows -1; - - renderer->clearDisplay(); - renderer->setTextSize(Settings.display_size); - renderer->setCursor(0,0); - for (byte i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - renderer->println(disp_screen_buffer[i]); - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - - renderer->println(disp_screen_buffer[last_row]); - renderer->Updateframe(); - } - } -} - -void Ssd1306Time(void) -{ - char line[12]; - - renderer->clearDisplay(); - renderer->setTextSize(Settings.display_size); - renderer->setTextFont(Settings.display_font); - renderer->setCursor(0, 0); - snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - renderer->println(line); - snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); - renderer->println(line); - renderer->Updateframe(); -} - -void Ssd1306Refresh(void) -{ - if (!renderer) return; - - if (Settings.display_mode) { - switch (Settings.display_mode) { - case 1: - Ssd1306Time(); - break; - case 2: - case 3: - case 4: - case 5: - Ssd1306PrintLog(); - break; - } - } -} - -#endif - - - - - -bool Xdsp02(byte function) -{ - if (!I2cEnabled(XI2C_04)) { return false; } - - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - SSD1306InitDriver(); - } - else if (XDSP_02 == Settings.display_model) { - switch (function) { -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - Ssd1306Refresh(); - break; -#endif - case FUNC_DISPLAY_MODEL: - result = true; - break; - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_03_matrix.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_03_matrix.ino" -#ifdef USE_I2C -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_MATRIX - -#define XDSP_03 3 -#define XI2C_05 5 - -#define MTX_MAX_SCREEN_BUFFER 80 - -#include -#include -#include - -Adafruit_8x8matrix *matrix[8]; -uint8_t mtx_matrices = 0; -uint8_t mtx_state = 0; -uint8_t mtx_counter = 0; -int16_t mtx_x = 0; -int16_t mtx_y = 0; - - -char *mtx_buffer = nullptr; - -uint8_t mtx_mode = 0; -uint8_t mtx_loop = 0; -uint8_t mtx_done = 0; - - - -void MatrixWrite(void) -{ - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->writeDisplay(); - } -} - -void MatrixClear(void) -{ - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->clear(); - } - MatrixWrite(); -} - -void MatrixFixed(char* txt) -{ - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->clear(); - matrix[i]->setCursor(-i *8, 0); - matrix[i]->print(txt); - matrix[i]->setBrightness(Settings.display_dimmer); - } - MatrixWrite(); -} - -void MatrixCenter(char* txt) -{ - int offset; - - int len = strlen(txt); - offset = (len < 8) ? offset = ((mtx_matrices *8) - (len *6)) / 2 : 0; - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->clear(); - matrix[i]->setCursor(-(i *8)+offset, 0); - matrix[i]->print(txt); - matrix[i]->setBrightness(Settings.display_dimmer); - } - MatrixWrite(); -} - -void MatrixScrollLeft(char* txt, int loop) -{ - switch (mtx_state) { - case 1: - mtx_state = 2; - - mtx_x = 8 * mtx_matrices; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), txt); - - disp_refresh = Settings.display_refresh; - case 2: - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->clear(); - matrix[i]->setCursor(mtx_x - i *8, 0); - matrix[i]->print(txt); - matrix[i]->setBrightness(Settings.display_dimmer); - } - MatrixWrite(); - - mtx_x--; - int16_t len = strlen(txt); - if (mtx_x < -(len *6)) { mtx_state = loop; } - } - break; - } -} - -void MatrixScrollUp(char* txt, int loop) -{ - int wordcounter = 0; - char tmpbuf[200]; - char *words[100]; - - - - char separators[] = " /"; - - switch (mtx_state) { - case 1: - mtx_state = 2; - - mtx_y = 8; - mtx_counter = 0; - disp_refresh = Settings.display_refresh; - case 2: - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - strlcpy(tmpbuf, txt, sizeof(tmpbuf)); - char *p = strtok(tmpbuf, separators); - while (p != nullptr && wordcounter < 40) { - words[wordcounter++] = p; - p = strtok(nullptr, separators); - } - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->clear(); - for (uint32_t j = 0; j < wordcounter; j++) { - matrix[i]->setCursor(-i *8, mtx_y + (j *8)); - matrix[i]->println(words[j]); - } - matrix[i]->setBrightness(Settings.display_dimmer); - } - MatrixWrite(); - if (((mtx_y %8) == 0) && mtx_counter) { - mtx_counter--; - } else { - mtx_y--; - mtx_counter = STATES * 1; - } - if (mtx_y < -(wordcounter *8)) { mtx_state = loop; } - } - break; - } -} - - - -void MatrixInitMode(void) -{ - for (uint32_t i = 0; i < mtx_matrices; i++) { - matrix[i]->setRotation(Settings.display_rotate); - matrix[i]->setBrightness(Settings.display_dimmer); - matrix[i]->blinkRate(0); - matrix[i]->setTextWrap(false); - - - matrix[i]->cp437(true); - } - MatrixClear(); -} - -void MatrixInit(uint8_t mode) -{ - switch(mode) { - case DISPLAY_INIT_MODE: - MatrixInitMode(); - break; - case DISPLAY_INIT_PARTIAL: - case DISPLAY_INIT_FULL: - break; - } -} - -void MatrixInitDriver(void) -{ - mtx_buffer = (char*)(malloc(MTX_MAX_SCREEN_BUFFER)); - if (mtx_buffer != nullptr) { - if (!Settings.display_model) { - if (I2cSetDevice(Settings.display_address[1])) { - Settings.display_model = XDSP_03; - } - } - - if (XDSP_03 == Settings.display_model) { - mtx_state = 1; - for (mtx_matrices = 0; mtx_matrices < 8; mtx_matrices++) { - if (Settings.display_address[mtx_matrices]) { - I2cSetActiveFound(Settings.display_address[mtx_matrices], "8x8Matrix"); - matrix[mtx_matrices] = new Adafruit_8x8matrix(); - matrix[mtx_matrices]->begin(Settings.display_address[mtx_matrices]); - } else { - break; - } - } - - Settings.display_width = mtx_matrices * 8; - Settings.display_height = 8; - - MatrixInitMode(); - } - } -} - -void MatrixOnOff(void) -{ - if (!disp_power) { MatrixClear(); } -} - -void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag) -{ - strlcpy(mtx_buffer, str, MTX_MAX_SCREEN_BUFFER); - mtx_mode = x &1; - mtx_loop = y &1; - if (!mtx_state) { mtx_state = 1; } -} - - - -#ifdef USE_DISPLAY_MODES1TO5 - -void MatrixPrintLog(uint8_t direction) -{ - char* txt = (!mtx_done) ? DisplayLogBuffer('\370') : mtx_buffer; - if (txt != nullptr) { - if (!mtx_state) { mtx_state = 1; } - - if (!mtx_done) { - - uint8_t space = 0; - uint8_t max_cols = (disp_log_buffer_cols < MTX_MAX_SCREEN_BUFFER) ? disp_log_buffer_cols : MTX_MAX_SCREEN_BUFFER; - mtx_buffer[0] = '\0'; - uint8_t i = 0; - while ((txt[i] != '\0') && (i < max_cols)) { - if (txt[i] == ' ') { - space++; - } else { - space = 0; - } - if (space < 2) { - strncat(mtx_buffer, (const char*)txt +i, (strlen(mtx_buffer) < MTX_MAX_SCREEN_BUFFER -1) ? 1 : 0); - } - i++; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "[%s]"), mtx_buffer); - - mtx_done = 1; - } - - if (direction) { - MatrixScrollUp(mtx_buffer, 0); - } else { - MatrixScrollLeft(mtx_buffer, 0); - } - if (!mtx_state) { mtx_done = 0; } - } else { - char disp_time[9]; - - snprintf_P(disp_time, sizeof(disp_time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - MatrixFixed(disp_time); - } -} - -#endif - -void MatrixRefresh(void) -{ - if (disp_power) { - switch (Settings.display_mode) { - case 0: { - switch (mtx_mode) { - case 0: - MatrixScrollLeft(mtx_buffer, mtx_loop); - break; - case 1: - MatrixScrollUp(mtx_buffer, mtx_loop); - break; - } - break; - } -#ifdef USE_DISPLAY_MODES1TO5 - case 2: { - char disp_date[9]; - snprintf_P(disp_date, sizeof(disp_date), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000); - MatrixFixed(disp_date); - break; - } - case 3: { - char disp_day[10]; - snprintf_P(disp_day, sizeof(disp_day), PSTR("%d %s"), RtcTime.day_of_month, RtcTime.name_of_month); - MatrixCenter(disp_day); - break; - } - case 4: - MatrixPrintLog(0); - break; - case 1: - case 5: - MatrixPrintLog(1); - break; -#endif - } - } -} - - - - - -bool Xdsp03(uint8_t function) -{ - if (!I2cEnabled(XI2C_05)) { return false; } - - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - MatrixInitDriver(); - } - else if (XDSP_03 == Settings.display_model) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_INIT: - MatrixInit(dsp_init); - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: - MatrixRefresh(); - break; - case FUNC_DISPLAY_POWER: - MatrixOnOff(); - break; - case FUNC_DISPLAY_DRAW_STRING: - MatrixDrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag); - break; - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_04_ili9341.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_04_ili9341.ino" -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_ILI9341 - -#define XDSP_04 4 - -#define TFT_TOP 16 -#define TFT_BOTTOM 16 -#define TFT_FONT_WIDTH 6 -#define TFT_FONT_HEIGTH 8 - -#include -#include -#include - -Adafruit_ILI9341 *tft; - -uint16_t tft_scroll; - - - -void Ili9341InitMode(void) -{ - tft->setRotation(Settings.display_rotate); - tft->invertDisplay(0); - tft->fillScreen(ILI9341_BLACK); - tft->setTextWrap(false); - tft->cp437(true); - if (!Settings.display_mode) { - tft->setCursor(0, 0); - tft->setTextColor(ILI9341_WHITE, ILI9341_BLACK); - tft->setTextSize(1); - } else { - tft->setScrollMargins(TFT_TOP, TFT_BOTTOM); - tft->setCursor(0, 0); - tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK); - tft->setTextSize(2); - - - tft_scroll = TFT_TOP; - } -} - -void Ili9341Init(uint8_t mode) -{ - switch(mode) { - case DISPLAY_INIT_MODE: - Ili9341InitMode(); -#ifdef USE_DISPLAY_MODES1TO5 - if (Settings.display_rotate) { - DisplayClearScreenBuffer(); - } -#endif - break; - case DISPLAY_INIT_PARTIAL: - case DISPLAY_INIT_FULL: - break; - } -} - -void Ili9341InitDriver(void) -{ - if (!Settings.display_model) { - Settings.display_model = XDSP_04; - } - - if (XDSP_04 == Settings.display_model) { - if (Settings.display_width != ILI9341_TFTWIDTH) { - Settings.display_width = ILI9341_TFTWIDTH; - } - if (Settings.display_height != ILI9341_TFTHEIGHT) { - Settings.display_height = ILI9341_TFTHEIGHT; - } - tft = new Adafruit_ILI9341(pin[GPIO_SPI_CS], pin[GPIO_SPI_DC]); - tft->begin(); - -#ifdef USE_DISPLAY_MODES1TO5 - if (Settings.display_rotate) { - DisplayAllocScreenBuffer(); - } -#endif - - Ili9341InitMode(); - } -} - -void Ili9341Clear(void) -{ - tft->fillScreen(ILI9341_BLACK); - tft->setCursor(0, 0); -} - -void Ili9341DrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag) -{ - uint16_t active_color = ILI9341_WHITE; - - tft->setTextSize(Settings.display_size); - if (!flag) { - tft->setCursor(x, y); - } else { - tft->setCursor((x-1) * TFT_FONT_WIDTH * Settings.display_size, (y-1) * TFT_FONT_HEIGTH * Settings.display_size); - } - if (color) { active_color = color; } - tft->setTextColor(active_color, ILI9341_BLACK); - tft->println(str); -} - -void Ili9341DisplayOnOff(uint8_t on) -{ - - - if (pin[GPIO_BACKLIGHT] < 99) { - pinMode(pin[GPIO_BACKLIGHT], OUTPUT); - digitalWrite(pin[GPIO_BACKLIGHT], on); - } -} - -void Ili9341OnOff(void) -{ - Ili9341DisplayOnOff(disp_power); -} - - - -#ifdef USE_DISPLAY_MODES1TO5 - -void Ili9341PrintLog(void) -{ - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - if (Settings.display_rotate) { - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - } - - char* txt = DisplayLogBuffer('\370'); - if (txt != nullptr) { - uint8_t size = Settings.display_size; - uint16_t theight = size * TFT_FONT_HEIGTH; - - tft->setTextSize(size); - tft->setTextColor(ILI9341_CYAN, ILI9341_BLACK); - if (!Settings.display_rotate) { - tft->setCursor(0, tft_scroll); - tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK); - tft->print(txt); - tft_scroll += theight; - if (tft_scroll >= (tft->height() - TFT_BOTTOM)) { - tft_scroll = TFT_TOP; - } - tft->scrollTo(tft_scroll); - } else { - uint8_t last_row = Settings.display_rows -1; - - tft_scroll = theight; - tft->setCursor(0, tft_scroll); - for (uint32_t i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - - tft->print(disp_screen_buffer[i]); - tft_scroll += theight; - tft->setCursor(0, tft_scroll); - delay(1); - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - tft->print(disp_screen_buffer[last_row]); - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "[%s]"), txt); - } - } -} - -void Ili9341Refresh(void) -{ - if (Settings.display_mode) { - char tftdt[Settings.display_cols[0] +1]; - char date4[11]; - char space[Settings.display_cols[0] - 17]; - char time[9]; - - tft->setTextSize(2); - tft->setTextColor(ILI9341_YELLOW, ILI9341_RED); - tft->setCursor(0, 0); - - snprintf_P(date4, sizeof(date4), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); - memset(space, 0x20, sizeof(space)); - space[sizeof(space) -1] = '\0'; - snprintf_P(time, sizeof(time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - snprintf_P(tftdt, sizeof(tftdt), PSTR("%s%s%s"), date4, space, time); - - tft->print(tftdt); - - switch (Settings.display_mode) { - case 1: - case 2: - case 3: - case 4: - case 5: - Ili9341PrintLog(); - break; - } - } -} - -#endif - - - - - -bool Xdsp04(uint8_t function) -{ - bool result = false; - - if (spi_flg) { - if (FUNC_DISPLAY_INIT_DRIVER == function) { - Ili9341InitDriver(); - } - else if (XDSP_04 == Settings.display_model) { - - if (!dsp_color) { dsp_color = ILI9341_WHITE; } - - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_INIT: - Ili9341Init(dsp_init); - break; - case FUNC_DISPLAY_POWER: - Ili9341OnOff(); - break; - case FUNC_DISPLAY_CLEAR: - Ili9341Clear(); - break; - case FUNC_DISPLAY_DRAW_HLINE: - tft->writeFastHLine(dsp_x, dsp_y, dsp_len, dsp_color); - break; - case FUNC_DISPLAY_DRAW_VLINE: - tft->writeFastVLine(dsp_x, dsp_y, dsp_len, dsp_color); - break; - case FUNC_DISPLAY_DRAW_LINE: - tft->writeLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color); - break; - case FUNC_DISPLAY_DRAW_CIRCLE: - tft->drawCircle(dsp_x, dsp_y, dsp_rad, dsp_color); - break; - case FUNC_DISPLAY_FILL_CIRCLE: - tft->fillCircle(dsp_x, dsp_y, dsp_rad, dsp_color); - break; - case FUNC_DISPLAY_DRAW_RECTANGLE: - tft->drawRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color); - break; - case FUNC_DISPLAY_FILL_RECTANGLE: - tft->fillRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color); - break; - - - - case FUNC_DISPLAY_TEXT_SIZE: - tft->setTextSize(Settings.display_size); - break; - case FUNC_DISPLAY_FONT_SIZE: - - break; - case FUNC_DISPLAY_DRAW_STRING: - Ili9341DrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag); - break; - case FUNC_DISPLAY_ONOFF: - Ili9341DisplayOnOff(dsp_on); - break; - case FUNC_DISPLAY_ROTATION: - tft->setRotation(Settings.display_rotate); - break; -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - Ili9341Refresh(); - break; -#endif - } - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_05_epaper_29.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_05_epaper_29.ino" -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_EPAPER_29 - -#define XDSP_05 5 - -#define EPD_TOP 12 -#define EPD_FONT_HEIGTH 12 - -#define COLORED 1 -#define UNCOLORED 0 - - - -#define USE_TINY_FONT - -#include -#include - - -extern uint8_t *buffer; -uint16_t epd_scroll; - -Epd *epd; - - - -void EpdInitDriver29() -{ - if (!Settings.display_model) { - Settings.display_model = XDSP_05; - } - - if (XDSP_05 == Settings.display_model) { - if (Settings.display_width != EPD_WIDTH) { - Settings.display_width = EPD_WIDTH; - } - if (Settings.display_height != EPD_HEIGHT) { - Settings.display_height = EPD_HEIGHT; - } - - - if (buffer) free(buffer); - buffer=(unsigned char*)calloc((EPD_WIDTH * EPD_HEIGHT) / 8,1); - if (!buffer) return; - - - epd = new Epd(EPD_WIDTH,EPD_HEIGHT); - - - if ((pin[GPIO_SPI_CS] < 99) && (pin[GPIO_SPI_CLK] < 99) && (pin[GPIO_SPI_MOSI] < 99)) { - epd->Begin(pin[GPIO_SPI_CS],pin[GPIO_SPI_MOSI],pin[GPIO_SPI_CLK]); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EPD: HardSPI CS %d, CLK %d, MOSI %d"),pin[GPIO_SPI_CS], pin[GPIO_SPI_CLK], pin[GPIO_SPI_MOSI]); - } - else if ((pin[GPIO_SSPI_CS] < 99) && (pin[GPIO_SSPI_SCLK] < 99) && (pin[GPIO_SSPI_MOSI] < 99)) { - epd->Begin(pin[GPIO_SSPI_CS],pin[GPIO_SSPI_MOSI],pin[GPIO_SSPI_SCLK]); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("EPD: SoftSPI CS %d, CLK %d, MOSI %d"),pin[GPIO_SSPI_CS], pin[GPIO_SSPI_SCLK], pin[GPIO_SSPI_MOSI]); - } else { - free(buffer); - return; - } - - renderer = epd; - epd->Init(DISPLAY_INIT_FULL); - epd->Init(DISPLAY_INIT_PARTIAL); - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); - - renderer->setTextColor(1,0); - -#ifdef SHOW_SPLASH - - renderer->setTextFont(1); - renderer->DrawStringAt(50, 50, "Waveshare E-Paper Display!", COLORED,0); - renderer->Updateframe(); - delay(1000); - renderer->fillScreen(0); -#endif - - } -} - - - - - - - -#ifdef USE_DISPLAY_MODES1TO5 -#define EPD_FONT_HEIGTH 12 -void EpdPrintLog29(void) -{ - - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - - - char* txt = DisplayLogBuffer('\040'); - if (txt != nullptr) { - uint8_t size = Settings.display_size; - uint16_t theight = size * EPD_FONT_HEIGTH; - - renderer->setTextFont(size); - uint8_t last_row = Settings.display_rows -1; - - - epd_scroll = 0; - for (uint32_t i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - renderer->DrawStringAt(0, epd_scroll, disp_screen_buffer[i], COLORED, 0); - epd_scroll += theight; - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - renderer->DrawStringAt(0, epd_scroll, disp_screen_buffer[last_row], COLORED, 0); - - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "[%s]"), txt); - } - } -} - -void EpdRefresh29(void) -{ - if (Settings.display_mode) { - - if (!renderer) return; -# 165 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_05_epaper_29.ino" - switch (Settings.display_mode) { - case 1: - case 2: - case 3: - case 4: - case 5: - EpdPrintLog29(); - renderer->Updateframe(); - break; - } - - - } -} - -#endif - - - - - -bool Xdsp05(uint8_t function) -{ - bool result = false; - if (FUNC_DISPLAY_INIT_DRIVER == function) { - EpdInitDriver29(); - } - else if (XDSP_05 == Settings.display_model) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - EpdRefresh29(); - break; -#endif - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_06_epaper_42.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_06_epaper_42.ino" -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_EPAPER_42 - -#define XDSP_06 6 - -#define COLORED42 1 -#define UNCOLORED42 0 - - - -#define USE_TINY_FONT - -#include -#include - -extern uint8_t *buffer; - -Epd42 *epd42; - - - - -void EpdInitDriver42() -{ - if (!Settings.display_model) { - Settings.display_model = XDSP_06; - } - - if (XDSP_06 == Settings.display_model) { - - if (Settings.display_width != EPD_WIDTH42) { - Settings.display_width = EPD_WIDTH42; - } - if (Settings.display_height != EPD_HEIGHT42) { - Settings.display_height = EPD_HEIGHT42; - } - - - if (buffer) free(buffer); - buffer=(unsigned char*)calloc((EPD_WIDTH42 * EPD_HEIGHT42) / 8,1); - if (!buffer) return; - - - epd42 = new Epd42(EPD_WIDTH42,EPD_HEIGHT42); - - #ifdef USE_SPI - if ((pin[GPIO_SSPI_CS]<99) && (pin[GPIO_SSPI_MOSI]<99) && (pin[GPIO_SSPI_SCLK]<99)) { - epd42->Begin(pin[GPIO_SSPI_CS],pin[GPIO_SSPI_MOSI],pin[GPIO_SSPI_SCLK]); - } else { - free(buffer); - return; - } - #else - if ((pin[GPIO_SPI_CS]<99) && (pin[GPIO_SPI_MOSI]<99) && (pin[GPIO_SPI_CLK]<99)) { - epd42->Begin(pin[GPIO_SPI_CS],pin[GPIO_SPI_MOSI],pin[GPIO_SPI_CLK]); - } else { - free(buffer); - return; - } - #endif - - renderer = epd42; - - epd42->Init(); - - renderer->fillScreen(0); - - - epd42->Init(DISPLAY_INIT_FULL); - - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); - - epd42->ClearFrame(); - renderer->Updateframe(); - delay(3000); - renderer->setTextColor(1,0); - -#ifdef SHOW_SPLASH - - renderer->setTextFont(2); - renderer->DrawStringAt(50, 140, "Waveshare E-Paper!", COLORED42,0); - renderer->Updateframe(); - delay(350); - renderer->fillScreen(0); -#endif - - } -} - - - - - - - -#ifdef USE_DISPLAY_MODES1TO5 - -void EpdRefresh42() -{ - if (Settings.display_mode) { - - } -} - -#endif - - - - - - -bool Xdsp06(uint8_t function) -{ - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - EpdInitDriver42(); - } - else if (XDSP_06 == Settings.display_model) { - - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - EpdRefresh42(); - break; -#endif - } - } - return result; -} - - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_07_sh1106.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_07_sh1106.ino" -#ifdef USE_I2C -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_SH1106 - -#define OLED_RESET 4 - -#define SPRINT(A) char str[32];sprintf(str,"val: %d ",A);Serial.println((char*)str); - -extern uint8_t *buffer; - -#define XDSP_07 7 -#define XI2C_06 6 - -#define OLED_ADDRESS1 0x3C -#define OLED_ADDRESS2 0x3D - -#define OLED_BUFFER_COLS 40 -#define OLED_BUFFER_ROWS 16 - -#define OLED_FONT_WIDTH 6 -#define OLED_FONT_HEIGTH 8 - -#include -#include -#include - -Adafruit_SH1106 *oled1106; - - - - -void SH1106InitDriver() -{ - if (!Settings.display_model) { - if (I2cSetDevice(OLED_ADDRESS1)) { - Settings.display_address[0] = OLED_ADDRESS1; - Settings.display_model = XDSP_07; - } - else if (I2cSetDevice(OLED_ADDRESS2)) { - Settings.display_address[0] = OLED_ADDRESS2; - Settings.display_model = XDSP_07; - } - } - - if (XDSP_07 == Settings.display_model) { - I2cSetActiveFound(Settings.display_address[0], "SH1106"); - - if (Settings.display_width != SH1106_LCDWIDTH) { - Settings.display_width = SH1106_LCDWIDTH; - } - if (Settings.display_height != SH1106_LCDHEIGHT) { - Settings.display_height = SH1106_LCDHEIGHT; - } - - - if (buffer) free(buffer); - buffer=(unsigned char*)calloc((SH1106_LCDWIDTH * SH1106_LCDHEIGHT) / 8,1); - if (!buffer) return; - - - oled1106 = new Adafruit_SH1106(SH1106_LCDWIDTH,SH1106_LCDHEIGHT); - renderer=oled1106; - renderer->Begin(SH1106_SWITCHCAPVCC, Settings.display_address[0],0); - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); - renderer->setTextColor(1,0); - -#ifdef SHOW_SPLASH - renderer->setTextFont(0); - renderer->setTextSize(2); - renderer->setCursor(20,20); - renderer->println(F("SH1106")); - renderer->Updateframe(); - renderer->DisplayOnff(1); -#endif - } -} - - - -#ifdef USE_DISPLAY_MODES1TO5 - -void SH1106PrintLog(void) -{ - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - - char* txt = DisplayLogBuffer('\370'); - if (txt != NULL) { - uint8_t last_row = Settings.display_rows -1; - - renderer->clearDisplay(); - renderer->setTextSize(Settings.display_size); - renderer->setCursor(0,0); - for (byte i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - renderer->println(disp_screen_buffer[i]); - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - - renderer->println(disp_screen_buffer[last_row]); - renderer->Updateframe(); - } - } -} - -void SH1106Time(void) -{ - char line[12]; - - renderer->clearDisplay(); - renderer->setTextSize(Settings.display_size); - renderer->setTextFont(Settings.display_font); - renderer->setCursor(0, 0); - snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - renderer->println(line); - snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); - renderer->println(line); - renderer->Updateframe(); -} - -void SH1106Refresh(void) -{ - if (!renderer) return; - if (Settings.display_mode) { - switch (Settings.display_mode) { - case 1: - SH1106Time(); - break; - case 2: - case 3: - case 4: - case 5: - SH1106PrintLog(); - break; - } - } -} - -#endif - - - - - -bool Xdsp07(uint8_t function) -{ - if (!I2cEnabled(XI2C_06)) { return false; } - - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - SH1106InitDriver(); - } - else if (XDSP_07 == Settings.display_model) { - - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - SH1106Refresh(); - break; -#endif - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_08_ILI9488.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_08_ILI9488.ino" -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_ILI9488 - -#define XDSP_08 8 -#define XI2C_38 38 - -#define COLORED 1 -#define UNCOLORED 0 - - -#define FT6236_address 0x38 - - - -#define USE_TINY_FONT - - -#include -#include - -TouchLocation ili9488_pLoc; -uint8_t ili9488_ctouch_counter = 0; - - -#define BACKPLANE_PIN 2 - -extern uint8_t *buffer; -extern uint8_t color_type; -ILI9488 *ili9488; - -#ifdef USE_TOUCH_BUTTONS -extern VButton *buttons[]; -#endif - -extern const uint16_t picture[]; -uint8_t FT6236_found; - - - -void ILI9488_InitDriver() -{ - if (!Settings.display_model) { - Settings.display_model = XDSP_08; - } - - if (XDSP_08 == Settings.display_model) { - - if (Settings.display_width != ILI9488_TFTWIDTH) { - Settings.display_width = ILI9488_TFTWIDTH; - } - if (Settings.display_height != ILI9488_TFTHEIGHT) { - Settings.display_height = ILI9488_TFTHEIGHT; - } - - - buffer=NULL; - - - fg_color = ILI9488_WHITE; - bg_color = ILI9488_BLACK; - - uint8_t bppin=BACKPLANE_PIN; - if (pin[GPIO_BACKLIGHT]<99) { - bppin=pin[GPIO_BACKLIGHT]; - } - - - if ((pin[GPIO_SSPI_CS]<99) && (pin[GPIO_SSPI_MOSI]<99) && (pin[GPIO_SSPI_SCLK]<99)){ - ili9488 = new ILI9488(pin[GPIO_SSPI_CS],pin[GPIO_SSPI_MOSI],pin[GPIO_SSPI_SCLK],bppin); - } else { - if ((pin[GPIO_SPI_CS]<99) && (pin[GPIO_SPI_MOSI]<99) && (pin[GPIO_SPI_CLK]<99)) { - ili9488 = new ILI9488(pin[GPIO_SPI_CS],pin[GPIO_SPI_MOSI],pin[GPIO_SPI_CLK],bppin); - } else { - return; - } - } - - SPI.begin(); - ili9488->begin(); - renderer = ili9488; - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); - -#ifdef SHOW_SPLASH - - renderer->setTextFont(2); - renderer->setTextColor(ILI9488_WHITE,ILI9488_BLACK); - renderer->DrawStringAt(50, 50, "ILI9488 TFT Display!", ILI9488_WHITE,0); - delay(1000); - - -#endif - - color_type = COLOR_COLOR; - - - if (I2cEnabled(XI2C_38) && I2cSetDevice(FT6236_address)) { - FT6236begin(FT6236_address); - FT6236_found=1; - I2cSetActiveFound(FT6236_address, "FT6236"); - } else { - FT6236_found=0; - } - - } -} - -#ifdef USE_TOUCH_BUTTONS -void ILI9488_MQTT(uint8_t count,const char *cp) { - ResponseTime_P(PSTR(",\"RA8876\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7); - MqttPublishTeleSensor(); -} - -void ILI9488_RDW_BUTT(uint32_t count,uint32_t pwr) { - buttons[count]->xdrawButton(pwr); - if (pwr) buttons[count]->vpower|=0x80; - else buttons[count]->vpower&=0x7f; -} - -void FT6236Check() { -uint16_t temp; -uint8_t rbutt=0,vbutt=0; -ili9488_ctouch_counter++; -if (2 == ili9488_ctouch_counter) { - - ili9488_ctouch_counter=0; - if (FT6236readTouchLocation(&ili9488_pLoc,1)) { - - if (renderer) { - uint8_t rot=renderer->getRotation(); - switch (rot) { - case 0: - temp=ili9488_pLoc.y; - ili9488_pLoc.y=renderer->height()-ili9488_pLoc.x; - ili9488_pLoc.x=temp; - break; - case 1: - break; - case 2: - break; - case 3: - temp=ili9488_pLoc.y; - ili9488_pLoc.y=ili9488_pLoc.x; - ili9488_pLoc.x=renderer->width()-temp; - break; - } - - for (uint8_t count=0; countvpower&0x7f; - if (buttons[count]->contains(ili9488_pLoc.x,ili9488_pLoc.y)) { - - buttons[count]->press(true); - if (buttons[count]->justPressed()) { - if (!bflags) { - uint8_t pwr=bitRead(power,rbutt); - if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { - ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); - ILI9488_RDW_BUTT(count,!pwr); - } - } else { - - const char *cp; - if (bflags==1) { - - buttons[count]->vpower^=0x80; - cp="TBT"; - } else { - - buttons[count]->vpower|=0x80; - cp="PBT"; - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - ILI9488_MQTT(count,cp); - } - } - } - if (!bflags) { - rbutt++; - } else { - vbutt++; - } - } - } - } - } else { - - for (uint8_t count=0; countvpower&0x7f; - buttons[count]->press(false); - if (buttons[count]->justReleased()) { - uint8_t bflags=buttons[count]->vpower&0x7f; - if (bflags>0) { - if (bflags>1) { - - buttons[count]->vpower&=0x7f; - ILI9488_MQTT(count,"PBT"); - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - } - } - if (!bflags) { - - uint8_t pwr=bitRead(power,rbutt); - uint8_t vpwr=(buttons[count]->vpower&0x80)>>7; - if (pwr!=vpwr) { - ILI9488_RDW_BUTT(count,pwr); - } - rbutt++; - } - } - } - ili9488_pLoc.x=0; - ili9488_pLoc.y=0; - } -} -} -#endif - - - - -bool Xdsp08(uint8_t function) -{ - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - ILI9488_InitDriver(); - } - else if (XDSP_08 == Settings.display_model) { - - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: -#ifdef USE_TOUCH_BUTTONS - if (FT6236_found) FT6236Check(); -#endif - break; - } - } - - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_09_SSD1351.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_09_SSD1351.ino" -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_SSD1351 - -#define XDSP_09 9 - -#define COLORED 1 -#define UNCOLORED 0 - - - - -#define USE_TINY_FONT - -#include - -extern uint8_t *buffer; -extern uint8_t color_type; -SSD1351 *ssd1351; - - - -void SSD1351_InitDriver() { - if (!Settings.display_model) { - Settings.display_model = XDSP_09; - } - - if (XDSP_09 == Settings.display_model) { - - if (Settings.display_width != SSD1351_WIDTH) { - Settings.display_width = SSD1351_WIDTH; - } - if (Settings.display_height != SSD1351_HEIGHT) { - Settings.display_height = SSD1351_HEIGHT; - } - - buffer=0; - - - fg_color = SSD1351_WHITE; - bg_color = SSD1351_BLACK; - - - if ((pin[GPIO_SSPI_CS]<99) && (pin[GPIO_SSPI_MOSI]<99) && (pin[GPIO_SSPI_SCLK]<99)){ - ssd1351 = new SSD1351(pin[GPIO_SSPI_CS],pin[GPIO_SSPI_MOSI],pin[GPIO_SSPI_SCLK]); - } else { - if ((pin[GPIO_SPI_CS]<99) && (pin[GPIO_SPI_MOSI]<99) && (pin[GPIO_SPI_CLK]<99)){ - ssd1351 = new SSD1351(pin[GPIO_SPI_CS],pin[GPIO_SPI_MOSI],pin[GPIO_SPI_CLK]); - } else { - return; - } - } - - delay(100); - SPI.begin(); - ssd1351->begin(); - renderer = ssd1351; - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); - renderer->dim(Settings.display_dimmer); - -#ifdef SHOW_SPLASH - - renderer->setTextFont(2); - renderer->setTextColor(SSD1351_WHITE,SSD1351_BLACK); - renderer->DrawStringAt(10, 60, "SSD1351", SSD1351_RED,0); - delay(1000); - -#endif - color_type = COLOR_COLOR; - } -} - -#ifdef USE_DISPLAY_MODES1TO5 - -void SSD1351PrintLog(void) -{ - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings.display_refresh; - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - - char* txt = DisplayLogBuffer('\370'); - if (txt != NULL) { - uint8_t last_row = Settings.display_rows -1; - - renderer->clearDisplay(); - renderer->setTextSize(Settings.display_size); - renderer->setCursor(0,0); - for (byte i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - renderer->println(disp_screen_buffer[i]); - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - - renderer->println(disp_screen_buffer[last_row]); - renderer->Updateframe(); - } - } -} - -void SSD1351Time(void) -{ - char line[12]; - - renderer->clearDisplay(); - renderer->setTextSize(2); - renderer->setCursor(0, 0); - snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); - renderer->println(line); - snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); - renderer->println(line); - renderer->Updateframe(); -} - -void SSD1351Refresh(void) -{ - if (Settings.display_mode) { - switch (Settings.display_mode) { - case 1: - SSD1351Time(); - break; - case 2: - case 3: - case 4: - case 5: - SSD1351PrintLog(); - break; - } - } -} - -#endif - - - - -bool Xdsp09(uint8_t function) -{ - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - SSD1351_InitDriver(); - } - else if (XDSP_09 == Settings.display_model) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - SSD1351Refresh(); - break; -#endif - } - } - return result; -} -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_10_RA8876.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_10_RA8876.ino" -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_RA8876 - -#define XDSP_10 10 -#define XI2C_39 39 - -#define COLORED 1 -#define UNCOLORED 0 - - -#define FT5316_address 0x38 - - - -#define USE_TINY_FONT - -#include -#include - -TouchLocation ra8876_pLoc; -uint8_t ra8876_ctouch_counter = 0; - -#ifdef USE_TOUCH_BUTTONS -extern VButton *buttons[]; -#endif - -extern uint8_t *buffer; -extern uint8_t color_type; -RA8876 *ra8876; - -uint8_t FT5316_found; - - -void RA8876_InitDriver() -{ - if (!Settings.display_model) { - Settings.display_model = XDSP_10; - } - - if (XDSP_10 == Settings.display_model) { - - if (Settings.display_width != RA8876_TFTWIDTH) { - Settings.display_width = RA8876_TFTWIDTH; - } - if (Settings.display_height != RA8876_TFTHEIGHT) { - Settings.display_height = RA8876_TFTHEIGHT; - } - buffer=0; - - - fg_color = RA8876_WHITE; - bg_color = RA8876_BLACK; - - - if ((pin[GPIO_SSPI_CS]<99) && (pin[GPIO_SSPI_MOSI]==13) && (pin[GPIO_SSPI_MISO]==12) && (pin[GPIO_SSPI_SCLK]==14)) { - ra8876 = new RA8876(pin[GPIO_SSPI_CS],pin[GPIO_SSPI_MOSI],pin[GPIO_SSPI_MISO],pin[GPIO_SSPI_SCLK],pin[GPIO_BACKLIGHT]); - } else { - if ((pin[GPIO_SPI_CS]<99) && (pin[GPIO_SPI_MOSI]==13) && (pin[GPIO_SPI_MISO]==12) && (pin[GPIO_SPI_CLK]==14)) { - ra8876 = new RA8876(pin[GPIO_SPI_CS],pin[GPIO_SPI_MOSI],pin[GPIO_SPI_MISO],pin[GPIO_SPI_CLK],pin[GPIO_BACKLIGHT]); - } else { - return; - } - } - - ra8876->begin(); - renderer = ra8876; - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); - renderer->dim(Settings.display_dimmer); - - -#ifdef SHOW_SPLASH - - renderer->setTextFont(2); - renderer->setTextColor(RA8876_WHITE,RA8876_BLACK); - renderer->DrawStringAt(600, 300, "RA8876", RA8876_RED,0); - delay(1000); - -#endif - color_type = COLOR_COLOR; - - if (I2cEnabled(XI2C_39) && I2cSetDevice(FT5316_address)) { - FT6236begin(FT5316_address); - FT5316_found=1; - I2cSetActiveFound(FT5316_address, "FT5316"); - } else { - FT5316_found=0; - } - - } -} - -#ifdef USE_TOUCH_BUTTONS -void RA8876_MQTT(uint8_t count,const char *cp) { - ResponseTime_P(PSTR(",\"RA8876\":{\"%s%d\":\"%d\"}}"), cp,count+1,(buttons[count]->vpower&0x80)>>7); - MqttPublishTeleSensor(); -} - -void RA8876_RDW_BUTT(uint32_t count,uint32_t pwr) { - buttons[count]->xdrawButton(pwr); - if (pwr) buttons[count]->vpower|=0x80; - else buttons[count]->vpower&=0x7f; -} - - -void FT5316Check() { -uint16_t temp; -uint8_t rbutt=0,vbutt=0; -ra8876_ctouch_counter++; -if (2 == ra8876_ctouch_counter) { - - ra8876_ctouch_counter=0; - - if (FT6236readTouchLocation(&ra8876_pLoc,1)) { - ra8876_pLoc.x=ra8876_pLoc.x*RA8876_TFTWIDTH/800; - ra8876_pLoc.y=ra8876_pLoc.y*RA8876_TFTHEIGHT/480; - - - if (renderer) { - - - ra8876_pLoc.x=RA8876_TFTWIDTH-ra8876_pLoc.x; - ra8876_pLoc.y=RA8876_TFTHEIGHT-ra8876_pLoc.y; -# 170 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_10_RA8876.ino" - for (uint8_t count=0; countvpower&0x7f; - if (buttons[count]->contains(ra8876_pLoc.x,ra8876_pLoc.y)) { - - buttons[count]->press(true); - if (buttons[count]->justPressed()) { - if (!bflags) { - - uint8_t pwr=bitRead(power,rbutt); - if (!SendKey(KEY_BUTTON, rbutt+1, POWER_TOGGLE)) { - ExecuteCommandPower(rbutt+1, POWER_TOGGLE, SRC_BUTTON); - RA8876_RDW_BUTT(count,!pwr); - } - } else { - - const char *cp; - if (bflags==1) { - - buttons[count]->vpower^=0x80; - cp="TBT"; - } else { - - buttons[count]->vpower|=0x80; - cp="PBT"; - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - RA8876_MQTT(count,cp); - } - } - } - if (!bflags) { - rbutt++; - } else { - vbutt++; - } - } - } - } - } else { - - for (uint8_t count=0; countvpower&0x7f; - buttons[count]->press(false); - if (buttons[count]->justReleased()) { - if (bflags>0) { - if (bflags>1) { - - buttons[count]->vpower&=0x7f; - RA8876_MQTT(count,"PBT"); - } - buttons[count]->xdrawButton(buttons[count]->vpower&0x80); - } - } - if (!bflags) { - - uint8_t pwr=bitRead(power,rbutt); - uint8_t vpwr=(buttons[count]->vpower&0x80)>>7; - if (pwr!=vpwr) { - RA8876_RDW_BUTT(count,pwr); - } - rbutt++; - } - } - } - ra8876_pLoc.x=0; - ra8876_pLoc.y=0; - } -} -} -#endif -# 426 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_10_RA8876.ino" -bool Xdsp10(uint8_t function) -{ - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - RA8876_InitDriver(); - } - else if (XDSP_10 == Settings.display_model) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: -#ifdef USE_TOUCH_BUTTONS - if (FT5316_found) FT5316Check(); -#endif - break; - } - } - return result; -} -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_11_sevenseg.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_11_sevenseg.ino" -#ifdef USE_I2C -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_SEVENSEG - -#define XDSP_11 11 -#define XI2C_47 47 - -#include -#include -#include - -Adafruit_7segment sevenseg = Adafruit_7segment(); - -uint8_t sevenseg_state = 0; - - - -void SevensegWrite(void) -{ - sevenseg.writeDisplay(); -} - -void SevensegClear(void) -{ - sevenseg.clear(); - SevensegWrite(); -} - - - - -void SevensegInitMode(void) -{ - sevenseg.setBrightness(Settings.display_dimmer); - sevenseg.blinkRate(0); - SevensegClear(); -} - -void SevensegInit(uint8_t mode) -{ - switch(mode) { - case DISPLAY_INIT_MODE: - case DISPLAY_INIT_PARTIAL: - case DISPLAY_INIT_FULL: - SevensegInitMode(); - break; - } -} - -void SevensegInitDriver(void) -{ - if (!Settings.display_model) { - if (I2cSetDevice(SEVENSEG_ADDRESS1)) { - Settings.display_model = XDSP_11; - } - } - - if (XDSP_11 == Settings.display_model) { - sevenseg_state = 1; - sevenseg.begin(SEVENSEG_ADDRESS1); - - Settings.display_width = 4; - Settings.display_height = 1; - - SevensegInitMode(); - } -} - -void SevensegOnOff(void) -{ - if (!disp_power) { SevensegClear(); } -} - -void SevensegDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag) -{ - uint16_t number = 0; - boolean hasnumber= false; - uint8_t dots= 0; - boolean t=false; - boolean T=false; - boolean d=false; - boolean hex=false; - boolean done=false; - boolean s=false; - for (int i=0; (str[i]!='\0') && (!done); i++) { -# 113 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_11_sevenseg.ino" - switch (str[i]) { - case 'x': - hex = true; - break; - case ':': - dots |= 0x02; - break; - case '^': - dots |= 0x08; - break; - case 'v': - dots |= 0x04; - break; - case '.': - dots |= 0x10; - break; - case 'T': - t = true; - break; - case 't': - T = true; - break; - case 's': - s = true; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - hasnumber= true; - number = atoi(str+i); - done = true; - break; - default: - break; - } - } - - if (s) { - - hex = false; - int hour = number/60/60; - int minute = (number/60)%60; - - if (hour) { - - number = hour*100 + minute; - } else { - - number = minute*100 + number%60; - } - } - - if (hasnumber) { - if (hex) { - sevenseg.print(number, HEX); - } else { - sevenseg.print(number, DEC); - } - } - - if (dots) { - sevenseg.writeDigitRaw(2, dots); - } - - sevenseg.writeDisplay(); -} - - - -#ifdef USE_DISPLAY_MODES1TO5 -void SevensegTime(boolean time_24) -{ - - uint hours = RtcTime.hour; - uint minutes = RtcTime.minute; - uint second = RtcTime.second; - uint16_t displayValue = hours * 100 + minutes; - uint16_t dots = 0; - - - if (!time_24) { - - if (hours > 12) { - displayValue -= 1200; - } - - else if (hours == 0) { - displayValue += 1200; - } - } - - - - sevenseg.print(displayValue, DEC); - - - - - if (time_24) { - if (hours == 0) { - - sevenseg.writeDigitNum(1, 0); - - if (minutes < 10) { - sevenseg.writeDigitNum(3, 0); - } - } - if (hours < 10) { - - sevenseg.writeDigitNum(0, 0); - } - } else { - - if (hours >= 12) { - dots |= 0x10; - } - } - - sevenseg.writeDigitRaw(2, dots |= ((second%2) << 1)); - sevenseg.writeDisplay(); -} - -#endif - -void SevensegRefresh(void) -{ - if (disp_power) { - if (Settings.display_mode) { - switch (Settings.display_mode) { - case 1: - SevensegTime(false); - break; - case 2: - SevensegTime(true); - break; - case 4: - case 3: - case 5: { - break; - } - } - } - } -} - - - - - -bool Xdsp11(uint8_t function) -{ - if (!I2cEnabled(XI2C_47)) { return false; } - - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - SevensegInitDriver(); - } - else if (XDSP_11 == Settings.display_model) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_INIT: - SevensegInit(dsp_init); - break; - case FUNC_DISPLAY_CLEAR: - SevensegClear(); - break; - case FUNC_DISPLAY_EVERY_SECOND: - SevensegRefresh(); - break; - case FUNC_DISPLAY_ONOFF: - case FUNC_DISPLAY_POWER: - SevensegOnOff(); - break; - case FUNC_DISPLAY_DRAW_STRING: - SevensegDrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag); - break; - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_interface.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_interface.ino" -#if defined(USE_I2C) || defined(USE_SPI) -#ifdef USE_DISPLAY - -#ifdef XFUNC_PTR_IN_ROM -bool (* const xdsp_func_ptr[])(uint8_t) PROGMEM = { -#else -bool (* const xdsp_func_ptr[])(uint8_t) = { -#endif - -#ifdef XDSP_01 - &Xdsp01, -#endif - -#ifdef XDSP_02 - &Xdsp02, -#endif - -#ifdef XDSP_03 - &Xdsp03, -#endif - -#ifdef XDSP_04 - &Xdsp04, -#endif - -#ifdef XDSP_05 - &Xdsp05, -#endif - -#ifdef XDSP_06 - &Xdsp06, -#endif - -#ifdef XDSP_07 - &Xdsp07, -#endif - -#ifdef XDSP_08 - &Xdsp08, -#endif - -#ifdef XDSP_09 - &Xdsp09, -#endif - -#ifdef XDSP_10 - &Xdsp10, -#endif - -#ifdef XDSP_11 - &Xdsp11, -#endif - -#ifdef XDSP_12 - &Xdsp12, -#endif - -#ifdef XDSP_13 - &Xdsp13, -#endif - -#ifdef XDSP_14 - &Xdsp14, -#endif - -#ifdef XDSP_15 - &Xdsp15, -#endif - -#ifdef XDSP_16 - &Xdsp16 -#endif -}; - -const uint8_t xdsp_present = sizeof(xdsp_func_ptr) / sizeof(xdsp_func_ptr[0]); -# 118 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xdsp_interface.ino" -uint8_t XdspPresent(void) -{ - return xdsp_present; -} - -bool XdspCall(uint8_t Function) -{ - bool result = false; - - DEBUG_TRACE_LOG(PSTR("DSP: %d"), Function); - - for (uint32_t x = 0; x < xdsp_present; x++) { - result = xdsp_func_ptr[x](Function); - - if (result && (FUNC_DISPLAY_MODEL == Function)) { - break; - } - } - - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_01_ws2812.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_01_ws2812.ino" -#ifdef USE_LIGHT -#ifdef USE_WS2812 -# 38 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_01_ws2812.ino" -#define XLGT_01 1 - -const uint8_t WS2812_SCHEMES = 8; - -const char kWs2812Commands[] PROGMEM = "|" - D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH ; - -void (* const Ws2812Command[])(void) PROGMEM = { - &CmndLed, &CmndPixels, &CmndRotation, &CmndWidth }; - -#include - -#if (USE_WS2812_CTYPE == NEO_GRB) - typedef NeoGrbFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_BRG) - typedef NeoBrgFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_RBG) - typedef NeoRbgFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_RGBW) - typedef NeoRgbwFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_GRBW) - typedef NeoGrbwFeature selectedNeoFeatureType; -#else - typedef NeoRgbFeature selectedNeoFeatureType; -#endif - -#ifdef USE_WS2812_DMA - - -#if (USE_WS2812_HARDWARE == NEO_HW_WS2812X) - typedef NeoEsp8266DmaWs2812xMethod selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812) - typedef NeoEsp8266DmaSk6812Method selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_APA106) - typedef NeoEsp8266DmaApa106Method selectedNeoSpeedType; -#else - typedef NeoEsp8266Dma800KbpsMethod selectedNeoSpeedType; -#endif - -#else - - -#if (USE_WS2812_HARDWARE == NEO_HW_WS2812X) - typedef NeoEsp8266BitBangWs2812xMethod selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812) - typedef NeoEsp8266BitBangSk6812Method selectedNeoSpeedType; -#else - typedef NeoEsp8266BitBang800KbpsMethod selectedNeoSpeedType; -#endif - -#endif - -NeoPixelBus *strip = nullptr; - -struct WsColor { - uint8_t red, green, blue; -}; - -struct ColorScheme { - WsColor* colors; - uint8_t count; -}; - -WsColor kIncandescent[2] = { 255,140,20, 0,0,0 }; -WsColor kRgb[3] = { 255,0,0, 0,255,0, 0,0,255 }; -WsColor kChristmas[2] = { 255,0,0, 0,255,0 }; -WsColor kHanukkah[2] = { 0,0,255, 255,255,255 }; -WsColor kwanzaa[3] = { 255,0,0, 0,0,0, 0,255,0 }; -WsColor kRainbow[7] = { 255,0,0, 255,128,0, 255,255,0, 0,255,0, 0,0,255, 128,0,255, 255,0,255 }; -WsColor kFire[3] = { 255,0,0, 255,102,0, 255,192,0 }; -ColorScheme kSchemes[WS2812_SCHEMES -1] = { - kIncandescent, 2, - kRgb, 3, - kChristmas, 2, - kHanukkah, 2, - kwanzaa, 3, - kRainbow, 7, - kFire, 3 }; - -uint8_t kWidth[5] = { - 1, - 2, - 4, - 8, - 255 }; -uint8_t kWsRepeat[5] = { - 8, - 6, - 4, - 2, - 1 }; - -struct WS2812 { - uint8_t show_next = 1; - uint8_t scheme_offset = 0; - bool suspend_update = false; -} Ws2812; - - - -void Ws2812StripShow(void) -{ -#if (USE_WS2812_CTYPE > NEO_3LED) - RgbwColor c; -#else - RgbColor c; -#endif - - if (Settings.light_correction) { - for (uint32_t i = 0; i < Settings.light_pixels; i++) { - c = strip->GetPixelColor(i); - c.R = ledGamma(c.R); - c.G = ledGamma(c.G); - c.B = ledGamma(c.B); -#if (USE_WS2812_CTYPE > NEO_3LED) - c.W = ledGamma(c.W); -#endif - strip->SetPixelColor(i, c); - } - } - strip->Show(); -} - -int mod(int a, int b) -{ - int ret = a % b; - if (ret < 0) ret += b; - return ret; -} - -void Ws2812UpdatePixelColor(int position, struct WsColor hand_color, float offset) -{ -#if (USE_WS2812_CTYPE > NEO_3LED) - RgbwColor color; -#else - RgbColor color; -#endif - - uint32_t mod_position = mod(position, (int)Settings.light_pixels); - - color = strip->GetPixelColor(mod_position); - float dimmer = 100 / (float)Settings.light_dimmer; - color.R = tmin(color.R + ((hand_color.red / dimmer) * offset), 255); - color.G = tmin(color.G + ((hand_color.green / dimmer) * offset), 255); - color.B = tmin(color.B + ((hand_color.blue / dimmer) * offset), 255); - strip->SetPixelColor(mod_position, color); -} - -void Ws2812UpdateHand(int position, uint32_t index) -{ - uint32_t width = Settings.light_width; - if (index < WS_MARKER) { width = Settings.ws_width[index]; } - if (!width) { return; } - - position = (position + Settings.light_rotation) % Settings.light_pixels; - - if (Settings.flag.ws_clock_reverse) { - position = Settings.light_pixels -position; - } - WsColor hand_color = { Settings.ws_color[index][WS_RED], Settings.ws_color[index][WS_GREEN], Settings.ws_color[index][WS_BLUE] }; - - Ws2812UpdatePixelColor(position, hand_color, 1); - - uint32_t range = ((width -1) / 2) +1; - for (uint32_t h = 1; h < range; h++) { - float offset = (float)(range - h) / (float)range; - Ws2812UpdatePixelColor(position -h, hand_color, offset); - Ws2812UpdatePixelColor(position +h, hand_color, offset); - } -} - -void Ws2812Clock(void) -{ - strip->ClearTo(0); - int clksize = 60000 / (int)Settings.light_pixels; - - Ws2812UpdateHand((RtcTime.second * 1000) / clksize, WS_SECOND); - Ws2812UpdateHand((RtcTime.minute * 1000) / clksize, WS_MINUTE); - Ws2812UpdateHand((((RtcTime.hour % 12) * 5000) + ((RtcTime.minute * 1000) / 12 )) / clksize, WS_HOUR); - if (Settings.ws_color[WS_MARKER][WS_RED] + Settings.ws_color[WS_MARKER][WS_GREEN] + Settings.ws_color[WS_MARKER][WS_BLUE]) { - for (uint32_t i = 0; i < 12; i++) { - Ws2812UpdateHand((i * 5000) / clksize, WS_MARKER); - } - } - - Ws2812StripShow(); -} - -void Ws2812GradientColor(uint32_t schemenr, struct WsColor* mColor, uint32_t range, uint32_t gradRange, uint32_t i) -{ - - - - - ColorScheme scheme = kSchemes[schemenr]; - uint32_t curRange = i / range; - uint32_t rangeIndex = i % range; - uint32_t colorIndex = rangeIndex / gradRange; - uint32_t start = colorIndex; - uint32_t end = colorIndex +1; - if (curRange % 2 != 0) { - start = (scheme.count -1) - start; - end = (scheme.count -1) - end; - } - float dimmer = 100 / (float)Settings.light_dimmer; - float fmyRed = (float)map(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].red, scheme.colors[end].red) / dimmer; - float fmyGrn = (float)map(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].green, scheme.colors[end].green) / dimmer; - float fmyBlu = (float)map(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].blue, scheme.colors[end].blue) / dimmer; - mColor->red = (uint8_t)fmyRed; - mColor->green = (uint8_t)fmyGrn; - mColor->blue = (uint8_t)fmyBlu; -} - -void Ws2812Gradient(uint32_t schemenr) -{ - - - - - -#if (USE_WS2812_CTYPE > NEO_3LED) - RgbwColor c; - c.W = 0; -#else - RgbColor c; -#endif - - ColorScheme scheme = kSchemes[schemenr]; - if (scheme.count < 2) { return; } - - uint32_t repeat = kWsRepeat[Settings.light_width]; - uint32_t range = (uint32_t)ceil((float)Settings.light_pixels / (float)repeat); - uint32_t gradRange = (uint32_t)ceil((float)range / (float)(scheme.count - 1)); - uint32_t speed = ((Settings.light_speed * 2) -1) * (STATES / 10); - uint32_t offset = speed > 0 ? Light.strip_timer_counter / speed : 0; - - WsColor oldColor, currentColor; - Ws2812GradientColor(schemenr, &oldColor, range, gradRange, offset); - currentColor = oldColor; - for (uint32_t i = 0; i < Settings.light_pixels; i++) { - if (kWsRepeat[Settings.light_width] > 1) { - Ws2812GradientColor(schemenr, ¤tColor, range, gradRange, i +offset); - } - if (Settings.light_speed > 0) { - - c.R = map(Light.strip_timer_counter % speed, 0, speed, oldColor.red, currentColor.red); - c.G = map(Light.strip_timer_counter % speed, 0, speed, oldColor.green, currentColor.green); - c.B = map(Light.strip_timer_counter % speed, 0, speed, oldColor.blue, currentColor.blue); - } - else { - - c.R = currentColor.red; - c.G = currentColor.green; - c.B = currentColor.blue; - } - strip->SetPixelColor(i, c); - oldColor = currentColor; - } - Ws2812StripShow(); -} - -void Ws2812Bars(uint32_t schemenr) -{ - - - - - -#if (USE_WS2812_CTYPE > NEO_3LED) - RgbwColor c; - c.W = 0; -#else - RgbColor c; -#endif - - ColorScheme scheme = kSchemes[schemenr]; - - uint32_t maxSize = Settings.light_pixels / scheme.count; - if (kWidth[Settings.light_width] > maxSize) { maxSize = 0; } - - uint32_t speed = ((Settings.light_speed * 2) -1) * (STATES / 10); - uint32_t offset = (speed > 0) ? Light.strip_timer_counter / speed : 0; - - WsColor mcolor[scheme.count]; - memcpy(mcolor, scheme.colors, sizeof(mcolor)); - float dimmer = 100 / (float)Settings.light_dimmer; - for (uint32_t i = 0; i < scheme.count; i++) { - float fmyRed = (float)mcolor[i].red / dimmer; - float fmyGrn = (float)mcolor[i].green / dimmer; - float fmyBlu = (float)mcolor[i].blue / dimmer; - mcolor[i].red = (uint8_t)fmyRed; - mcolor[i].green = (uint8_t)fmyGrn; - mcolor[i].blue = (uint8_t)fmyBlu; - } - uint32_t colorIndex = offset % scheme.count; - for (uint32_t i = 0; i < Settings.light_pixels; i++) { - if (maxSize) { colorIndex = ((i + offset) % (scheme.count * kWidth[Settings.light_width])) / kWidth[Settings.light_width]; } - c.R = mcolor[colorIndex].red; - c.G = mcolor[colorIndex].green; - c.B = mcolor[colorIndex].blue; - strip->SetPixelColor(i, c); - } - Ws2812StripShow(); -} - -void Ws2812Clear(void) -{ - strip->ClearTo(0); - strip->Show(); - Ws2812.show_next = 1; -} - -void Ws2812SetColor(uint32_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white) -{ -#if (USE_WS2812_CTYPE > NEO_3LED) - RgbwColor lcolor; - lcolor.W = white; -#else - RgbColor lcolor; -#endif - - lcolor.R = red; - lcolor.G = green; - lcolor.B = blue; - if (led) { - strip->SetPixelColor(led -1, lcolor); - } else { - - for (uint32_t i = 0; i < Settings.light_pixels; i++) { - strip->SetPixelColor(i, lcolor); - } - } - - if (!Ws2812.suspend_update) { - strip->Show(); - Ws2812.show_next = 1; - } -} - -char* Ws2812GetColor(uint32_t led, char* scolor) -{ - uint8_t sl_ledcolor[4]; - - #if (USE_WS2812_CTYPE > NEO_3LED) - RgbwColor lcolor = strip->GetPixelColor(led -1); - sl_ledcolor[3] = lcolor.W; - #else - RgbColor lcolor = strip->GetPixelColor(led -1); - #endif - sl_ledcolor[0] = lcolor.R; - sl_ledcolor[1] = lcolor.G; - sl_ledcolor[2] = lcolor.B; - scolor[0] = '\0'; - for (uint32_t i = 0; i < Light.subtype; i++) { - if (Settings.flag.decimal_text) { - snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", sl_ledcolor[i]); - } else { - snprintf_P(scolor, 25, PSTR("%s%02X"), scolor, sl_ledcolor[i]); - } - } - return scolor; -} - - - - - -void Ws2812ForceSuspend (void) -{ - Ws2812.suspend_update = true; -} - -void Ws2812ForceUpdate (void) -{ - Ws2812.suspend_update = false; - strip->Show(); - Ws2812.show_next = 1; -} - - - -bool Ws2812SetChannels(void) -{ - uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; - - Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]); - - return true; -} - -void Ws2812ShowScheme(void) -{ - uint32_t scheme = Settings.light_scheme - Ws2812.scheme_offset; - - switch (scheme) { - case 0: - if ((1 == state_250mS) || (Ws2812.show_next)) { - Ws2812Clock(); - Ws2812.show_next = 0; - } - break; - default: - if (1 == Settings.light_fade) { - Ws2812Gradient(scheme -1); - } else { - Ws2812Bars(scheme -1); - } - Ws2812.show_next = 1; - break; - } -} - -void Ws2812ModuleSelected(void) -{ - if (pin[GPIO_WS2812] < 99) { - - - strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); - strip->Begin(); - - Ws2812Clear(); - - Ws2812.scheme_offset = Light.max_scheme +1; - Light.max_scheme += WS2812_SCHEMES; - -#if (USE_WS2812_CTYPE > NEO_3LED) - light_type = LT_RGBW; -#else - light_type = LT_RGB; -#endif - light_flg = XLGT_01; - } -} - - - -void CmndLed(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Settings.light_pixels)) { - if (XdrvMailbox.data_len > 0) { - char *p; - uint16_t idx = XdrvMailbox.index; - Ws2812ForceSuspend(); - for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(nullptr, " ", &p)) { - if (LightColorEntry(color, strlen(color))) { - Ws2812SetColor(idx, Light.entry_color[0], Light.entry_color[1], Light.entry_color[2], Light.entry_color[3]); - idx++; - if (idx > Settings.light_pixels) { break; } - } else { - break; - } - } - Ws2812ForceUpdate(); - } - char scolor[LIGHT_COLOR_SIZE]; - ResponseCmndIdxChar(Ws2812GetColor(XdrvMailbox.index, scolor)); - } -} - -void CmndPixels(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= WS2812_MAX_LEDS)) { - Settings.light_pixels = XdrvMailbox.payload; - Settings.light_rotation = 0; - Ws2812Clear(); - Light.update = true; - } - ResponseCmndNumber(Settings.light_pixels); -} - -void CmndRotation(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < Settings.light_pixels)) { - Settings.light_rotation = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.light_rotation); -} - -void CmndWidth(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) { - if (1 == XdrvMailbox.index) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 4)) { - Settings.light_width = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.light_width); - } else { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32)) { - Settings.ws_width[XdrvMailbox.index -2] = XdrvMailbox.payload; - } - ResponseCmndIdxNumber(Settings.ws_width[XdrvMailbox.index -2]); - } - } -} - - - - - -bool Xlgt01(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_SET_CHANNELS: - result = Ws2812SetChannels(); - break; - case FUNC_SET_SCHEME: - Ws2812ShowScheme(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kWs2812Commands, Ws2812Command); - break; - case FUNC_MODULE_INIT: - Ws2812ModuleSelected(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_02_my92x1.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_02_my92x1.ino" -#ifdef USE_LIGHT -#ifdef USE_MY92X1 - - - - -#define XLGT_02 2 - -struct MY92X1 { - uint8_t pdi_pin = 0; - uint8_t pdcki_pin = 0; - uint8_t model = 0; -} My92x1; - -extern "C" { - void os_delay_us(unsigned int); -} - -void LightDiPulse(uint8_t times) -{ - for (uint32_t i = 0; i < times; i++) { - digitalWrite(My92x1.pdi_pin, HIGH); - digitalWrite(My92x1.pdi_pin, LOW); - } -} - -void LightDckiPulse(uint8_t times) -{ - for (uint32_t i = 0; i < times; i++) { - digitalWrite(My92x1.pdcki_pin, HIGH); - digitalWrite(My92x1.pdcki_pin, LOW); - } -} - -void LightMy92x1Write(uint8_t data) -{ - for (uint32_t i = 0; i < 4; i++) { - digitalWrite(My92x1.pdcki_pin, LOW); - digitalWrite(My92x1.pdi_pin, (data & 0x80)); - digitalWrite(My92x1.pdcki_pin, HIGH); - data = data << 1; - digitalWrite(My92x1.pdi_pin, (data & 0x80)); - digitalWrite(My92x1.pdcki_pin, LOW); - digitalWrite(My92x1.pdi_pin, LOW); - data = data << 1; - } -} - -void LightMy92x1Init(void) -{ - uint8_t chips[3] = { 1, 2, 2 }; - - LightDckiPulse(chips[My92x1.model] * 32); - os_delay_us(12); - - - LightDiPulse(12); - os_delay_us(12); - for (uint32_t n = 0; n < chips[My92x1.model]; n++) { - LightMy92x1Write(0x18); - } - os_delay_us(12); - - - LightDiPulse(16); - os_delay_us(12); -} - -void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c) -{ - uint8_t channels[3] = { 4, 6, 6 }; - - uint8_t duty[3][6] = {{ duty_r, duty_g, duty_b, duty_w, 0, 0 }, - { duty_w, duty_c, 0, duty_g, duty_r, duty_b }, - { duty_r, duty_g, duty_b, duty_w, duty_w, duty_w }}; - - os_delay_us(12); - for (uint32_t channel = 0; channel < channels[My92x1.model]; channel++) { - LightMy92x1Write(duty[My92x1.model][channel]); - } - os_delay_us(12); - LightDiPulse(8); - os_delay_us(12); -} - - - -bool My92x1SetChannels(void) -{ - uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; - - LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); - - return true; -} - -void My92x1ModuleSelected(void) -{ - if ((pin[GPIO_DCKI] < 99) && (pin[GPIO_DI] < 99)) { - My92x1.pdi_pin = pin[GPIO_DI]; - My92x1.pdcki_pin = pin[GPIO_DCKI]; - - pinMode(My92x1.pdi_pin, OUTPUT); - pinMode(My92x1.pdcki_pin, OUTPUT); - digitalWrite(My92x1.pdi_pin, LOW); - digitalWrite(My92x1.pdcki_pin, LOW); - - My92x1.model = 2; - light_type = LT_RGBW; - if (AILIGHT == my_module_type) { - My92x1.model = 0; - - } - else if (SONOFF_B1 == my_module_type) { - My92x1.model = 1; - light_type = LT_RGBWC; - } - - LightMy92x1Init(); - - light_flg = XLGT_02; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: MY29x1 Found")); - } -} - - - - - -bool Xlgt02(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_SET_CHANNELS: - result = My92x1SetChannels(); - break; - case FUNC_MODULE_INIT: - My92x1ModuleSelected(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_03_sm16716.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_03_sm16716.ino" -#ifdef USE_LIGHT -#ifdef USE_SM16716 - - - - - - - -#define XLGT_03 3 - -#define D_LOG_SM16716 "SM16716: " - -struct SM16716 { - uint8_t pin_clk = 0; - uint8_t pin_dat = 0; - uint8_t pin_sel = 0; - bool enabled = false; -} Sm16716; - -void SM16716_SendBit(uint8_t v) -{ - - - - - - digitalWrite(Sm16716.pin_dat, (v != 0) ? HIGH : LOW); - - digitalWrite(Sm16716.pin_clk, HIGH); - - digitalWrite(Sm16716.pin_clk, LOW); -} - -void SM16716_SendByte(uint8_t v) -{ - uint8_t mask; - - for (mask = 0x80; mask; mask >>= 1) { - SM16716_SendBit(v & mask); - } -} - -void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b) -{ - if (Sm16716.pin_sel < 99) { - bool should_enable = (duty_r | duty_g | duty_b); - if (!Sm16716.enabled && should_enable) { - DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color on")); - Sm16716.enabled = true; - digitalWrite(Sm16716.pin_sel, HIGH); - - - delayMicroseconds(1000); - SM16716_Init(); - } - else if (Sm16716.enabled && !should_enable) { - DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color off")); - Sm16716.enabled = false; - digitalWrite(Sm16716.pin_sel, LOW); - } - } - DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "Update; rgb=%02x%02x%02x"), duty_r, duty_g, duty_b); - - - SM16716_SendBit(1); - SM16716_SendByte(duty_r); - SM16716_SendByte(duty_g); - SM16716_SendByte(duty_b); - - - - - - SM16716_SendBit(0); - SM16716_SendByte(0); - SM16716_SendByte(0); - SM16716_SendByte(0); -} -# 111 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_03_sm16716.ino" -void SM16716_Init(void) -{ - for (uint32_t t_init = 0; t_init < 50; ++t_init) { - SM16716_SendBit(0); - } -} - - - -bool Sm16716SetChannels(void) -{ -# 132 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_03_sm16716.ino" - uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; - - SM16716_Update(cur_col[0], cur_col[1], cur_col[2]); - - return true; -} - -void Sm16716ModuleSelected(void) -{ - if ((pin[GPIO_SM16716_CLK] < 99) && (pin[GPIO_SM16716_DAT] < 99)) { - Sm16716.pin_clk = pin[GPIO_SM16716_CLK]; - Sm16716.pin_dat = pin[GPIO_SM16716_DAT]; - Sm16716.pin_sel = pin[GPIO_SM16716_SEL]; -# 157 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_03_sm16716.ino" - pinMode(Sm16716.pin_clk, OUTPUT); - digitalWrite(Sm16716.pin_clk, LOW); - - pinMode(Sm16716.pin_dat, OUTPUT); - digitalWrite(Sm16716.pin_dat, LOW); - - if (Sm16716.pin_sel < 99) { - pinMode(Sm16716.pin_sel, OUTPUT); - digitalWrite(Sm16716.pin_sel, LOW); - - } else { - - SM16716_Init(); - } - - LightPwmOffset(LST_RGB); - light_type += LST_RGB; - light_flg = XLGT_03; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM16716 Found")); - } -} - - - - - -bool Xlgt03(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_SET_CHANNELS: - result = Sm16716SetChannels(); - break; - case FUNC_MODULE_INIT: - Sm16716ModuleSelected(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_04_sm2135.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_04_sm2135.ino" -#ifdef USE_LIGHT -#ifdef USE_SM2135 - - - - - - -#define XLGT_04 4 - -#define SM2135_ADDR_MC 0xC0 -#define SM2135_ADDR_CH 0xC1 -#define SM2135_ADDR_R 0xC2 -#define SM2135_ADDR_G 0xC3 -#define SM2135_ADDR_B 0xC4 -#define SM2135_ADDR_C 0xC5 -#define SM2135_ADDR_W 0xC6 - -#define SM2135_RGB 0x00 -#define SM2135_CW 0x80 - -#define SM2135_10MA 0x00 -#define SM2135_15MA 0x01 -#define SM2135_20MA 0x02 -#define SM2135_25MA 0x03 -#define SM2135_30MA 0x04 -#define SM2135_35MA 0x05 -#define SM2135_40MA 0x06 -#define SM2135_45MA 0x07 -#define SM2135_50MA 0x08 -#define SM2135_55MA 0x09 -#define SM2135_60MA 0x0A - - -const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_15MA; - -struct SM2135 { - uint8_t clk = 0; - uint8_t data = 0; -} Sm2135; - -uint8_t Sm2135Write(uint8_t data) -{ - for (uint32_t i = 0; i < 8; i++) { - digitalWrite(Sm2135.clk, LOW); - digitalWrite(Sm2135.data, (data & 0x80)); - digitalWrite(Sm2135.clk, HIGH); - data = data << 1; - } - digitalWrite(Sm2135.clk, LOW); - digitalWrite(Sm2135.data, HIGH); - pinMode(Sm2135.data, INPUT); - digitalWrite(Sm2135.clk, HIGH); - uint8_t ack = digitalRead(Sm2135.data); - pinMode(Sm2135.data, OUTPUT); - return ack; -} - -void Sm2135Send(uint8_t *buffer, uint8_t size) -{ - digitalWrite(Sm2135.data, LOW); - for (uint32_t i = 0; i < size; i++) { - Sm2135Write(buffer[i]); - } - digitalWrite(Sm2135.clk, LOW); - digitalWrite(Sm2135.clk, HIGH); - digitalWrite(Sm2135.data, HIGH); -} - - - -bool Sm2135SetChannels(void) -{ - uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; - uint8_t data[6]; - - if ((0 == cur_col[0]) && (0 == cur_col[1]) && (0 == cur_col[2])) { -# 106 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_04_sm2135.ino" - data[0] = SM2135_ADDR_MC; - data[1] = SM2135_CURRENT; - data[2] = SM2135_CW; - Sm2135Send(data, 3); - delay(1); - data[0] = SM2135_ADDR_C; - data[1] = cur_col[4]; - data[2] = cur_col[3]; - Sm2135Send(data, 3); - } else { - - - - - - - - data[0] = SM2135_ADDR_MC; - data[1] = SM2135_CURRENT; - data[2] = SM2135_RGB; - data[3] = cur_col[1]; - data[4] = cur_col[0]; - data[5] = cur_col[2]; - Sm2135Send(data, 6); - } - - return true; -} - -void Sm2135ModuleSelected(void) -{ - if ((pin[GPIO_SM2135_CLK] < 99) && (pin[GPIO_SM2135_DAT] < 99)) { - Sm2135.clk = pin[GPIO_SM2135_CLK]; - Sm2135.data = pin[GPIO_SM2135_DAT]; - - pinMode(Sm2135.data, OUTPUT); - digitalWrite(Sm2135.data, HIGH); - pinMode(Sm2135.clk, OUTPUT); - digitalWrite(Sm2135.clk, HIGH); - - light_type = LT_RGBWC; - light_flg = XLGT_04; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM2135 Found")); - } -} - - - - - -bool Xlgt04(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_SET_CHANNELS: - result = Sm2135SetChannels(); - break; - case FUNC_MODULE_INIT: - Sm2135ModuleSelected(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_05_sonoff_l1.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_05_sonoff_l1.ino" -#ifdef USE_LIGHT -#ifdef USE_SONOFF_L1 - - - - -#define XLGT_05 5 - -#define SONOFF_L1_BUFFER_SIZE 140 - -#define SONOFF_L1_MODE_COLORFUL 1 -#define SONOFF_L1_MODE_COLORFUL_GRADIENT 2 -#define SONOFF_L1_MODE_COLORFUL_BREATH 3 -#define SONOFF_L1_MODE_DIY_GRADIENT 4 -#define SONOFF_L1_MODE_DIY_PULSE 5 -#define SONOFF_L1_MODE_DIY_BREATH 6 -#define SONOFF_L1_MODE_DIY_STROBE 7 -#define SONOFF_L1_MODE_RGB_GRADIENT 8 -#define SONOFF_L1_MODE_RGB_PULSE 9 -#define SONOFF_L1_MODE_RGB_BREATH 10 -#define SONOFF_L1_MODE_RGB_STROBE 11 -#define SONOFF_L1_MODE_SYNC_TO_MUSIC 12 - -struct SNFL1 { - uint32_t unlock = 0; - bool receive_ready = true; -} Snfl1; - - - -void SnfL1Send(const char *buffer) -{ - - - Serial.print(buffer); - Serial.write(0x1B); - Serial.flush(); -} - -void SnfL1SerialSendOk(void) -{ - char buffer[16]; - snprintf_P(buffer, sizeof(buffer), PSTR("AT+SEND=ok")); - - SnfL1Send(buffer); -} - -bool SnfL1SerialInput(void) -{ - if (serial_in_byte != 0x1B) { - if (serial_in_byte_counter >= 140) { - serial_in_byte_counter = 0; - } - if (serial_in_byte_counter || (!serial_in_byte_counter && ('A' == serial_in_byte))) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - } - } else { - serial_in_buffer[serial_in_byte_counter++] = 0x00; - - - - - - - if (!strncmp(serial_in_buffer +3, "RESULT", 6)) { - Snfl1.receive_ready = true; - } - else if (!strncmp(serial_in_buffer +3, "UPDATE", 6)) { - char cmnd_dimmer[20]; - char cmnd_color[20]; - char *end_str; - char *string = serial_in_buffer +10; - char *token = strtok_r(string, ",", &end_str); - - bool color_updated[3] = { false, false, false }; - uint8_t current_color[3]; - memcpy(current_color, Settings.light_color, 3); - - bool switch_state = false; - bool is_power_change = false; - bool is_color_change = false; - bool is_brightness_change = false; - - while (token != nullptr) { - char* end_token; - char* token2 = strtok_r(token, ":", &end_token); - char* token3 = strtok_r(nullptr, ":", &end_token); - - if (!strncmp(token2, "\"sequence\"", 10)) { - - - - token = nullptr; - } - - else if (!strncmp(token2, "\"switch\"", 8)) { - switch_state = !strncmp(token3, "\"on\"", 4) ? true : false; - - - - is_power_change = (switch_state != Light.power); - } - - else if (!strncmp(token2, "\"color", 6)) { - char color_channel_name = token2[6]; - int color_index; - switch(color_channel_name) - { - case 'R': color_index = 0; - break; - case 'G': color_index = 1; - break; - case 'B': color_index = 2; - break; - } - int color_value = atoi(token3); - current_color[color_index] = color_value; - color_updated[color_index] = true; - - bool all_color_channels_updated = color_updated[0] && color_updated[1] && color_updated[2]; - if (all_color_channels_updated) { - - - - - - is_color_change = (Light.power && (memcmp(current_color, Settings.light_color, 3) != 0)); - } - snprintf_P(cmnd_color, sizeof(cmnd_color), PSTR(D_CMND_COLOR "2 %02x%02x%02x"), current_color[0], current_color[1], current_color[2]); - } - - else if (!strncmp(token2, "\"bright\"", 8)) { - uint8_t dimmer = atoi(token3); - - - - is_brightness_change = (Light.power && (dimmer > 0) && (dimmer != Settings.light_dimmer)); - snprintf_P(cmnd_dimmer, sizeof(cmnd_dimmer), PSTR(D_CMND_DIMMER " %d"), dimmer); - } - - token = strtok_r(nullptr, ",", &end_str); - } - - if (is_power_change) { - if (Settings.light_scheme > 0) { - if (!switch_state) { - char cmnd_scheme[20]; - snprintf_P(cmnd_scheme, sizeof(cmnd_scheme), PSTR(D_CMND_SCHEME " 0")); - ExecuteCommand(cmnd_scheme, SRC_SWITCH); - } - } else { - ExecuteCommandPower(1, switch_state, SRC_SWITCH); - } - } - else if (is_brightness_change) { - ExecuteCommand(cmnd_dimmer, SRC_SWITCH); - } - else if (Light.power && is_color_change) { - if (0 == Settings.light_scheme) { - if (Settings.light_fade) { - char cmnd_fade[20]; - snprintf_P(cmnd_fade, sizeof(cmnd_fade), PSTR(D_CMND_FADE " 0")); - ExecuteCommand(cmnd_fade, SRC_SWITCH); - } - ExecuteCommand(cmnd_color, SRC_SWITCH); - } - } - } - - SnfL1SerialSendOk(); - - return true; - } - serial_in_byte = 0; - return false; -} - - - -bool SnfL1SetChannels(void) -{ - if (Snfl1.receive_ready || TimeReached(Snfl1.unlock)) { - - uint8_t *scale_col = (uint8_t*)XdrvMailbox.topic; - - char buffer[140]; - snprintf_P(buffer, sizeof(buffer), PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"switch\":\"%s\",\"light_type\":1,\"colorR\":%d,\"colorG\":%d,\"colorB\":%d,\"bright\":%d,\"mode\":%d"), - LocalTime(), millis()%1000, - Light.power ? "on" : "off", - scale_col[0], scale_col[1], scale_col[2], - light_state.getDimmer(), - SONOFF_L1_MODE_COLORFUL); - - SnfL1Send(buffer); - - Snfl1.unlock = millis() + 500; - Snfl1.receive_ready = false; - } - return true; -} - -void SnfL1ModuleSelected(void) -{ - if (SONOFF_L1 == my_module_type) { - if ((pin[GPIO_RXD] < 99) && (pin[GPIO_TXD] < 99)) { - SetSerial(19200, TS_SERIAL_8N1); - - light_type = LT_RGB; - light_flg = XLGT_05; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("LGT: Sonoff L1 Found")); - } - } -} - - - - - -bool Xlgt05(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_SERIAL: - result = SnfL1SerialInput(); - break; - case FUNC_SET_CHANNELS: - result = SnfL1SetChannels(); - break; - case FUNC_MODULE_INIT: - SnfL1ModuleSelected(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_06_electriq_moodl.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_06_electriq_moodl.ino" -#ifdef USE_LIGHT -#ifdef USE_ELECTRIQ_MOODL -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_06_electriq_moodl.ino" -#define XLGT_06 6 - - - -bool ElectriqMoodLSetChannels(void) -{ - uint8_t *col = (uint8_t*)XdrvMailbox.data; - uint8_t checksum = (uint8_t)(0x65 + 0xAA + 0x01 + 0x0A); - - Serial.write(0x65); - Serial.write(0xAA); - Serial.write(0x00); - Serial.write(0x01); - Serial.write(0x0A); - - uint8_t payload[5]; - payload[0] = col[0]; - payload[1] = col[1]; - payload[2] = col[2]; - payload[3] = col[3]; - payload[4] = 0x0; - - - for (uint32_t i = 0; i < 5; i++) { - Serial.write(payload[i]); - checksum += payload[i]; - } - - - for (uint32_t i = 0; i < 5; i++) { - Serial.write(payload[i]); - checksum += payload[i]; - } - - Serial.write(checksum); - Serial.flush(); - - return true; -} - -void ElectriqMoodLModuleSelected(void) -{ - if (pin[GPIO_ELECTRIQ_MOODL_TX] < 99) { - SetSerial(9600, TS_SERIAL_8N1); - light_type = LT_RGBW; - light_flg = XLGT_06; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("LGT: ElectriQ Mood Lamp Found")); - } -} - - - - - -bool Xlgt06(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_SET_CHANNELS: - result = ElectriqMoodLSetChannels(); - break; - case FUNC_MODULE_INIT: - ElectriqMoodLModuleSelected(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_interface.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xlgt_interface.ino" -#ifdef USE_LIGHT - -#ifdef XFUNC_PTR_IN_ROM -bool (* const xlgt_func_ptr[])(uint8_t) PROGMEM = { -#else -bool (* const xlgt_func_ptr[])(uint8_t) = { -#endif - -#ifdef XLGT_01 - &Xlgt01, -#endif - -#ifdef XLGT_02 - &Xlgt02, -#endif - -#ifdef XLGT_03 - &Xlgt03, -#endif - -#ifdef XLGT_04 - &Xlgt04, -#endif - -#ifdef XLGT_05 - &Xlgt05, -#endif - -#ifdef XLGT_06 - &Xlgt06, -#endif - -#ifdef XLGT_07 - &Xlgt07, -#endif - -#ifdef XLGT_08 - &Xlgt08, -#endif - -#ifdef XLGT_09 - &Xlgt09, -#endif - -#ifdef XLGT_10 - &Xlgt10, -#endif - -#ifdef XLGT_11 - &Xlgt11, -#endif - -#ifdef XLGT_12 - &Xlgt12, -#endif - -#ifdef XLGT_13 - &Xlgt13, -#endif - -#ifdef XLGT_14 - &Xlgt14, -#endif - -#ifdef XLGT_15 - &Xlgt15, -#endif - -#ifdef XLGT_16 - &Xlgt16 -#endif -}; - -const uint8_t xlgt_present = sizeof(xlgt_func_ptr) / sizeof(xlgt_func_ptr[0]); - -uint8_t xlgt_active = 0; - -bool XlgtCall(uint8_t function) -{ - DEBUG_TRACE_LOG(PSTR("LGT: %d"), function); - - if (FUNC_MODULE_INIT == function) { - for (uint32_t x = 0; x < xlgt_present; x++) { - xlgt_func_ptr[x](function); - if (light_flg) { - xlgt_active = x; - return true; - } - } - } - else if (light_flg) { - return xlgt_func_ptr[xlgt_active](function); - } - return false; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_01_hlw8012.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_01_hlw8012.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_HLW8012 - - - - - - -#define XNRG_01 1 - - -#define HLW_PREF 10000 -#define HLW_UREF 2200 -#define HLW_IREF 4545 - - -#define HJL_PREF 1362 -#define HJL_UREF 822 -#define HJL_IREF 3300 - -#define HLW_POWER_PROBE_TIME 10 -#define HLW_SAMPLE_COUNT 10 - - - -struct HLW { -#ifdef HLW_DEBUG - unsigned long debug[HLW_SAMPLE_COUNT]; -#endif - unsigned long cf_pulse_length = 0; - unsigned long cf_pulse_last_time = 0; - unsigned long cf_power_pulse_length = 0; - - unsigned long cf1_pulse_length = 0; - unsigned long cf1_pulse_last_time = 0; - unsigned long cf1_summed_pulse_length = 0; - unsigned long cf1_pulse_counter = 0; - unsigned long cf1_voltage_pulse_length = 0; - unsigned long cf1_current_pulse_length = 0; - - unsigned long energy_period_counter = 0; - - unsigned long power_ratio = 0; - unsigned long voltage_ratio = 0; - unsigned long current_ratio = 0; - - uint8_t model_type = 0; - uint8_t cf1_timer = 0; - uint8_t power_retry = 0; - bool select_ui_flag = false; - bool ui_flag = true; - bool load_off = true; -} Hlw; - - -#ifndef USE_WS2812_DMA -void HlwCfInterrupt(void) ICACHE_RAM_ATTR; -void HlwCf1Interrupt(void) ICACHE_RAM_ATTR; -#endif - -void HlwCfInterrupt(void) -{ - unsigned long us = micros(); - - if (Hlw.load_off) { - Hlw.cf_pulse_last_time = us; - Hlw.load_off = false; - } else { - Hlw.cf_pulse_length = us - Hlw.cf_pulse_last_time; - Hlw.cf_pulse_last_time = us; - Hlw.energy_period_counter++; - } - Energy.data_valid[0] = 0; -} - -void HlwCf1Interrupt(void) -{ - unsigned long us = micros(); - - Hlw.cf1_pulse_length = us - Hlw.cf1_pulse_last_time; - Hlw.cf1_pulse_last_time = us; - if ((Hlw.cf1_timer > 2) && (Hlw.cf1_timer < 8)) { - Hlw.cf1_summed_pulse_length += Hlw.cf1_pulse_length; -#ifdef HLW_DEBUG - Hlw.debug[Hlw.cf1_pulse_counter] = Hlw.cf1_pulse_length; -#endif - Hlw.cf1_pulse_counter++; - if (HLW_SAMPLE_COUNT == Hlw.cf1_pulse_counter) { - Hlw.cf1_timer = 8; - } - } - Energy.data_valid[0] = 0; -} - - - -void HlwEvery200ms(void) -{ - unsigned long cf1_pulse_length = 0; - unsigned long hlw_w = 0; - unsigned long hlw_u = 0; - unsigned long hlw_i = 0; - - if (micros() - Hlw.cf_pulse_last_time > (HLW_POWER_PROBE_TIME * 1000000)) { - Hlw.cf_pulse_length = 0; - Hlw.load_off = true; - } - Hlw.cf_power_pulse_length = Hlw.cf_pulse_length; - - if (Hlw.cf_power_pulse_length && Energy.power_on && !Hlw.load_off) { - hlw_w = (Hlw.power_ratio * Settings.energy_power_calibration) / Hlw.cf_power_pulse_length ; - Energy.active_power[0] = (float)hlw_w / 10; - Hlw.power_retry = 1; - } else { - if (Hlw.power_retry) { - Hlw.power_retry--; - } else { - Energy.active_power[0] = 0; - } - } - - if (pin[GPIO_NRG_CF1] < 99) { - Hlw.cf1_timer++; - if (Hlw.cf1_timer >= 8) { - Hlw.cf1_timer = 0; - Hlw.select_ui_flag = (Hlw.select_ui_flag) ? false : true; - DigitalWrite(GPIO_NRG_SEL, Hlw.select_ui_flag); - - if (Hlw.cf1_pulse_counter) { - cf1_pulse_length = Hlw.cf1_summed_pulse_length / Hlw.cf1_pulse_counter; - } - -#ifdef HLW_DEBUG - - char stemp[100]; - stemp[0] = '\0'; - for (uint32_t i = 0; i < Hlw.cf1_pulse_counter; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%s %d"), stemp, Hlw.debug[i]); - } - for (uint32_t i = 0; i < Hlw.cf1_pulse_counter; i++) { - for (uint32_t j = i + 1; j < Hlw.cf1_pulse_counter; j++) { - if (Hlw.debug[i] > Hlw.debug[j]) { - std::swap(Hlw.debug[i], Hlw.debug[j]); - } - } - } - unsigned long median = Hlw.debug[(Hlw.cf1_pulse_counter +1) / 2]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: power %d, ui %d, cnt %d, smpl%s, sum %d, mean %d, median %d"), - Hlw.cf_power_pulse_length , Hlw.select_ui_flag, Hlw.cf1_pulse_counter, stemp, Hlw.cf1_summed_pulse_length, cf1_pulse_length, median); -#endif - - if (Hlw.select_ui_flag == Hlw.ui_flag) { - Hlw.cf1_voltage_pulse_length = cf1_pulse_length; - - if (Hlw.cf1_voltage_pulse_length && Energy.power_on) { - hlw_u = (Hlw.voltage_ratio * Settings.energy_voltage_calibration) / Hlw.cf1_voltage_pulse_length ; - Energy.voltage[0] = (float)hlw_u / 10; - } else { - Energy.voltage[0] = 0; - } - - } else { - Hlw.cf1_current_pulse_length = cf1_pulse_length; - - if (Hlw.cf1_current_pulse_length && Energy.active_power[0]) { - hlw_i = (Hlw.current_ratio * Settings.energy_current_calibration) / Hlw.cf1_current_pulse_length; - Energy.current[0] = (float)hlw_i / 1000; - } else { - Energy.current[0] = 0; - } - - } - Hlw.cf1_summed_pulse_length = 0; - Hlw.cf1_pulse_counter = 0; - } - } -} - -void HlwEverySecond(void) -{ - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { - Hlw.cf1_voltage_pulse_length = 0; - Hlw.cf1_current_pulse_length = 0; - Hlw.cf_power_pulse_length = 0; - } else { - unsigned long hlw_len; - - if (Hlw.energy_period_counter) { - hlw_len = 10000 / Hlw.energy_period_counter; - Hlw.energy_period_counter = 0; - if (hlw_len) { - Energy.kWhtoday_delta += ((Hlw.power_ratio * Settings.energy_power_calibration) / hlw_len) / 36; - EnergyUpdateToday(); - } - } - } -} - -void HlwSnsInit(void) -{ - if (!Settings.energy_power_calibration || (4975 == Settings.energy_power_calibration)) { - Settings.energy_power_calibration = HLW_PREF_PULSE; - Settings.energy_voltage_calibration = HLW_UREF_PULSE; - Settings.energy_current_calibration = HLW_IREF_PULSE; - } - - if (Hlw.model_type) { - Hlw.power_ratio = HJL_PREF; - Hlw.voltage_ratio = HJL_UREF; - Hlw.current_ratio = HJL_IREF; - } else { - Hlw.power_ratio = HLW_PREF; - Hlw.voltage_ratio = HLW_UREF; - Hlw.current_ratio = HLW_IREF; - } - - if (pin[GPIO_NRG_SEL] < 99) { - pinMode(pin[GPIO_NRG_SEL], OUTPUT); - digitalWrite(pin[GPIO_NRG_SEL], Hlw.select_ui_flag); - } - if (pin[GPIO_NRG_CF1] < 99) { - pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP); - attachInterrupt(pin[GPIO_NRG_CF1], HlwCf1Interrupt, FALLING); - } - pinMode(pin[GPIO_HLW_CF], INPUT_PULLUP); - attachInterrupt(pin[GPIO_HLW_CF], HlwCfInterrupt, FALLING); -} - -void HlwDrvInit(void) -{ - Hlw.model_type = 0; - if (pin[GPIO_HJL_CF] < 99) { - pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF]; - pin[GPIO_HJL_CF] = 99; - Hlw.model_type = 1; - } - - if (pin[GPIO_HLW_CF] < 99) { - - Hlw.ui_flag = true; - if (pin[GPIO_NRG_SEL_INV] < 99) { - pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV]; - pin[GPIO_NRG_SEL_INV] = 99; - Hlw.ui_flag = false; - } - - if (pin[GPIO_NRG_CF1] < 99) { - if (99 == pin[GPIO_NRG_SEL]) { - Energy.current_available = false; - } - } else { - Energy.current_available = false; - Energy.voltage_available = false; - } - - energy_flg = XNRG_01; - } -} - -bool HlwCommand(void) -{ - bool serviced = true; - - if ((CMND_POWERCAL == Energy.command_code) || (CMND_VOLTAGECAL == Energy.command_code) || (CMND_CURRENTCAL == Energy.command_code)) { - - } - else if (CMND_POWERSET == Energy.command_code) { - if (XdrvMailbox.data_len && Hlw.cf_power_pulse_length ) { - Settings.energy_power_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio; - } - } - else if (CMND_VOLTAGESET == Energy.command_code) { - if (XdrvMailbox.data_len && Hlw.cf1_voltage_pulse_length ) { - Settings.energy_voltage_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio; - } - } - else if (CMND_CURRENTSET == Energy.command_code) { - if (XdrvMailbox.data_len && Hlw.cf1_current_pulse_length) { - Settings.energy_current_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio; - } - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg01(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_200_MSECOND: - HlwEvery200ms(); - break; - case FUNC_ENERGY_EVERY_SECOND: - HlwEverySecond(); - break; - case FUNC_COMMAND: - result = HlwCommand(); - break; - case FUNC_INIT: - HlwSnsInit(); - break; - case FUNC_PRE_INIT: - HlwDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_02_cse7766.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_02_cse7766.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_CSE7766 - - - - - - - -#define XNRG_02 2 - -#define CSE_MAX_INVALID_POWER 128 - -#define CSE_NOT_CALIBRATED 0xAA - -#define CSE_PULSES_NOT_INITIALIZED -1 - -#define CSE_PREF 1000 -#define CSE_UREF 100 - -#define CSE_BUFFER_SIZE 25 - -#include - -TasmotaSerial *CseSerial = nullptr; - -struct CSE { - long voltage_cycle = 0; - long current_cycle = 0; - long power_cycle = 0; - long power_cycle_first = 0; - long cf_pulses = 0; - long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; - - int byte_counter = 0; - uint8_t *rx_buffer = nullptr; - uint8_t power_invalid = 0; - bool received = false; -} Cse; - -void CseReceived(void) -{ - - - - - - - uint8_t header = Cse.rx_buffer[0]; - if ((header & 0xFC) == 0xFC) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware")); - return; - } - - - if (HLW_UREF_PULSE == Settings.energy_voltage_calibration) { - long voltage_coefficient = 191200; - if (CSE_NOT_CALIBRATED != header) { - voltage_coefficient = Cse.rx_buffer[2] << 16 | Cse.rx_buffer[3] << 8 | Cse.rx_buffer[4]; - } - Settings.energy_voltage_calibration = voltage_coefficient / CSE_UREF; - } - if (HLW_IREF_PULSE == Settings.energy_current_calibration) { - long current_coefficient = 16140; - if (CSE_NOT_CALIBRATED != header) { - current_coefficient = Cse.rx_buffer[8] << 16 | Cse.rx_buffer[9] << 8 | Cse.rx_buffer[10]; - } - Settings.energy_current_calibration = current_coefficient; - } - if (HLW_PREF_PULSE == Settings.energy_power_calibration) { - long power_coefficient = 5364000; - if (CSE_NOT_CALIBRATED != header) { - power_coefficient = Cse.rx_buffer[14] << 16 | Cse.rx_buffer[15] << 8 | Cse.rx_buffer[16]; - } - Settings.energy_power_calibration = power_coefficient / CSE_PREF; - } - - uint8_t adjustement = Cse.rx_buffer[20]; - Cse.voltage_cycle = Cse.rx_buffer[5] << 16 | Cse.rx_buffer[6] << 8 | Cse.rx_buffer[7]; - Cse.current_cycle = Cse.rx_buffer[11] << 16 | Cse.rx_buffer[12] << 8 | Cse.rx_buffer[13]; - Cse.power_cycle = Cse.rx_buffer[17] << 16 | Cse.rx_buffer[18] << 8 | Cse.rx_buffer[19]; - Cse.cf_pulses = Cse.rx_buffer[21] << 8 | Cse.rx_buffer[22]; - - if (Energy.power_on) { - if (adjustement & 0x40) { - Energy.voltage[0] = (float)(Settings.energy_voltage_calibration * CSE_UREF) / (float)Cse.voltage_cycle; - } - if (adjustement & 0x10) { - Cse.power_invalid = 0; - if ((header & 0xF2) == 0xF2) { - Energy.active_power[0] = 0; - } else { - if (0 == Cse.power_cycle_first) { Cse.power_cycle_first = Cse.power_cycle; } - if (Cse.power_cycle_first != Cse.power_cycle) { - Cse.power_cycle_first = -1; - Energy.active_power[0] = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)Cse.power_cycle; - } else { - Energy.active_power[0] = 0; - } - } - } else { - if (Cse.power_invalid < Settings.param[P_CSE7766_INVALID_POWER]) { - Cse.power_invalid++; - } else { - Cse.power_cycle_first = 0; - Energy.active_power[0] = 0; - } - } - if (adjustement & 0x20) { - if (0 == Energy.active_power[0]) { - Energy.current[0] = 0; - } else { - Energy.current[0] = (float)Settings.energy_current_calibration / (float)Cse.current_cycle; - } - } - } else { - Cse.power_cycle_first = 0; - Energy.voltage[0] = 0; - Energy.active_power[0] = 0; - Energy.current[0] = 0; - } -} - -bool CseSerialInput(void) -{ - while (CseSerial->available()) { - yield(); - uint8_t serial_in_byte = CseSerial->read(); - - if (Cse.received) { - Cse.rx_buffer[Cse.byte_counter++] = serial_in_byte; - if (24 == Cse.byte_counter) { - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, Cse.rx_buffer, 24); - - uint8_t checksum = 0; - for (uint32_t i = 2; i < 23; i++) { checksum += Cse.rx_buffer[i]; } - if (checksum == Cse.rx_buffer[23]) { - Energy.data_valid[0] = 0; - CseReceived(); - Cse.received = false; - return true; - } else { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE)); - do { - memmove(Cse.rx_buffer, Cse.rx_buffer +1, 24); - Cse.byte_counter--; - } while ((Cse.byte_counter > 2) && (0x5A != Cse.rx_buffer[1])); - if (0x5A != Cse.rx_buffer[1]) { - Cse.received = false; - Cse.byte_counter = 0; - } - } - } - } else { - if ((0x5A == serial_in_byte) && (1 == Cse.byte_counter)) { - Cse.received = true; - } else { - Cse.byte_counter = 0; - } - Cse.rx_buffer[Cse.byte_counter++] = serial_in_byte; - } - } -} - - - -void CseEverySecond(void) -{ - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { - Cse.voltage_cycle = 0; - Cse.current_cycle = 0; - Cse.power_cycle = 0; - } else { - long cf_frequency = 0; - - if (CSE_PULSES_NOT_INITIALIZED == Cse.cf_pulses_last_time) { - Cse.cf_pulses_last_time = Cse.cf_pulses; - } else { - if (Cse.cf_pulses < Cse.cf_pulses_last_time) { - cf_frequency = (65536 - Cse.cf_pulses_last_time) + Cse.cf_pulses; - } else { - cf_frequency = Cse.cf_pulses - Cse.cf_pulses_last_time; - } - if (cf_frequency && Energy.active_power[0]) { - unsigned long delta = (cf_frequency * Settings.energy_power_calibration) / 36; - - - - if (delta <= (4000*100/36) * 10 ) { - Cse.cf_pulses_last_time = Cse.cf_pulses; - Energy.kWhtoday_delta += delta; - } - else { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow")); - Cse.cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; - } - EnergyUpdateToday(); - } - } - } -} - -void CseSnsInit(void) -{ - - - CseSerial = new TasmotaSerial(pin[GPIO_CSE7766_RX], -1, 1); - if (CseSerial->begin(4800, 2)) { - if (CseSerial->hardwareSerial()) { - SetSerial(4800, TS_SERIAL_8E1); - ClaimSerial(); - } - if (0 == Settings.param[P_CSE7766_INVALID_POWER]) { - Settings.param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; - } - Cse.power_invalid = Settings.param[P_CSE7766_INVALID_POWER]; - } else { - energy_flg = ENERGY_NONE; - } -} - -void CseDrvInit(void) -{ - Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE)); - if (Cse.rx_buffer != nullptr) { - - if (pin[GPIO_CSE7766_RX] < 99) { - energy_flg = XNRG_02; - } - } -} - -bool CseCommand(void) -{ - bool serviced = true; - - if (CMND_POWERSET == Energy.command_code) { - if (XdrvMailbox.data_len && Cse.power_cycle) { - Settings.energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF; - } - } - else if (CMND_VOLTAGESET == Energy.command_code) { - if (XdrvMailbox.data_len && Cse.voltage_cycle) { - Settings.energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF; - } - } - else if (CMND_CURRENTSET == Energy.command_code) { - if (XdrvMailbox.data_len && Cse.current_cycle) { - Settings.energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000; - } - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg02(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_LOOP: - if (CseSerial) { CseSerialInput(); } - break; - case FUNC_ENERGY_EVERY_SECOND: - CseEverySecond(); - break; - case FUNC_COMMAND: - result = CseCommand(); - break; - case FUNC_INIT: - CseSnsInit(); - break; - case FUNC_PRE_INIT: - CseDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_03_pzem004t.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_03_pzem004t.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_PZEM004T -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_03_pzem004t.ino" -#define XNRG_03 3 - -const uint32_t PZEM_STABILIZE = 30; - -#include - -TasmotaSerial *PzemSerial = nullptr; - -#define PZEM_VOLTAGE (uint8_t)0xB0 -#define RESP_VOLTAGE (uint8_t)0xA0 - -#define PZEM_CURRENT (uint8_t)0xB1 -#define RESP_CURRENT (uint8_t)0xA1 - -#define PZEM_POWER (uint8_t)0xB2 -#define RESP_POWER (uint8_t)0xA2 - -#define PZEM_ENERGY (uint8_t)0xB3 -#define RESP_ENERGY (uint8_t)0xA3 - -#define PZEM_SET_ADDRESS (uint8_t)0xB4 -#define RESP_SET_ADDRESS (uint8_t)0xA4 - -#define PZEM_POWER_ALARM (uint8_t)0xB5 -#define RESP_POWER_ALARM (uint8_t)0xA5 - -#define PZEM_DEFAULT_READ_TIMEOUT 500 - - - -struct PZEM { - float energy = 0; - float last_energy = 0; - uint8_t send_retry = 0; - uint8_t read_state = 0; - uint8_t phase = 0; - uint8_t address = 0; -} Pzem; - -struct PZEMCommand { - uint8_t command; - uint8_t addr[4]; - uint8_t data; - uint8_t crc; -}; - -uint8_t PzemCrc(uint8_t *data) -{ - uint16_t crc = 0; - for (uint32_t i = 0; i < sizeof(PZEMCommand) -1; i++) { - crc += *data++; - } - return (uint8_t)(crc & 0xFF); -} - -void PzemSend(uint8_t cmd) -{ - PZEMCommand pzem; - - pzem.command = cmd; - pzem.addr[0] = 192; - pzem.addr[1] = 168; - pzem.addr[2] = 1; - pzem.addr[3] = ((PZEM_SET_ADDRESS == cmd) && Pzem.address) ? Pzem.address : 1 + Pzem.phase; - pzem.data = 0; - - uint8_t *bytes = (uint8_t*)&pzem; - pzem.crc = PzemCrc(bytes); - - PzemSerial->flush(); - PzemSerial->write(bytes, sizeof(pzem)); - - Pzem.address = 0; -} - -bool PzemReceiveReady(void) -{ - return PzemSerial->available() >= (int)sizeof(PZEMCommand); -} - -bool PzemRecieve(uint8_t resp, float *data) -{ -# 124 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_03_pzem004t.ino" - uint8_t buffer[sizeof(PZEMCommand)] = { 0 }; - - unsigned long start = millis(); - uint8_t len = 0; - while ((len < sizeof(PZEMCommand)) && (millis() - start < PZEM_DEFAULT_READ_TIMEOUT)) { - if (PzemSerial->available() > 0) { - uint8_t c = (uint8_t)PzemSerial->read(); - if (!len && ((c & 0xF8) != 0xA0)) { - continue; - } - buffer[len++] = c; - } - } - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, len); - - if (len != sizeof(PZEMCommand)) { - - return false; - } - if (buffer[6] != PzemCrc(buffer)) { - - return false; - } - if (buffer[0] != resp) { - - return false; - } - - switch (resp) { - case RESP_VOLTAGE: - *data = (float)(buffer[1] << 8) + buffer[2] + (buffer[3] / 10.0); - break; - case RESP_CURRENT: - *data = (float)(buffer[1] << 8) + buffer[2] + (buffer[3] / 100.0); - break; - case RESP_POWER: - *data = (float)(buffer[1] << 8) + buffer[2]; - break; - case RESP_ENERGY: - *data = (float)((uint32_t)buffer[1] << 16) + ((uint16_t)buffer[2] << 8) + buffer[3]; - break; - } - return true; -} - - - -const uint8_t pzem_commands[] { PZEM_SET_ADDRESS, PZEM_VOLTAGE, PZEM_CURRENT, PZEM_POWER, PZEM_ENERGY }; -const uint8_t pzem_responses[] { RESP_SET_ADDRESS, RESP_VOLTAGE, RESP_CURRENT, RESP_POWER, RESP_ENERGY }; - -void PzemEvery250ms(void) -{ - bool data_ready = PzemReceiveReady(); - - if (data_ready) { - float value = 0; - if (PzemRecieve(pzem_responses[Pzem.read_state], &value)) { - Energy.data_valid[Pzem.phase] = 0; - switch (Pzem.read_state) { - case 1: - Energy.voltage[Pzem.phase] = value; - break; - case 2: - Energy.current[Pzem.phase] = value; - break; - case 3: - Energy.active_power[Pzem.phase] = value; - break; - case 4: - Pzem.energy += value; - if (Pzem.phase == Energy.phase_count -1) { - if (Pzem.energy > Pzem.last_energy) { - if (uptime > PZEM_STABILIZE) { - EnergyUpdateTotal(Pzem.energy, false); - } - Pzem.last_energy = Pzem.energy; - } - Pzem.energy = 0; - } - break; - } - Pzem.read_state++; - if (5 == Pzem.read_state) { - Pzem.read_state = 1; - } - - - } - } - - if (0 == Pzem.send_retry || data_ready) { - if (1 == Pzem.read_state) { - if (0 == Pzem.phase) { - Pzem.phase = Energy.phase_count -1; - } else { - Pzem.phase--; - } - - - } - - if (Pzem.address) { - Pzem.read_state = 0; - } - - Pzem.send_retry = 5; - PzemSend(pzem_commands[Pzem.read_state]); - } - else { - Pzem.send_retry--; - if ((Energy.phase_count > 1) && (0 == Pzem.send_retry) && (uptime < PZEM_STABILIZE)) { - Energy.phase_count--; - } - } -} - -void PzemSnsInit(void) -{ - - PzemSerial = new TasmotaSerial(pin[GPIO_PZEM004_RX], pin[GPIO_PZEM0XX_TX], 1); - if (PzemSerial->begin(9600)) { - if (PzemSerial->hardwareSerial()) { - ClaimSerial(); - } - Energy.phase_count = 3; - Pzem.phase = 0; - Pzem.read_state = 1; - } else { - energy_flg = ENERGY_NONE; - } -} - -void PzemDrvInit(void) -{ - if ((pin[GPIO_PZEM004_RX] < 99) && (pin[GPIO_PZEM0XX_TX] < 99)) { - energy_flg = XNRG_03; - } -} - -bool PzemCommand(void) -{ - bool serviced = true; - - if (CMND_MODULEADDRESS == Energy.command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4)) { - Pzem.address = XdrvMailbox.payload; - } - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg03(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (PzemSerial && (uptime > 4)) { PzemEvery250ms(); } - break; - case FUNC_COMMAND: - result = PzemCommand(); - break; - case FUNC_INIT: - PzemSnsInit(); - break; - case FUNC_PRE_INIT: - PzemDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_04_mcp39f501.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_04_mcp39f501.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_MCP39F501 - - - - - - - -#define XNRG_04 4 - -#define MCP_BAUDRATE 4800 -#define MCP_TIMEOUT 4 -#define MCP_CALIBRATION_TIMEOUT 2 - -#define MCP_CALIBRATE_POWER 0x001 -#define MCP_CALIBRATE_VOLTAGE 0x002 -#define MCP_CALIBRATE_CURRENT 0x004 -#define MCP_CALIBRATE_FREQUENCY 0x008 -#define MCP_SINGLE_WIRE_FLAG 0x100 - -#define MCP_START_FRAME 0xA5 -#define MCP_ACK_FRAME 0x06 -#define MCP_ERROR_NAK 0x15 -#define MCP_ERROR_CRC 0x51 - -#define MCP_SINGLE_WIRE 0xAB - -#define MCP_SET_ADDRESS 0x41 - -#define MCP_READ 0x4E -#define MCP_READ_16 0x52 -#define MCP_READ_32 0x44 - -#define MCP_WRITE 0x4D -#define MCP_WRITE_16 0x57 -#define MCP_WRITE_32 0x45 - -#define MCP_SAVE_REGISTERS 0x53 - -#define MCP_CALIBRATION_BASE 0x0028 -#define MCP_CALIBRATION_LEN 52 - -#define MCP_FREQUENCY_REF_BASE 0x0094 -#define MCP_FREQUENCY_GAIN_BASE 0x00AE -#define MCP_FREQUENCY_LEN 4 - -#define MCP_BUFFER_SIZE 60 - -#include -TasmotaSerial *McpSerial = nullptr; - -typedef struct mcp_cal_registers_type { - uint16_t gain_current_rms; - uint16_t gain_voltage_rms; - uint16_t gain_active_power; - uint16_t gain_reactive_power; - sint32_t offset_current_rms; - sint32_t offset_active_power; - sint32_t offset_reactive_power; - sint16_t dc_offset_current; - sint16_t phase_compensation; - uint16_t apparent_power_divisor; - - uint32_t system_configuration; - uint16_t dio_configuration; - uint32_t range; - - uint32_t calibration_current; - uint16_t calibration_voltage; - uint32_t calibration_active_power; - uint32_t calibration_reactive_power; - uint16_t accumulation_interval; -} mcp_cal_registers_type; - -char *mcp_buffer = nullptr; -unsigned long mcp_window = 0; -unsigned long mcp_kWhcounter = 0; -uint32_t mcp_system_configuration = 0x03000000; -uint32_t mcp_active_power; - - -uint32_t mcp_current_rms; -uint16_t mcp_voltage_rms; -uint16_t mcp_line_frequency; - -uint8_t mcp_address = 0; -uint8_t mcp_calibration_active = 0; -uint8_t mcp_init = 0; -uint8_t mcp_timeout = 0; -uint8_t mcp_calibrate = 0; -uint8_t mcp_byte_counter = 0; - - - - - - -uint8_t McpChecksum(uint8_t *data) -{ - uint8_t checksum = 0; - uint8_t offset = 0; - uint8_t len = data[1] -1; - - for (uint32_t i = offset; i < len; i++) { checksum += data[i]; } - return checksum; -} - -unsigned long McpExtractInt(char *data, uint8_t offset, uint8_t size) -{ - unsigned long result = 0; - unsigned long pow = 1; - - for (uint32_t i = 0; i < size; i++) { - result = result + (uint8_t)data[offset + i] * pow; - pow = pow * 256; - } - return result; -} - -void McpSetInt(unsigned long value, uint8_t *data, uint8_t offset, size_t size) -{ - for (uint32_t i = 0; i < size; i++) { - data[offset + i] = ((value >> (i * 8)) & 0xFF); - } -} - -void McpSend(uint8_t *data) -{ - if (mcp_timeout) { return; } - mcp_timeout = MCP_TIMEOUT; - - data[0] = MCP_START_FRAME; - data[data[1] -1] = McpChecksum(data); - - - - for (uint32_t i = 0; i < data[1]; i++) { - McpSerial->write(data[i]); - } -} - - - -void McpGetAddress(void) -{ - uint8_t data[] = { MCP_START_FRAME, 7, MCP_SET_ADDRESS, 0x00, 0x26, MCP_READ_16, 0x00 }; - - McpSend(data); -} - -void McpAddressReceive(void) -{ - - mcp_address = mcp_buffer[3]; -} - - - -void McpGetCalibration(void) -{ - if (mcp_calibration_active) { return; } - mcp_calibration_active = MCP_CALIBRATION_TIMEOUT; - - uint8_t data[] = { MCP_START_FRAME, 8, MCP_SET_ADDRESS, (MCP_CALIBRATION_BASE >> 8) & 0xFF, MCP_CALIBRATION_BASE & 0xFF, MCP_READ, MCP_CALIBRATION_LEN, 0x00 }; - - McpSend(data); -} - -void McpParseCalibration(void) -{ - bool action = false; - mcp_cal_registers_type cal_registers; - - - cal_registers.gain_current_rms = McpExtractInt(mcp_buffer, 2, 2); - cal_registers.gain_voltage_rms = McpExtractInt(mcp_buffer, 4, 2); - cal_registers.gain_active_power = McpExtractInt(mcp_buffer, 6, 2); - cal_registers.gain_reactive_power = McpExtractInt(mcp_buffer, 8, 2); - cal_registers.offset_current_rms = McpExtractInt(mcp_buffer, 10, 4); - cal_registers.offset_active_power = McpExtractInt(mcp_buffer, 14, 4); - cal_registers.offset_reactive_power = McpExtractInt(mcp_buffer, 18, 4); - cal_registers.dc_offset_current = McpExtractInt(mcp_buffer, 22, 2); - cal_registers.phase_compensation = McpExtractInt(mcp_buffer, 24, 2); - cal_registers.apparent_power_divisor = McpExtractInt(mcp_buffer, 26, 2); - - cal_registers.system_configuration = McpExtractInt(mcp_buffer, 28, 4); - cal_registers.dio_configuration = McpExtractInt(mcp_buffer, 32, 2); - cal_registers.range = McpExtractInt(mcp_buffer, 34, 4); - - cal_registers.calibration_current = McpExtractInt(mcp_buffer, 38, 4); - cal_registers.calibration_voltage = McpExtractInt(mcp_buffer, 42, 2); - cal_registers.calibration_active_power = McpExtractInt(mcp_buffer, 44, 4); - cal_registers.calibration_reactive_power = McpExtractInt(mcp_buffer, 48, 4); - cal_registers.accumulation_interval = McpExtractInt(mcp_buffer, 52, 2); - - if (mcp_calibrate & MCP_CALIBRATE_POWER) { - cal_registers.calibration_active_power = Settings.energy_power_calibration; - if (McpCalibrationCalc(&cal_registers, 16)) { action = true; } - } - if (mcp_calibrate & MCP_CALIBRATE_VOLTAGE) { - cal_registers.calibration_voltage = Settings.energy_voltage_calibration; - if (McpCalibrationCalc(&cal_registers, 0)) { action = true; } - } - if (mcp_calibrate & MCP_CALIBRATE_CURRENT) { - cal_registers.calibration_current = Settings.energy_current_calibration; - if (McpCalibrationCalc(&cal_registers, 8)) { action = true; } - } - mcp_timeout = 0; - if (action) { McpSetCalibration(&cal_registers); } - - mcp_calibrate = 0; - - Settings.energy_power_calibration = cal_registers.calibration_active_power; - Settings.energy_voltage_calibration = cal_registers.calibration_voltage; - Settings.energy_current_calibration = cal_registers.calibration_current; - - mcp_system_configuration = cal_registers.system_configuration; - - if (mcp_system_configuration & MCP_SINGLE_WIRE_FLAG) { - mcp_system_configuration &= ~MCP_SINGLE_WIRE_FLAG; - McpSetSystemConfiguration(2); - } -} - -bool McpCalibrationCalc(struct mcp_cal_registers_type *cal_registers, uint8_t range_shift) -{ - uint32_t measured; - uint32_t expected; - uint16_t *gain; - uint32_t new_gain; - - if (range_shift == 0) { - measured = mcp_voltage_rms; - expected = cal_registers->calibration_voltage; - gain = &(cal_registers->gain_voltage_rms); - } else if (range_shift == 8) { - measured = mcp_current_rms; - expected = cal_registers->calibration_current; - gain = &(cal_registers->gain_current_rms); - } else if (range_shift == 16) { - measured = mcp_active_power; - expected = cal_registers->calibration_active_power; - gain = &(cal_registers->gain_active_power); - } else { - return false; - } - - if (measured == 0) { - return false; - } - - uint32_t range = (cal_registers->range >> range_shift) & 0xFF; - -calc: - new_gain = (*gain) * expected / measured; - - if (new_gain < 25000) { - range++; - if (measured > 6) { - measured = measured / 2; - goto calc; - } - } - - if (new_gain > 55000) { - range--; - measured = measured * 2; - goto calc; - } - - *gain = new_gain; - uint32_t old_range = (cal_registers->range >> range_shift) & 0xFF; - cal_registers->range = cal_registers->range ^ (old_range << range_shift); - cal_registers->range = cal_registers->range | (range << range_shift); - - return true; -} - - - - - - -void McpSetCalibration(struct mcp_cal_registers_type *cal_registers) -{ - uint8_t data[7 + MCP_CALIBRATION_LEN + 2 + 1]; - - data[1] = sizeof(data); - data[2] = MCP_SET_ADDRESS; - data[3] = (MCP_CALIBRATION_BASE >> 8) & 0xFF; - data[4] = (MCP_CALIBRATION_BASE >> 0) & 0xFF; - - data[5] = MCP_WRITE; - data[6] = MCP_CALIBRATION_LEN; - - McpSetInt(cal_registers->gain_current_rms, data, 0+7, 2); - McpSetInt(cal_registers->gain_voltage_rms, data, 2+7, 2); - McpSetInt(cal_registers->gain_active_power, data, 4+7, 2); - McpSetInt(cal_registers->gain_reactive_power, data, 6+7, 2); - McpSetInt(cal_registers->offset_current_rms, data, 8+7, 4); - McpSetInt(cal_registers->offset_active_power, data, 12+7, 4); - McpSetInt(cal_registers->offset_reactive_power, data, 16+7, 4); - McpSetInt(cal_registers->dc_offset_current, data, 20+7, 2); - McpSetInt(cal_registers->phase_compensation, data, 22+7, 2); - McpSetInt(cal_registers->apparent_power_divisor, data, 24+7, 2); - - McpSetInt(cal_registers->system_configuration, data, 26+7, 4); - McpSetInt(cal_registers->dio_configuration, data, 30+7, 2); - McpSetInt(cal_registers->range, data, 32+7, 4); - - McpSetInt(cal_registers->calibration_current, data, 36+7, 4); - McpSetInt(cal_registers->calibration_voltage, data, 40+7, 2); - McpSetInt(cal_registers->calibration_active_power, data, 42+7, 4); - McpSetInt(cal_registers->calibration_reactive_power, data, 46+7, 4); - McpSetInt(cal_registers->accumulation_interval, data, 50+7, 2); - - data[MCP_CALIBRATION_LEN+7] = MCP_SAVE_REGISTERS; - data[MCP_CALIBRATION_LEN+8] = mcp_address; - - McpSend(data); -} - - - -void McpSetSystemConfiguration(uint16 interval) -{ - - uint8_t data[17]; - - data[ 1] = sizeof(data); - data[ 2] = MCP_SET_ADDRESS; - data[ 3] = 0x00; - data[ 4] = 0x42; - data[ 5] = MCP_WRITE_32; - data[ 6] = (mcp_system_configuration >> 24) & 0xFF; - data[ 7] = (mcp_system_configuration >> 16) & 0xFF; - data[ 8] = (mcp_system_configuration >> 8) & 0xFF; - data[ 9] = (mcp_system_configuration >> 0) & 0xFF; - data[10] = MCP_SET_ADDRESS; - data[11] = 0x00; - data[12] = 0x5A; - data[13] = MCP_WRITE_16; - data[14] = (interval >> 8) & 0xFF; - data[15] = (interval >> 0) & 0xFF; - - McpSend(data); -} - - - -void McpGetFrequency(void) -{ - if (mcp_calibration_active) { return; } - mcp_calibration_active = MCP_CALIBRATION_TIMEOUT; - - uint8_t data[] = { MCP_START_FRAME, 11, MCP_SET_ADDRESS, (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF, MCP_FREQUENCY_REF_BASE & 0xFF, MCP_READ_16, - MCP_SET_ADDRESS, (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF, MCP_FREQUENCY_GAIN_BASE & 0xFF, MCP_READ_16, 0x00 }; - - McpSend(data); -} - -void McpParseFrequency(void) -{ - - uint16_t line_frequency_ref = mcp_buffer[2] * 256 + mcp_buffer[3]; - uint16_t gain_line_frequency = mcp_buffer[4] * 256 + mcp_buffer[5]; - - if (mcp_calibrate & MCP_CALIBRATE_FREQUENCY) { - line_frequency_ref = Settings.energy_frequency_calibration; - - if ((0xFFFF == mcp_line_frequency) || (0 == gain_line_frequency)) { - mcp_line_frequency = 50000; - gain_line_frequency = 0x8000; - } - gain_line_frequency = gain_line_frequency * line_frequency_ref / mcp_line_frequency; - - mcp_timeout = 0; - McpSetFrequency(line_frequency_ref, gain_line_frequency); - } - - Settings.energy_frequency_calibration = line_frequency_ref; - - mcp_calibrate = 0; -} - -void McpSetFrequency(uint16_t line_frequency_ref, uint16_t gain_line_frequency) -{ - - uint8_t data[17]; - - data[ 1] = sizeof(data); - data[ 2] = MCP_SET_ADDRESS; - data[ 3] = (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF; - data[ 4] = (MCP_FREQUENCY_REF_BASE >> 0) & 0xFF; - - data[ 5] = MCP_WRITE_16; - data[ 6] = (line_frequency_ref >> 8) & 0xFF; - data[ 7] = (line_frequency_ref >> 0) & 0xFF; - - data[ 8] = MCP_SET_ADDRESS; - data[ 9] = (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF; - data[10] = (MCP_FREQUENCY_GAIN_BASE >> 0) & 0xFF; - - data[11] = MCP_WRITE_16; - data[12] = (gain_line_frequency >> 8) & 0xFF; - data[13] = (gain_line_frequency >> 0) & 0xFF; - - data[14] = MCP_SAVE_REGISTERS; - data[15] = mcp_address; - - McpSend(data); -} - - - -void McpGetData(void) -{ - uint8_t data[] = { MCP_START_FRAME, 8, MCP_SET_ADDRESS, 0x00, 0x04, MCP_READ, 22, 0x00 }; - - McpSend(data); -} - -void McpParseData(void) -{ - - - - - - mcp_current_rms = McpExtractInt(mcp_buffer, 2, 4); - mcp_voltage_rms = McpExtractInt(mcp_buffer, 6, 2); - mcp_active_power = McpExtractInt(mcp_buffer, 8, 4); - - - mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2); - - if (Energy.power_on) { - Energy.data_valid[0] = 0; - Energy.frequency[0] = (float)mcp_line_frequency / 1000; - Energy.voltage[0] = (float)mcp_voltage_rms / 10; - Energy.active_power[0] = (float)mcp_active_power / 100; - if (0 == Energy.active_power[0]) { - Energy.current[0] = 0; - } else { - Energy.current[0] = (float)mcp_current_rms / 10000; - } - } else { - Energy.data_valid[0] = ENERGY_WATCHDOG; - } -} - - - -void McpSerialInput(void) -{ - while ((McpSerial->available()) && (mcp_byte_counter < MCP_BUFFER_SIZE)) { - yield(); - mcp_buffer[mcp_byte_counter++] = McpSerial->read(); - mcp_window = millis(); - } - - - if ((mcp_byte_counter) && (millis() - mcp_window > (24000 / MCP_BAUDRATE) +1)) { - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)mcp_buffer, mcp_byte_counter); - - if (MCP_BUFFER_SIZE == mcp_byte_counter) { - - } - else if (1 == mcp_byte_counter) { - if (MCP_ERROR_CRC == mcp_buffer[0]) { - - mcp_timeout = 0; - } - else if (MCP_ERROR_NAK == mcp_buffer[0]) { - - mcp_timeout = 0; - } - } - else if (MCP_ACK_FRAME == mcp_buffer[0]) { - if (mcp_byte_counter == mcp_buffer[1]) { - - if (McpChecksum((uint8_t *)mcp_buffer) != mcp_buffer[mcp_byte_counter -1]) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); - } else { - if (5 == mcp_buffer[1]) { McpAddressReceive(); } - if (25 == mcp_buffer[1]) { McpParseData(); } - if (MCP_CALIBRATION_LEN + 3 == mcp_buffer[1]) { McpParseCalibration(); } - if (MCP_FREQUENCY_LEN + 3 == mcp_buffer[1]) { McpParseFrequency(); } - } - - } - mcp_timeout = 0; - } - else if (MCP_SINGLE_WIRE == mcp_buffer[0]) { - mcp_timeout = 0; - } - - mcp_byte_counter = 0; - McpSerial->flush(); - } -} - - - -void McpEverySecond(void) -{ - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { - mcp_voltage_rms = 0; - mcp_current_rms = 0; - mcp_active_power = 0; - mcp_line_frequency = 0; - } - - if (mcp_active_power) { - Energy.kWhtoday_delta += ((mcp_active_power * 10) / 36); - EnergyUpdateToday(); - } - - if (mcp_timeout) { - mcp_timeout--; - } - else if (mcp_calibration_active) { - mcp_calibration_active--; - } - else if (mcp_init) { - if (2 == mcp_init) { - McpGetCalibration(); - } - else if (1 == mcp_init) { - McpGetFrequency(); - } - mcp_init--; - } - else if (!mcp_address) { - McpGetAddress(); - } - else { - McpGetData(); - } -} - -void McpSnsInit(void) -{ - - McpSerial = new TasmotaSerial(pin[GPIO_MCP39F5_RX], pin[GPIO_MCP39F5_TX], 1); - if (McpSerial->begin(MCP_BAUDRATE)) { - if (McpSerial->hardwareSerial()) { - ClaimSerial(); - mcp_buffer = serial_in_buffer; - } else { - mcp_buffer = (char*)(malloc(MCP_BUFFER_SIZE)); - } - DigitalWrite(GPIO_MCP39F5_RST, 1); - } else { - energy_flg = ENERGY_NONE; - } -} - -void McpDrvInit(void) -{ - if ((pin[GPIO_MCP39F5_RX] < 99) && (pin[GPIO_MCP39F5_TX] < 99)) { - if (pin[GPIO_MCP39F5_RST] < 99) { - pinMode(pin[GPIO_MCP39F5_RST], OUTPUT); - digitalWrite(pin[GPIO_MCP39F5_RST], 0); - } - mcp_calibrate = 0; - mcp_timeout = 2; - mcp_init = 2; - energy_flg = XNRG_04; - } -} - -bool McpCommand(void) -{ - bool serviced = true; - unsigned long value = 0; - - if (CMND_POWERSET == Energy.command_code) { - if (XdrvMailbox.data_len && mcp_active_power) { - value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100); - if ((value > 100) && (value < 200000)) { - Settings.energy_power_calibration = value; - mcp_calibrate |= MCP_CALIBRATE_POWER; - McpGetCalibration(); - } - } - } - else if (CMND_VOLTAGESET == Energy.command_code) { - if (XdrvMailbox.data_len && mcp_voltage_rms) { - value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); - if ((value > 1000) && (value < 2600)) { - Settings.energy_voltage_calibration = value; - mcp_calibrate |= MCP_CALIBRATE_VOLTAGE; - McpGetCalibration(); - } - } - } - else if (CMND_CURRENTSET == Energy.command_code) { - if (XdrvMailbox.data_len && mcp_current_rms) { - value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); - if ((value > 100) && (value < 80000)) { - Settings.energy_current_calibration = value; - mcp_calibrate |= MCP_CALIBRATE_CURRENT; - McpGetCalibration(); - } - } - } - else if (CMND_FREQUENCYSET == Energy.command_code) { - if (XdrvMailbox.data_len && mcp_line_frequency) { - value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000); - if ((value > 45000) && (value < 65000)) { - Settings.energy_frequency_calibration = value; - mcp_calibrate |= MCP_CALIBRATE_FREQUENCY; - McpGetFrequency(); - } - } - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg04(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_LOOP: - if (McpSerial) { McpSerialInput(); } - break; - case FUNC_ENERGY_EVERY_SECOND: - if (McpSerial) { McpEverySecond(); } - break; - case FUNC_COMMAND: - result = McpCommand(); - break; - case FUNC_INIT: - McpSnsInit(); - break; - case FUNC_PRE_INIT: - McpDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_05_pzem_ac.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_05_pzem_ac.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_PZEM_AC -# 33 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_05_pzem_ac.ino" -#define XNRG_05 5 - -const uint8_t PZEM_AC_DEVICE_ADDRESS = 0x01; -const uint32_t PZEM_AC_STABILIZE = 30; - -#include -TasmotaModbus *PzemAcModbus; - -struct PZEMAC { - float energy = 0; - float last_energy = 0; - uint8_t send_retry = 0; - uint8_t phase = 0; - uint8_t address = 0; - uint8_t address_step = ADDR_IDLE; -} PzemAc; - -void PzemAcEverySecond(void) -{ - bool data_ready = PzemAcModbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[30]; - - uint8_t registers = 10; - if (ADDR_RECEIVE == PzemAc.address_step) { - registers = 2; - PzemAc.address_step--; - } - uint8_t error = PzemAcModbus->ReceiveBuffer(buffer, registers); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, PzemAcModbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PAC: PzemAc %d error %d"), PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, error); - } else { - Energy.data_valid[PzemAc.phase] = 0; - if (10 == registers) { - - - - - - Energy.voltage[PzemAc.phase] = (float)((buffer[3] << 8) + buffer[4]) / 10.0; - Energy.current[PzemAc.phase] = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0; - Energy.active_power[PzemAc.phase] = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0; - Energy.frequency[PzemAc.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0; - Energy.power_factor[PzemAc.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0; - - PzemAc.energy += (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]); - if (PzemAc.phase == Energy.phase_count -1) { - if (PzemAc.energy > PzemAc.last_energy) { - if (uptime > PZEM_AC_STABILIZE) { - EnergyUpdateTotal(PzemAc.energy, false); - } - PzemAc.last_energy = PzemAc.energy; - } - PzemAc.energy = 0; - } - - } - } - } - - if (0 == PzemAc.send_retry || data_ready) { - if (0 == PzemAc.phase) { - PzemAc.phase = Energy.phase_count -1; - } else { - PzemAc.phase--; - } - PzemAc.send_retry = ENERGY_WATCHDOG; - if (ADDR_SEND == PzemAc.address_step) { - PzemAcModbus->Send(0xF8, 0x06, 0x0002, (uint16_t)PzemAc.address); - PzemAc.address_step--; - } else { - PzemAcModbus->Send(PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, 0x04, 0, 10); - } - } - else { - PzemAc.send_retry--; - if ((Energy.phase_count > 1) && (0 == PzemAc.send_retry) && (uptime < PZEM_AC_STABILIZE)) { - Energy.phase_count--; - } - } -} - -void PzemAcSnsInit(void) -{ - PzemAcModbus = new TasmotaModbus(pin[GPIO_PZEM016_RX], pin[GPIO_PZEM0XX_TX]); - uint8_t result = PzemAcModbus->Begin(9600); - if (result) { - if (2 == result) { ClaimSerial(); } - Energy.phase_count = 3; - PzemAc.phase = 0; - } else { - energy_flg = ENERGY_NONE; - } -} - -void PzemAcDrvInit(void) -{ - if ((pin[GPIO_PZEM016_RX] < 99) && (pin[GPIO_PZEM0XX_TX] < 99)) { - energy_flg = XNRG_05; - } -} - -bool PzemAcCommand(void) -{ - bool serviced = true; - - if (CMND_MODULEADDRESS == Energy.command_code) { - PzemAc.address = XdrvMailbox.payload; - PzemAc.address_step = ADDR_SEND; - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg05(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_ENERGY_EVERY_SECOND: - if (uptime > 4) { PzemAcEverySecond(); } - break; - case FUNC_COMMAND: - result = PzemAcCommand(); - break; - case FUNC_INIT: - PzemAcSnsInit(); - break; - case FUNC_PRE_INIT: - PzemAcDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_06_pzem_dc.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_06_pzem_dc.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_PZEM_DC -# 32 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_06_pzem_dc.ino" -#define XNRG_06 6 - -const uint8_t PZEM_DC_DEVICE_ADDRESS = 0x01; -const uint32_t PZEM_DC_STABILIZE = 30; - -#include -TasmotaModbus *PzemDcModbus; - -struct PZEMDC { - float energy = 0; - float last_energy = 0; - uint8_t send_retry = 0; - uint8_t channel = 0; - uint8_t address = 0; - uint8_t address_step = ADDR_IDLE; -} PzemDc; - -void PzemDcEverySecond(void) -{ - bool data_ready = PzemDcModbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[26]; - - uint8_t registers = 8; - if (ADDR_RECEIVE == PzemDc.address_step) { - registers = 2; - PzemDc.address_step--; - } - uint8_t error = PzemDcModbus->ReceiveBuffer(buffer, registers); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, PzemDcModbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PDC: PzemDc %d error %d"), PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, error); - } else { - Energy.data_valid[PzemDc.channel] = 0; - if (8 == registers) { - - - - - - Energy.voltage[PzemDc.channel] = (float)((buffer[3] << 8) + buffer[4]) / 100.0; - Energy.current[PzemDc.channel] = (float)((buffer[5] << 8) + buffer[6]) / 100.0; - Energy.active_power[PzemDc.channel] = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0; - - PzemDc.energy += (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]); - if (PzemDc.channel == Energy.phase_count -1) { - if (PzemDc.energy > PzemDc.last_energy) { - if (uptime > PZEM_DC_STABILIZE) { - EnergyUpdateTotal(PzemDc.energy, false); - } - PzemDc.last_energy = PzemDc.energy; - } - PzemDc.energy = 0; - } - } - } - } - - if (0 == PzemDc.send_retry || data_ready) { - if (0 == PzemDc.channel) { - PzemDc.channel = Energy.phase_count -1; - } else { - PzemDc.channel--; - } - PzemDc.send_retry = ENERGY_WATCHDOG; - if (ADDR_SEND == PzemDc.address_step) { - PzemDcModbus->Send(0xF8, 0x06, 0x0002, (uint16_t)PzemDc.address); - PzemDc.address_step--; - } else { - PzemDcModbus->Send(PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, 0x04, 0, 8); - } - } - else { - PzemDc.send_retry--; - if ((Energy.phase_count > 1) && (0 == PzemDc.send_retry) && (uptime < PZEM_DC_STABILIZE)) { - Energy.phase_count--; - } - } -} - -void PzemDcSnsInit(void) -{ - PzemDcModbus = new TasmotaModbus(pin[GPIO_PZEM017_RX], pin[GPIO_PZEM0XX_TX]); - uint8_t result = PzemDcModbus->Begin(9600, 2); - if (result) { - if (2 == result) { ClaimSerial(); } - Energy.type_dc = true; - Energy.phase_count = 3; - PzemDc.channel = 0; - } else { - energy_flg = ENERGY_NONE; - } -} - -void PzemDcDrvInit(void) -{ - if ((pin[GPIO_PZEM017_RX] < 99) && (pin[GPIO_PZEM0XX_TX] < 99)) { - energy_flg = XNRG_06; - } -} - -bool PzemDcCommand(void) -{ - bool serviced = true; - - if (CMND_MODULEADDRESS == Energy.command_code) { - PzemDc.address = XdrvMailbox.payload; - PzemDc.address_step = ADDR_SEND; - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg06(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_ENERGY_EVERY_SECOND: - if (uptime > 4) { PzemDcEverySecond(); } - break; - case FUNC_COMMAND: - result = PzemDcCommand(); - break; - case FUNC_INIT: - PzemDcSnsInit(); - break; - case FUNC_PRE_INIT: - PzemDcDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_07_ade7953.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_07_ade7953.ino" -#ifdef USE_I2C -#ifdef USE_ENERGY_SENSOR -#ifdef USE_ADE7953 -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_07_ade7953.ino" -#define XNRG_07 7 -#define XI2C_07 7 - -#define ADE7953_PREF 1540 -#define ADE7953_UREF 26000 -#define ADE7953_IREF 10000 - -#define ADE7953_ADDR 0x38 - -const uint16_t Ade7953Registers[] { - 0x31B, - 0x313, - 0x311, - 0x315, - 0x31A, - 0x312, - 0x310, - 0x314, - 0x31C, - 0x10E -}; - -struct Ade7953 { - uint32_t voltage_rms = 0; - uint32_t period = 0; - uint32_t current_rms[2] = { 0, 0 }; - uint32_t active_power[2] = { 0, 0 }; - uint8_t init_step = 0; -} Ade7953; - -int Ade7953RegSize(uint16_t reg) -{ - int size = 0; - switch ((reg >> 8) & 0x0F) { - case 0x03: - size++; - case 0x02: - size++; - case 0x01: - size++; - case 0x00: - case 0x07: - case 0x08: - size++; - } - return size; -} - -void Ade7953Write(uint16_t reg, uint32_t val) -{ - int size = Ade7953RegSize(reg); - if (size) { - Wire.beginTransmission(ADE7953_ADDR); - Wire.write((reg >> 8) & 0xFF); - Wire.write(reg & 0xFF); - while (size--) { - Wire.write((val >> (8 * size)) & 0xFF); - } - Wire.endTransmission(); - delayMicroseconds(5); - } -} - -int32_t Ade7953Read(uint16_t reg) -{ - uint32_t response = 0; - - int size = Ade7953RegSize(reg); - if (size) { - Wire.beginTransmission(ADE7953_ADDR); - Wire.write((reg >> 8) & 0xFF); - Wire.write(reg & 0xFF); - Wire.endTransmission(0); - Wire.requestFrom(ADE7953_ADDR, size); - if (size <= Wire.available()) { - for (uint32_t i = 0; i < size; i++) { - response = response << 8 | Wire.read(); - } - } - } - return response; -} - -void Ade7953Init(void) -{ - Ade7953Write(0x102, 0x0004); - Ade7953Write(0x0FE, 0x00AD); - Ade7953Write(0x120, 0x0030); -} - -void Ade7953GetData(void) -{ - int32_t reg[2][4]; - for (uint32_t i = 0; i < sizeof(Ade7953Registers)/sizeof(uint16_t); i++) { - int32_t value = Ade7953Read(Ade7953Registers[i]); - if (8 == i) { - Ade7953.voltage_rms = value; - } else if (9 == i) { - Ade7953.period = value; - } else { - reg[i >> 2][i &3] = value; - } - } - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: %d, %d, [%d, %d, %d, %d], [%d, %d, %d, %d]"), - Ade7953.voltage_rms, Ade7953.period, - reg[0][0], reg[0][1], reg[0][2], reg[0][3], - reg[1][0], reg[1][1], reg[1][2], reg[1][3]); - - uint32_t apparent_power[2] = { 0, 0 }; - uint32_t reactive_power[2] = { 0, 0 }; - - for (uint32_t channel = 0; channel < 2; channel++) { - Ade7953.current_rms[channel] = reg[channel][0]; - if (Ade7953.current_rms[channel] < 2000) { - Ade7953.current_rms[channel] = 0; - Ade7953.active_power[channel] = 0; - } else { - Ade7953.active_power[channel] = abs(reg[channel][1]); - apparent_power[channel] = abs(reg[channel][2]); - reactive_power[channel] = abs(reg[channel][3]); - } - } - - uint32_t current_rms_sum = Ade7953.current_rms[0] + Ade7953.current_rms[1]; - uint32_t active_power_sum = Ade7953.active_power[0] + Ade7953.active_power[1]; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ADE: U %d, C %d, I %d + %d = %d, P %d + %d = %d"), - Ade7953.voltage_rms, Ade7953.period, - Ade7953.current_rms[0], Ade7953.current_rms[1], current_rms_sum, - Ade7953.active_power[0], Ade7953.active_power[1], active_power_sum); - - if (Energy.power_on) { - Energy.voltage[0] = (float)Ade7953.voltage_rms / Settings.energy_voltage_calibration; - Energy.frequency[0] = 223750.0f / ( (float)Ade7953.period + 1); - - for (uint32_t channel = 0; channel < 2; channel++) { - Energy.data_valid[channel] = 0; - Energy.active_power[channel] = (float)Ade7953.active_power[channel] / (Settings.energy_power_calibration / 10); - Energy.reactive_power[channel] = (float)reactive_power[channel] / (Settings.energy_power_calibration / 10); - Energy.apparent_power[channel] = (float)apparent_power[channel] / (Settings.energy_power_calibration / 10); - if (0 == Energy.active_power[channel]) { - Energy.current[channel] = 0; - } else { - Energy.current[channel] = (float)Ade7953.current_rms[channel] / (Settings.energy_current_calibration * 10); - } - } - } else { - Energy.data_valid[0] = ENERGY_WATCHDOG; - Energy.data_valid[1] = ENERGY_WATCHDOG; - } - - if (active_power_sum) { - Energy.kWhtoday_delta += ((active_power_sum * (100000 / (Settings.energy_power_calibration / 10))) / 3600); - EnergyUpdateToday(); - } -} - -void Ade7953EnergyEverySecond(void) -{ - if (Ade7953.init_step) { - if (1 == Ade7953.init_step) { - Ade7953Init(); - } - Ade7953.init_step--; - } else { - Ade7953GetData(); - } -} - -void Ade7953DrvInit(void) -{ - if (pin[GPIO_ADE7953_IRQ] < 99) { - delay(100); - if (I2cSetDevice(ADE7953_ADDR)) { - if (HLW_PREF_PULSE == Settings.energy_power_calibration) { - Settings.energy_power_calibration = ADE7953_PREF; - Settings.energy_voltage_calibration = ADE7953_UREF; - Settings.energy_current_calibration = ADE7953_IREF; - } - I2cSetActiveFound(ADE7953_ADDR, "ADE7953"); - Ade7953.init_step = 2; - - Energy.phase_count = 2; - Energy.voltage_common = true; - - energy_flg = XNRG_07; - } - } -} - -bool Ade7953Command(void) -{ - bool serviced = true; - - uint32_t channel = (2 == XdrvMailbox.index) ? 1 : 0; - uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); - - if (CMND_POWERCAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; } - - } - else if (CMND_VOLTAGECAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_UREF; } - - } - else if (CMND_CURRENTCAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_IREF; } - - } - else if (CMND_POWERSET == Energy.command_code) { - if (XdrvMailbox.data_len && Ade7953.active_power[channel]) { - if ((value > 100) && (value < 200000)) { - Settings.energy_power_calibration = (Ade7953.active_power[channel] * 1000) / value; - } - } - } - else if (CMND_VOLTAGESET == Energy.command_code) { - if (XdrvMailbox.data_len && Ade7953.voltage_rms) { - if ((value > 10000) && (value < 26000)) { - Settings.energy_voltage_calibration = (Ade7953.voltage_rms * 100) / value; - } - } - } - else if (CMND_CURRENTSET == Energy.command_code) { - if (XdrvMailbox.data_len && Ade7953.current_rms[channel]) { - if ((value > 2000) && (value < 1000000)) { - Settings.energy_current_calibration = ((Ade7953.current_rms[channel] * 100) / value) * 100; - } - } - } - else serviced = false; - - return serviced; -} - - - - - -bool Xnrg07(uint8_t function) -{ - if (!I2cEnabled(XI2C_07)) { return false; } - - bool result = false; - - switch (function) { - case FUNC_ENERGY_EVERY_SECOND: - Ade7953EnergyEverySecond(); - break; - case FUNC_COMMAND: - result = Ade7953Command(); - break; - case FUNC_PRE_INIT: - Ade7953DrvInit(); - break; - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_08_sdm120.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_08_sdm120.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_SDM120 - - - - - - -#define XNRG_08 8 - - -#ifndef SDM120_SPEED - #define SDM120_SPEED 2400 -#endif - -#ifndef SDM120_ADDR - #define SDM120_ADDR 1 -#endif - -#include -TasmotaModbus *Sdm120Modbus; - -const uint8_t sdm120_table = 8; -const uint8_t sdm220_table = 13; - -const uint16_t sdm120_start_addresses[] { - 0x0000, - 0x0006, - 0x000C, - 0x0012, - 0x0018, - 0x001E, - 0x0046, - 0x0156, - - 0X0048, - 0X004A, - 0X004C, - 0X004E, - 0X0024 -}; - -struct SDM120 { - float total_active = 0; - float import_active = NAN; - float import_reactive = 0; - float export_reactive = 0; - float phase_angle = 0; - uint8_t read_state = 0; - uint8_t send_retry = 0; - uint8_t start_address_count = sdm220_table; -} Sdm120; - - - -void SDM120Every250ms(void) -{ - bool data_ready = Sdm120Modbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[14]; - - uint32_t error = Sdm120Modbus->ReceiveBuffer(buffer, 2); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, Sdm120Modbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: SDM120 error %d"), error); - } else { - Energy.data_valid[0] = 0; - - - - - float value; - ((uint8_t*)&value)[3] = buffer[3]; - ((uint8_t*)&value)[2] = buffer[4]; - ((uint8_t*)&value)[1] = buffer[5]; - ((uint8_t*)&value)[0] = buffer[6]; - - switch(Sdm120.read_state) { - case 0: - Energy.voltage[0] = value; - break; - - case 1: - Energy.current[0] = value; - break; - - case 2: - Energy.active_power[0] = value; - break; - - case 3: - Energy.apparent_power[0] = value; - break; - - case 4: - Energy.reactive_power[0] = value; - break; - - case 5: - Energy.power_factor[0] = value; - break; - - case 6: - Energy.frequency[0] = value; - break; - - case 7: - Sdm120.total_active = value; - break; - - case 8: - Sdm120.import_active = value; - break; - - case 9: - Energy.export_active = value; - break; - - case 10: - Sdm120.import_reactive = value; - break; - - case 11: - Sdm120.export_reactive = value; - break; - - case 12: - Sdm120.phase_angle = value; - break; - } - - Sdm120.read_state++; - if (Sdm120.read_state == Sdm120.start_address_count) { - Sdm120.read_state = 0; - - if (Sdm120.start_address_count > sdm120_table) { - if (!isnan(Sdm120.import_active)) { - Sdm120.total_active = Sdm120.import_active; - } else { - Sdm120.start_address_count = sdm120_table; - } - } - EnergyUpdateTotal(Sdm120.total_active, true); - } - } - } - - if (0 == Sdm120.send_retry || data_ready) { - Sdm120.send_retry = 5; - Sdm120Modbus->Send(SDM120_ADDR, 0x04, sdm120_start_addresses[Sdm120.read_state], 2); - } else { - Sdm120.send_retry--; - } -} - -void Sdm120SnsInit(void) -{ - Sdm120Modbus = new TasmotaModbus(pin[GPIO_SDM120_RX], pin[GPIO_SDM120_TX]); - uint8_t result = Sdm120Modbus->Begin(SDM120_SPEED); - if (result) { - if (2 == result) { ClaimSerial(); } - } else { - energy_flg = ENERGY_NONE; - } -} - -void Sdm120DrvInit(void) -{ - if ((pin[GPIO_SDM120_RX] < 99) && (pin[GPIO_SDM120_TX] < 99)) { - energy_flg = XNRG_08; - } -} - -void Sdm220Reset(void) -{ - if (isnan(Sdm120.import_active)) { return; } - - Sdm120.import_active = 0; - Sdm120.import_reactive = 0; - Sdm120.export_reactive = 0; - Sdm120.phase_angle = 0; -} - -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM220[] PROGMEM = - "{s}" D_IMPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - "{s}" D_EXPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}"; -#endif - -void Sdm220Show(bool json) -{ - if (isnan(Sdm120.import_active)) { return; } - - char import_active_chr[FLOATSZ]; - dtostrfd(Sdm120.import_active, Settings.flag2.energy_resolution, import_active_chr); - char import_reactive_chr[FLOATSZ]; - dtostrfd(Sdm120.import_reactive, Settings.flag2.energy_resolution, import_reactive_chr); - char export_reactive_chr[FLOATSZ]; - dtostrfd(Sdm120.export_reactive, Settings.flag2.energy_resolution, export_reactive_chr); - char phase_angle_chr[FLOATSZ]; - dtostrfd(Sdm120.phase_angle, 2, phase_angle_chr); - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s"), - import_active_chr, import_reactive_chr, export_reactive_chr, phase_angle_chr); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_SDM220, import_reactive_chr, export_reactive_chr, phase_angle_chr); -#endif - } -} - - - - - -bool Xnrg08(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (uptime > 4) { SDM120Every250ms(); } - break; - case FUNC_JSON_APPEND: - Sdm220Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Sdm220Show(0); - break; -#endif - case FUNC_ENERGY_RESET: - Sdm220Reset(); - break; - case FUNC_INIT: - Sdm120SnsInit(); - break; - case FUNC_PRE_INIT: - Sdm120DrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_09_dds2382.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_09_dds2382.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_DDS2382 - - - - - - -#define XNRG_09 9 - -#ifndef DDS2382_SPEED -#define DDS2382_SPEED 9600 -#endif -#ifndef DDS2382_ADDR -#define DDS2382_ADDR 1 -#endif - -#include -TasmotaModbus *Dds2382Modbus; - -uint8_t Dds2382_send_retry = 0; - -void Dds2382EverySecond(void) -{ - bool data_ready = Dds2382Modbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[46]; - - uint32_t error = Dds2382Modbus->ReceiveBuffer(buffer, 18); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, Dds2382Modbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "DDS2382 response error %d"), error); - } else { - Energy.data_valid[0] = 0; -# 67 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_09_dds2382.ino" - Energy.voltage[0] = (float)((buffer[27] << 8) + buffer[28]) / 10.0; - Energy.current[0] = (float)((buffer[29] << 8) + buffer[30]) / 100.0; - Energy.active_power[0] = (float)((buffer[31] << 8) + buffer[32]); - Energy.reactive_power[0] = (float)((buffer[33] << 8) + buffer[34]); - Energy.power_factor[0] = (float)((buffer[35] << 8) + buffer[36]) / 1000.0; - Energy.frequency[0] = (float)((buffer[37] << 8) + buffer[38]) / 100.0; - uint8_t offset = 11; - if (Settings.flag3.dds2382_model) { - offset = 19; - } - Energy.export_active = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0; - float import_active = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0; - - EnergyUpdateTotal(import_active, true); - } - } - - if (0 == Dds2382_send_retry || data_ready) { - Dds2382_send_retry = 5; - Dds2382Modbus->Send(DDS2382_ADDR, 0x03, 0, 18); - } else { - Dds2382_send_retry--; - } -} - -void Dds2382SnsInit(void) -{ - Dds2382Modbus = new TasmotaModbus(pin[GPIO_DDS2382_RX], pin[GPIO_DDS2382_TX]); - uint8_t result = Dds2382Modbus->Begin(DDS2382_SPEED); - if (result) { - if (2 == result) { ClaimSerial(); } - } else { - energy_flg = ENERGY_NONE; - } -} - -void Dds2382DrvInit(void) -{ - if ((pin[GPIO_DDS2382_RX] < 99) && (pin[GPIO_DDS2382_TX] < 99)) { - energy_flg = XNRG_09; - } -} - - - - - -bool Xnrg09(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_ENERGY_EVERY_SECOND: - if (uptime > 4) { Dds2382EverySecond(); } - break; - case FUNC_INIT: - Dds2382SnsInit(); - break; - case FUNC_PRE_INIT: - Dds2382DrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_10_sdm630.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_10_sdm630.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_SDM630 - - - - - - -#define XNRG_10 10 - - -#ifndef SDM630_SPEED - #define SDM630_SPEED 9600 -#endif - -#ifndef SDM630_ADDR - #define SDM630_ADDR 1 -#endif - -#include -TasmotaModbus *Sdm630Modbus; - -const uint16_t sdm630_start_addresses[] { - 0x0000, - 0x0002, - 0x0004, - 0x0006, - 0x0008, - 0x000A, - 0x000C, - 0x000E, - 0x0010, - 0x0018, - 0x001A, - 0x001C, - 0x001E, - 0x0020, - 0x0022, - 0x0156 -}; - -struct SDM630 { - uint8_t read_state = 0; - uint8_t send_retry = 0; -} Sdm630; - - - -void SDM630Every250ms(void) -{ - bool data_ready = Sdm630Modbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[14]; - - uint32_t error = Sdm630Modbus->ReceiveBuffer(buffer, 2); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, Sdm630Modbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: SDM630 error %d"), error); - } else { - Energy.data_valid[0] = 0; - Energy.data_valid[1] = 0; - Energy.data_valid[2] = 0; - - - - - float value; - ((uint8_t*)&value)[3] = buffer[3]; - ((uint8_t*)&value)[2] = buffer[4]; - ((uint8_t*)&value)[1] = buffer[5]; - ((uint8_t*)&value)[0] = buffer[6]; - - switch(Sdm630.read_state) { - case 0: - Energy.voltage[0] = value; - break; - - case 1: - Energy.voltage[1] = value; - break; - - case 2: - Energy.voltage[2] = value; - break; - - case 3: - Energy.current[0] = value; - break; - - case 4: - Energy.current[1] = value; - break; - - case 5: - Energy.current[2] = value; - break; - - case 6: - Energy.active_power[0] = value; - break; - - case 7: - Energy.active_power[1] = value; - break; - - case 8: - Energy.active_power[2] = value; - break; - - case 9: - Energy.reactive_power[0] = value; - break; - - case 10: - Energy.reactive_power[1] = value; - break; - - case 11: - Energy.reactive_power[2] = value; - break; - - case 12: - Energy.power_factor[0] = value; - break; - - case 13: - Energy.power_factor[1] = value; - break; - - case 14: - Energy.power_factor[2] = value; - break; - - case 15: - EnergyUpdateTotal(value, true); - break; - } - - Sdm630.read_state++; - if (sizeof(sdm630_start_addresses)/2 == Sdm630.read_state) { - Sdm630.read_state = 0; - } - } - } - - if (0 == Sdm630.send_retry || data_ready) { - Sdm630.send_retry = 5; - Sdm630Modbus->Send(SDM630_ADDR, 0x04, sdm630_start_addresses[Sdm630.read_state], 2); - } else { - Sdm630.send_retry--; - } -} - -void Sdm630SnsInit(void) -{ - Sdm630Modbus = new TasmotaModbus(pin[GPIO_SDM630_RX], pin[GPIO_SDM630_TX]); - uint8_t result = Sdm630Modbus->Begin(SDM630_SPEED); - if (result) { - if (2 == result) { ClaimSerial(); } - Energy.phase_count = 3; - } else { - energy_flg = ENERGY_NONE; - } -} - -void Sdm630DrvInit(void) -{ - if ((pin[GPIO_SDM630_RX] < 99) && (pin[GPIO_SDM630_TX] < 99)) { - energy_flg = XNRG_10; - } -} - - - - - -bool Xnrg10(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (uptime > 4) { SDM630Every250ms(); } - break; - case FUNC_INIT: - Sdm630SnsInit(); - break; - case FUNC_PRE_INIT: - Sdm630DrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_11_ddsu666.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_11_ddsu666.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_DDSU666 - - - - -#define XNRG_11 11 - - -#ifndef DDSU666_SPEED - #define DDSU666_SPEED 9600 -#endif - -#ifndef DDSU666_ADDR - #define DDSU666_ADDR 1 -#endif - -#include -TasmotaModbus *Ddsu666Modbus; - -const uint16_t Ddsu666_start_addresses[] { - 0x2000, - 0x2002, - 0x2004, - 0x2006, - 0x200A, - 0x200E, - 0X4000, - 0X400A, -}; - -struct DDSU666 { - float import_active = NAN; - uint8_t read_state = 0; - uint8_t send_retry = 0; -} Ddsu666; - - - -void DDSU666Every250ms(void) -{ - bool data_ready = Ddsu666Modbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[14]; - - uint32_t error = Ddsu666Modbus->ReceiveBuffer(buffer, 2); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, Ddsu666Modbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: Ddsu666 error %d"), error); - } else { - Energy.data_valid[0] = 0; - - - - - float value; - ((uint8_t*)&value)[3] = buffer[3]; - ((uint8_t*)&value)[2] = buffer[4]; - ((uint8_t*)&value)[1] = buffer[5]; - ((uint8_t*)&value)[0] = buffer[6]; - - switch(Ddsu666.read_state) { - case 0: - Energy.voltage[0] = value; - break; - - case 1: - Energy.current[0] = value; - break; - - case 2: - Energy.active_power[0] = value * 1000; - break; - - case 3: - Energy.reactive_power[0] = value * 1000; - break; - - case 4: - Energy.power_factor[0] = value; - break; - - case 5: - Energy.frequency[0] = value; - break; - - case 6: - Ddsu666.import_active = value; - break; - - case 7: - Energy.export_active = value; - break; - } - - Ddsu666.read_state++; - - if (Ddsu666.read_state == 8) { - Ddsu666.read_state = 0; - EnergyUpdateTotal(Ddsu666.import_active, true); - } - } - } - - if (0 == Ddsu666.send_retry || data_ready) { - Ddsu666.send_retry = 5; - Ddsu666Modbus->Send(DDSU666_ADDR, 0x04, Ddsu666_start_addresses[Ddsu666.read_state], 2); - } else { - Ddsu666.send_retry--; - } -} - -void Ddsu666SnsInit(void) -{ - Ddsu666Modbus = new TasmotaModbus(pin[GPIO_DDSU666_RX], pin[GPIO_DDSU666_TX]); - uint8_t result = Ddsu666Modbus->Begin(DDSU666_SPEED); - if (result) { - if (2 == result) { ClaimSerial(); } - } else { - energy_flg = ENERGY_NONE; - } -} - -void Ddsu666DrvInit(void) -{ - if ((pin[GPIO_DDSU666_RX] < 99) && (pin[GPIO_DDSU666_TX] < 99)) { - energy_flg = XNRG_11; - } -} - - - - - -bool Xnrg11(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (uptime > 4) { DDSU666Every250ms(); } - break; - case FUNC_INIT: - Ddsu666SnsInit(); - break; - case FUNC_PRE_INIT: - Ddsu666DrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_12_solaxX1.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_12_solaxX1.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_SOLAX_X1 - - - - -#define XNRG_12 12 - -#ifndef SOLAXX1_SPEED -#define SOLAXX1_SPEED 9600 -#endif - -#define INVERTER_ADDRESS 0x0A - -#define D_SOLAX_X1 "SolaxX1" - -#include - -enum solaxX1_Error -{ - solaxX1_ERR_NO_ERROR, - solaxX1_ERR_CRC_ERROR -}; - -union { - uint32_t ErrMessage; - struct { - - uint8_t TzProtectFault:1; - uint8_t MainsLostFault:1; - uint8_t GridVoltFault:1; - uint8_t GridFreqFault:1; - uint8_t PLLLostFault:1; - uint8_t BusVoltFault:1; - uint8_t ErrBit06:1; - uint8_t OciFault:1; - - uint8_t Dci_OCP_Fault:1; - uint8_t ResidualCurrentFault:1; - uint8_t PvVoltFault:1; - uint8_t Ac10Mins_Voltage_Fault:1; - uint8_t IsolationFault:1; - uint8_t TemperatureOverFault:1; - uint8_t FanFault:1; - uint8_t ErrBit15:1; - - uint8_t SpiCommsFault:1; - uint8_t SciCommsFault:1; - uint8_t ErrBit18:1; - uint8_t InputConfigFault:1; - uint8_t EepromFault:1; - uint8_t RelayFault:1; - uint8_t SampleConsistenceFault:1; - uint8_t ResidualCurrent_DeviceFault:1; - - uint8_t ErrBit24:1; - uint8_t ErrBit25:1; - uint8_t ErrBit26:1; - uint8_t ErrBit27:1; - uint8_t ErrBit28:1; - uint8_t DCI_DeviceFault:1; - uint8_t OtherDeviceFault:1; - uint8_t ErrBit31:1; - }; -} ErrCode; - -const char kSolaxMode[] PROGMEM = D_WAITING "|" D_CHECKING "|" D_WORKING "|" D_FAILURE; - -const char kSolaxError[] PROGMEM = - D_SOLAX_ERROR_0 "|" D_SOLAX_ERROR_1 "|" D_SOLAX_ERROR_2 "|" D_SOLAX_ERROR_3 "|" D_SOLAX_ERROR_4 "|" D_SOLAX_ERROR_5 "|" - D_SOLAX_ERROR_6 "|" D_SOLAX_ERROR_7 "|" D_SOLAX_ERROR_8; - - - -TasmotaSerial *solaxX1Serial; - -uint8_t solaxX1_Init = 1; - -struct SOLAXX1 { - float temperature = 0; - float energy_today = 0; - float dc1_voltage = 0; - float dc2_voltage = 0; - float dc1_current = 0; - float dc2_current = 0; - float energy_total = 0; - float runtime_total = 0; - float dc1_power = 0; - float dc2_power = 0; - - uint8_t status = 0; - uint32_t errorCode = 0; -} solaxX1; - -union { - uint8_t status; - struct { - uint8_t freeBit7:1; - uint8_t freeBit6:1; - uint8_t freeBit5:1; - uint8_t queryOffline:1; - uint8_t queryOfflineSend:1; - uint8_t hasAddress:1; - uint8_t inverterAddressSend:1; - uint8_t inverterSnReceived:1; - }; -} protocolStatus; - -uint8_t header[2] = {0xAA, 0x55}; -uint8_t source[2] = {0x00, 0x00}; -uint8_t destination[2] = {0x00, 0x00}; -uint8_t controlCode[1] = {0x00}; -uint8_t functionCode[1] = {0x00}; -uint8_t dataLength[1] = {0x00}; -uint8_t data[16] = {0}; - -uint8_t message[30]; - - - -bool solaxX1_RS485ReceiveReady(void) -{ - return (solaxX1Serial->available() > 1); -} - -void solaxX1_RS485Send(uint16_t msgLen) -{ - memcpy(message, header, 2); - memcpy(message + 2, source, 2); - memcpy(message + 4, destination, 2); - memcpy(message + 6, controlCode, 1); - memcpy(message + 7, functionCode, 1); - memcpy(message + 8, dataLength, 1); - memcpy(message + 9, data, sizeof(data)); - uint16_t crc = solaxX1_calculateCRC(message, msgLen); - - while (solaxX1Serial->available() > 0) - { - solaxX1Serial->read(); - } - - solaxX1Serial->flush(); - solaxX1Serial->write(message, msgLen); - solaxX1Serial->write(highByte(crc)); - solaxX1Serial->write(lowByte(crc)); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, message, msgLen); -} - -uint8_t solaxX1_RS485Receive(uint8_t *value) -{ - uint8_t len = 0; - - while (solaxX1Serial->available() > 0) - { - value[len++] = (uint8_t)solaxX1Serial->read(); - } - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, value, len); - - uint16_t crc = solaxX1_calculateCRC(value, len - 2); - - if (value[len - 1] == lowByte(crc) && value[len - 2] == highByte(crc)) - { - return solaxX1_ERR_NO_ERROR; - } - else - { - return solaxX1_ERR_CRC_ERROR; - } -} - -uint16_t solaxX1_calculateCRC(uint8_t *bExternTxPackage, uint8_t bLen) -{ - uint8_t i; - uint16_t wChkSum; - wChkSum = 0; - - for (i = 0; i < bLen; i++) - { - wChkSum = wChkSum + bExternTxPackage[i]; - } - return wChkSum; -} - -void solaxX1_SendInverterAddress(void) -{ - source[0] = 0x00; - destination[0] = 0x00; - destination[1] = 0x00; - controlCode[0] = 0x10; - functionCode[0] = 0x01; - dataLength[0] = 0x0F; - data[14] = INVERTER_ADDRESS; - solaxX1_RS485Send(24); -} - -void solaxX1_QueryLiveData(void) -{ - source[0] = 0x01; - destination[0] = 0x00; - destination[1] = INVERTER_ADDRESS; - controlCode[0] = 0x11; - functionCode[0] = 0x02; - dataLength[0] = 0x00; - solaxX1_RS485Send(9); -} - -uint8_t solaxX1_ParseErrorCode(uint32_t code){ - ErrCode.ErrMessage = code; - - if (code == 0) return 0; - if (ErrCode.MainsLostFault) return 1; - if (ErrCode.GridVoltFault) return 2; - if (ErrCode.GridFreqFault) return 3; - if (ErrCode.PvVoltFault) return 4; - if (ErrCode.IsolationFault) return 5; - if (ErrCode.TemperatureOverFault) return 6; - if (ErrCode.FanFault) return 7; - if (ErrCode.OtherDeviceFault) return 8; -} - - - -uint8_t solaxX1_send_retry = 0; -uint8_t solaxX1_nodata_count = 0; - -void solaxX1250MSecond(void) -{ - uint8_t value[61] = {0}; - bool data_ready = solaxX1_RS485ReceiveReady(); - - if (protocolStatus.hasAddress && (data_ready || solaxX1_send_retry == 0)) - { - if (data_ready) - { - uint8_t error = solaxX1_RS485Receive(value); - if (error) - { - DEBUG_SENSOR_LOG(PSTR("SX1: Data response CRC error")); - } - else - { - solaxX1_nodata_count = 0; - solaxX1_send_retry = 12; - Energy.data_valid[0] = 0; - - solaxX1.temperature = (float)((value[9] << 8) | value[10]); - solaxX1.energy_today = (float)((value[11] << 8) | value[12]) * 0.1f; - solaxX1.dc1_voltage = (float)((value[13] << 8) | value[14]) * 0.1f; - solaxX1.dc2_voltage = (float)((value[15] << 8) | value[16]) * 0.1f; - solaxX1.dc1_current = (float)((value[17] << 8) | value[18]) * 0.1f; - solaxX1.dc2_current = (float)((value[19] << 8) | value[20]) * 0.1f; - Energy.current[0] = (float)((value[21] << 8) | value[22]) * 0.1f; - Energy.voltage[0] = (float)((value[23] << 8) | value[24]) * 0.1f; - Energy.frequency[0] = (float)((value[25] << 8) | value[26]) * 0.01f; - Energy.active_power[0] = (float)((value[27] << 8) | value[28]); - - solaxX1.energy_total = (float)((value[31] << 8) | (value[32] << 8) | (value[33] << 8) | value[34]) * 0.1f; - solaxX1.runtime_total = (float)((value[35] << 8) | (value[36] << 8) | (value[37] << 8) | value[38]); - solaxX1.status = (uint8_t)((value[39] << 8) | value[40]); - - - - - - - - solaxX1.errorCode = (uint32_t)((value[58] << 8) | (value[57] << 8) | (value[56] << 8) | value[55]); - - solaxX1.dc1_power = solaxX1.dc1_voltage * solaxX1.dc1_current; - solaxX1.dc2_power = solaxX1.dc2_voltage * solaxX1.dc2_current; - - solaxX1_QueryLiveData(); - EnergyUpdateTotal(solaxX1.energy_total, true); - } - } - - if (0 == solaxX1_send_retry && 255 != solaxX1_nodata_count) { - solaxX1_send_retry = 12; - solaxX1_QueryLiveData(); - } - - - - if (255 == solaxX1_nodata_count) { - solaxX1_nodata_count = 0; - solaxX1_send_retry = 12; - } - } - else - { - if ((solaxX1_nodata_count % 4) == 0) { DEBUG_SENSOR_LOG(PSTR("SX1: No Data count: %d"), solaxX1_nodata_count); } - if (solaxX1_nodata_count < 10 * 4) - { - solaxX1_nodata_count++; - } - else if (255 != solaxX1_nodata_count) - { - - solaxX1_nodata_count = 255; - solaxX1_send_retry = 12; - protocolStatus.status = 0b00001000; - Energy.data_valid[0] = ENERGY_WATCHDOG; - - solaxX1.temperature = solaxX1.dc1_voltage = solaxX1.dc2_voltage = solaxX1.dc1_current = solaxX1.dc2_current = solaxX1.dc1_power = 0; - solaxX1.dc2_power = solaxX1.status = Energy.current[0] = Energy.voltage[0] = Energy.frequency[0] = Energy.active_power[0] = 0; - - } - } - - if (!protocolStatus.hasAddress && (data_ready || solaxX1_send_retry == 0)) - { - if (data_ready) - { - - if (protocolStatus.inverterAddressSend) - { - uint8_t error = solaxX1_RS485Receive(value); - if (error) - { - DEBUG_SENSOR_LOG(PSTR("SX1: Address confirmation response CRC error")); - } - else - { - if (value[6] == 0x10 && value[7] == 0x81 && value[9] == 0x06) - { - DEBUG_SENSOR_LOG(PSTR("SX1: Set hasAddress")); - protocolStatus.status = 0b00100000; - } - } - } - - - if (protocolStatus.queryOfflineSend) - { - uint8_t error = solaxX1_RS485Receive(value); - if (error) - { - DEBUG_SENSOR_LOG(PSTR("SX1: Query Offline response CRC error")); - } - else - { - - if (value[6] == 0x10 && value[7] == 0x80 && protocolStatus.inverterSnReceived == false) - { - for (uint8_t i = 9; i <= 22; i++) - { - data[i - 9] = value[i]; - } - solaxX1_SendInverterAddress(); - protocolStatus.status = 0b1100000; - DEBUG_SENSOR_LOG(PSTR("SX1: Set inverterSnReceived and inverterAddressSend")); - } - } - } - } - - if (solaxX1_send_retry == 0) - { - if (protocolStatus.queryOfflineSend) - { - protocolStatus.status = 0b00001000; - DEBUG_SENSOR_LOG(PSTR("SX1: Set Query Offline")); - } - solaxX1_send_retry = 12; - } - - - if (protocolStatus.queryOffline) - { - - source[0] = 0x01; - destination[1] = 0x00; - controlCode[0] = 0x10; - functionCode[0] = 0x00; - dataLength[0] = 0x00; - solaxX1_RS485Send(9); - protocolStatus.status = 0b00010000; - DEBUG_SENSOR_LOG(PSTR("SX1: Query Offline Send")); - } - } - - if (!data_ready) - solaxX1_send_retry--; -} - -void solaxX1SnsInit(void) -{ - AddLog_P(LOG_LEVEL_DEBUG, PSTR("SX1: Solax X1 Inverter Init")); - DEBUG_SENSOR_LOG(PSTR("SX1: RX pin: %d, TX pin: %d"), pin[GPIO_SOLAXX1_RX], pin[GPIO_SOLAXX1_TX]); - protocolStatus.status = 0b00100000; - - solaxX1Serial = new TasmotaSerial(pin[GPIO_SOLAXX1_RX], pin[GPIO_SOLAXX1_TX], 1); - if (solaxX1Serial->begin(SOLAXX1_SPEED)) { - if (solaxX1Serial->hardwareSerial()) { ClaimSerial(); } - } else { - energy_flg = ENERGY_NONE; - } -} - -void solaxX1DrvInit(void) -{ - if ((pin[GPIO_SOLAXX1_RX] < 99) && (pin[GPIO_SOLAXX1_TX] < 99)) { - energy_flg = XNRG_12; - } -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_solaxX1_DATA1[] PROGMEM = - "{s}" D_SOLAX_X1 " " D_SOLAR_POWER "{m}%s " D_UNIT_WATT "{e}" - "{s}" D_SOLAX_X1 " " D_PV1_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}" - "{s}" D_SOLAX_X1 " " D_PV1_CURRENT "{m}%s " D_UNIT_AMPERE "{e}" - "{s}" D_SOLAX_X1 " " D_PV1_POWER "{m}%s " D_UNIT_WATT "{e}"; -#ifdef SOLAXX1_PV2 -const char HTTP_SNS_solaxX1_DATA2[] PROGMEM = - "{s}" D_SOLAX_X1 " " D_PV2_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}" - "{s}" D_SOLAX_X1 " " D_PV2_CURRENT "{m}%s " D_UNIT_AMPERE "{e}" - "{s}" D_SOLAX_X1 " " D_PV2_POWER "{m}%s " D_UNIT_WATT "{e}"; -#endif -const char HTTP_SNS_solaxX1_DATA3[] PROGMEM = - "{s}" D_SOLAX_X1 " " D_UPTIME "{m}%s " D_UNIT_HOUR "{e}" - "{s}" D_SOLAX_X1 " " D_STATUS "{m}%s" - "{s}" D_SOLAX_X1 " " D_ERROR "{m}%s"; -#endif - -void solaxX1Show(bool json) -{ - char solar_power[33]; - dtostrfd(solaxX1.dc1_power + solaxX1.dc2_power, Settings.flag2.wattage_resolution, solar_power); - char pv1_voltage[33]; - dtostrfd(solaxX1.dc1_voltage, Settings.flag2.voltage_resolution, pv1_voltage); - char pv1_current[33]; - dtostrfd(solaxX1.dc1_current, Settings.flag2.current_resolution, pv1_current); - char pv1_power[33]; - dtostrfd(solaxX1.dc1_power, Settings.flag2.wattage_resolution, pv1_power); -#ifdef SOLAXX1_PV2 - char pv2_voltage[33]; - dtostrfd(solaxX1.dc2_voltage, Settings.flag2.voltage_resolution, pv2_voltage); - char pv2_current[33]; - dtostrfd(solaxX1.dc2_current, Settings.flag2.current_resolution, pv2_current); - char pv2_power[33]; - dtostrfd(solaxX1.dc2_power, Settings.flag2.wattage_resolution, pv2_power); -#endif - char temperature[33]; - dtostrfd(solaxX1.temperature, Settings.flag2.temperature_resolution, temperature); - char runtime[33]; - dtostrfd(solaxX1.runtime_total, 0, runtime); - char status[33]; - GetTextIndexed(status, sizeof(status), solaxX1.status, kSolaxMode); - - if (json) - { - ResponseAppend_P(PSTR(",\"" D_JSON_SOLAR_POWER "\":%s,\"" D_JSON_PV1_VOLTAGE "\":%s,\"" D_JSON_PV1_CURRENT "\":%s,\"" D_JSON_PV1_POWER "\":%s"), - solar_power, pv1_voltage, pv1_current, pv1_power); -#ifdef SOLAXX1_PV2 - ResponseAppend_P(PSTR(",\"" D_JSON_PV2_VOLTAGE "\":%s,\"" D_JSON_PV2_CURRENT "\":%s,\"" D_JSON_PV2_POWER "\":%s"), - pv2_voltage, pv2_current, pv2_power); -#endif - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_RUNTIME "\":%s,\"" D_JSON_STATUS "\":\"%s\",\"" D_JSON_ERROR "\":%d"), - temperature, runtime, status, solaxX1.errorCode); - -#ifdef USE_WEBSERVER - } - else - { - WSContentSend_PD(HTTP_SNS_solaxX1_DATA1, solar_power, pv1_voltage, pv1_current, pv1_power); -#ifdef SOLAXX1_PV2 - WSContentSend_PD(HTTP_SNS_solaxX1_DATA2, pv2_voltage, pv2_current, pv2_power); -#endif - WSContentSend_PD(HTTP_SNS_TEMP, D_SOLAX_X1, temperature, TempUnit()); - char errorCodeString[33]; - WSContentSend_PD(HTTP_SNS_solaxX1_DATA3, runtime, status, - GetTextIndexed(errorCodeString, sizeof(errorCodeString), solaxX1_ParseErrorCode(solaxX1.errorCode), kSolaxError)); -#endif - } -} - - - - - -bool Xnrg12(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (uptime > 4) { solaxX1250MSecond(); } - break; - case FUNC_JSON_APPEND: - solaxX1Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - solaxX1Show(0); - break; -#endif - case FUNC_INIT: - solaxX1SnsInit(); - break; - case FUNC_PRE_INIT: - solaxX1DrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_13_fif_le01mr.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_13_fif_le01mr.ino" -#ifdef USE_ENERGY_SENSOR -#ifdef USE_LE01MR -# 71 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_13_fif_le01mr.ino" -#define XNRG_13 13 - - -#ifndef LE01MR_SPEED - #define LE01MR_SPEED 2400 -#endif - -#ifndef LE01MR_ADDR - #define LE01MR_ADDR 1 -#endif - -#include -TasmotaModbus *FifLEModbus; - -const uint8_t le01mr_table_sz = 9; - -const uint16_t le01mr_register_addresses[] { - - 0x0130, - 0x0131, - 0x0158, - 0x0139, - 0x0140, - 0x0148, - 0x0150, - 0xA000, - 0xA01E -}; - -struct LE01MR { - float total_active = 0; - float total_reactive = 0; - uint8_t read_state = 0; - uint8_t send_retry = 0; - uint8_t start_address_count = le01mr_table_sz; -} Le01mr; - - - -void FifLEEvery250ms(void) -{ - bool data_ready = FifLEModbus->ReceiveReady(); - - if (data_ready) { - uint8_t buffer[14]; - uint8_t reg_count = 2; - if (Le01mr.read_state < 3) { - reg_count=1; - } - - uint32_t error = FifLEModbus->ReceiveBuffer(buffer, reg_count); - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, FifLEModbus->ReceiveCount()); - - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("FiF-LE: LE01MR Modbus error %d"), error); - } else { - Energy.data_valid[0] = 0; -# 146 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_13_fif_le01mr.ino" - uint32_t value_buff = 0; - - if (Le01mr.read_state >= 0 && Le01mr.read_state < 3) { - value_buff = ((uint32_t)buffer[3])<<8 | buffer[4]; - } else { - value_buff = ((uint32_t)buffer[3])<<24 | ((uint32_t)buffer[4])<<16 | ((uint32_t)buffer[5])<<8 | buffer[6]; - } - - switch(Le01mr.read_state) { - case 0: - Energy.frequency[0] = value_buff * 0.01f; - break; - - case 1: - Energy.voltage[0] = value_buff * 0.01f; - break; - - case 2: - Energy.power_factor[0] = ((int16_t)value_buff) * 0.001f; - break; - - case 3: - Energy.current[0] = value_buff * 0.001f; - break; - - case 4: - Energy.active_power[0] = value_buff * 1.0f; - break; - - case 5: - Energy.reactive_power[0] = value_buff * 1.0f; - break; - - case 6: - Energy.apparent_power[0] = value_buff * 1.0f; - break; - - case 7: - Le01mr.total_active = value_buff * 0.01f; - break; - - case 8: - Le01mr.total_reactive = value_buff * 0.01f; - break; - } - - Le01mr.read_state++; - if (Le01mr.read_state == Le01mr.start_address_count) { - Le01mr.read_state = 0; - - EnergyUpdateTotal(Le01mr.total_active, true); - } - } - } - - if (0 == Le01mr.send_retry || data_ready) { - uint8_t reg_count = 2; - - Le01mr.send_retry = 5; - - if (Le01mr.read_state < 3) reg_count=1; - - FifLEModbus->Send(LE01MR_ADDR, 0x03, le01mr_register_addresses[Le01mr.read_state], reg_count); - } else { - Le01mr.send_retry--; - } -} - -void FifLESnsInit(void) -{ - FifLEModbus = new TasmotaModbus(pin[GPIO_LE01MR_RX], pin[GPIO_LE01MR_TX]); - uint8_t result = FifLEModbus->Begin(LE01MR_SPEED); - if (result) { - if (2 == result) { ClaimSerial(); } - } else { - energy_flg = ENERGY_NONE; - } -} - -void FifLEDrvInit(void) -{ - if ((pin[GPIO_LE01MR_RX] < 99) && (pin[GPIO_LE01MR_TX] < 99)) { - energy_flg = XNRG_13; - } -} - -void FifLEReset(void) -{ - Le01mr.total_active = 0; - Le01mr.total_reactive = 0; -} - -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_LE01MR[] PROGMEM = - "{s}" D_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_TOTAL_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - ; -#endif - -void FifLEShow(bool json) -{ - char total_reactive_chr[FLOATSZ]; - dtostrfd(Le01mr.total_reactive, Settings.flag2.energy_resolution, total_reactive_chr); - char total_active_chr[FLOATSZ]; - dtostrfd(Le01mr.total_active, Settings.flag2.energy_resolution, total_active_chr); - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s"), - total_active_chr, total_reactive_chr); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_LE01MR, total_active_chr, total_reactive_chr); -#endif - } -} - - - - - -bool Xnrg13(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (uptime > 4) { - FifLEEvery250ms(); - } - break; - case FUNC_JSON_APPEND: - FifLEShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - FifLEShow(0); - break; -#endif - case FUNC_ENERGY_RESET: - FifLEReset(); - break; - case FUNC_INIT: - FifLESnsInit(); - break; - case FUNC_PRE_INIT: - FifLEDrvInit(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_interface.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xnrg_interface.ino" -#ifdef USE_ENERGY_SENSOR - -#ifdef XFUNC_PTR_IN_ROM -bool (* const xnrg_func_ptr[])(uint8_t) PROGMEM = { -#else -bool (* const xnrg_func_ptr[])(uint8_t) = { -#endif - -#ifdef XNRG_01 - &Xnrg01, -#endif - -#ifdef XNRG_02 - &Xnrg02, -#endif - -#ifdef XNRG_03 - &Xnrg03, -#endif - -#ifdef XNRG_04 - &Xnrg04, -#endif - -#ifdef XNRG_05 - &Xnrg05, -#endif - -#ifdef XNRG_06 - &Xnrg06, -#endif - -#ifdef XNRG_07 - &Xnrg07, -#endif - -#ifdef XNRG_08 - &Xnrg08, -#endif - -#ifdef XNRG_09 - &Xnrg09, -#endif - -#ifdef XNRG_10 - &Xnrg10, -#endif - -#ifdef XNRG_11 - &Xnrg11, -#endif - -#ifdef XNRG_12 - &Xnrg12, -#endif - -#ifdef XNRG_13 - &Xnrg13, -#endif - -#ifdef XNRG_14 - &Xnrg14, -#endif - -#ifdef XNRG_15 - &Xnrg15, -#endif - -#ifdef XNRG_16 - &Xnrg16 -#endif -}; - -const uint8_t xnrg_present = sizeof(xnrg_func_ptr) / sizeof(xnrg_func_ptr[0]); - -uint8_t xnrg_active = 0; - -bool XnrgCall(uint8_t function) -{ - DEBUG_TRACE_LOG(PSTR("NRG: %d"), function); - - if (FUNC_PRE_INIT == function) { - for (uint32_t x = 0; x < xnrg_present; x++) { - xnrg_func_ptr[x](function); - if (energy_flg) { - xnrg_active = x; - return true; - } - } - } - else if (energy_flg) { - return xnrg_func_ptr[xnrg_active](function); - } - return false; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_01_counter.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_01_counter.ino" -#ifdef USE_COUNTER - - - - -#define XSNS_01 1 - -#define D_PRFX_COUNTER "Counter" -#define D_CMND_COUNTERTYPE "Type" -#define D_CMND_COUNTERDEBOUNCE "Debounce" -#define D_CMND_COUNTERDEBOUNCELOW "DebounceLow" -#define D_CMND_COUNTERDEBOUNCEHIGH "DebounceHigh" - -const char kCounterCommands[] PROGMEM = D_PRFX_COUNTER "|" - "|" D_CMND_COUNTERTYPE "|" D_CMND_COUNTERDEBOUNCE "|" D_CMND_COUNTERDEBOUNCELOW "|" D_CMND_COUNTERDEBOUNCEHIGH ; - -void (* const CounterCommand[])(void) PROGMEM = { - &CmndCounter, &CmndCounterType, &CmndCounterDebounce, &CmndCounterDebounceLow, &CmndCounterDebounceHigh }; - -struct COUNTER { - uint32_t timer[MAX_COUNTERS]; - uint32_t timer_low_high[MAX_COUNTERS]; - uint8_t no_pullup = 0; - uint8_t pin_state = 0; - bool any_counter = false; -} Counter; - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 -void CounterUpdate(uint8_t index) ICACHE_RAM_ATTR; -void CounterUpdate1(void) ICACHE_RAM_ATTR; -void CounterUpdate2(void) ICACHE_RAM_ATTR; -void CounterUpdate3(void) ICACHE_RAM_ATTR; -void CounterUpdate4(void) ICACHE_RAM_ATTR; -#endif - -void CounterUpdate(uint8_t index) -{ - uint32_t time = micros(); - uint32_t debounce_time; - - if (Counter.pin_state) { - - if (digitalRead(pin[GPIO_CNTR1 +index]) == bitRead(Counter.pin_state, index)) { - - return; - } - debounce_time = time - Counter.timer_low_high[index]; - if bitRead(Counter.pin_state, index) { - - if (debounce_time <= Settings.pulse_counter_debounce_high * 1000) return; - } else { - - if (debounce_time <= Settings.pulse_counter_debounce_low * 1000) return; - } - - Counter.timer_low_high[index] = time; - Counter.pin_state ^= (1< Settings.pulse_counter_debounce * 1000) { - Counter.timer[index] = time; - if (bitRead(Settings.pulse_counter_type, index)) { - RtcSettings.pulse_counter[index] = debounce_time; - } else { - RtcSettings.pulse_counter[index]++; - } - } -} - -void CounterUpdate1(void) -{ - CounterUpdate(0); -} - -void CounterUpdate2(void) -{ - CounterUpdate(1); -} - -void CounterUpdate3(void) -{ - CounterUpdate(2); -} - -void CounterUpdate4(void) -{ - CounterUpdate(3); -} - - - -bool CounterPinState(void) -{ - if ((XdrvMailbox.index >= GPIO_CNTR1_NP) && (XdrvMailbox.index < (GPIO_CNTR1_NP + MAX_COUNTERS))) { - bitSet(Counter.no_pullup, XdrvMailbox.index - GPIO_CNTR1_NP); - XdrvMailbox.index -= (GPIO_CNTR1_NP - GPIO_CNTR1); - return true; - } - return false; -} - -void CounterInit(void) -{ - typedef void (*function) () ; - function counter_callbacks[] = { CounterUpdate1, CounterUpdate2, CounterUpdate3, CounterUpdate4 }; - - for (uint32_t i = 0; i < MAX_COUNTERS; i++) { - if (pin[GPIO_CNTR1 +i] < 99) { - Counter.any_counter = true; - pinMode(pin[GPIO_CNTR1 +i], bitRead(Counter.no_pullup, i) ? INPUT : INPUT_PULLUP); - if ((0 == Settings.pulse_counter_debounce_low) && (0 == Settings.pulse_counter_debounce_high)) { - Counter.pin_state = 0; - attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], FALLING); - } else { - Counter.pin_state = 0x8f; - attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], CHANGE); - } - } - } -} - -void CounterEverySecond(void) -{ - for (uint32_t i = 0; i < MAX_COUNTERS; i++) { - if (pin[GPIO_CNTR1 +i] < 99) { - if (bitRead(Settings.pulse_counter_type, i)) { - uint32_t time = micros() - Counter.timer[i]; - if (time > 4200000000) { - RtcSettings.pulse_counter[i] = 4200000000; - } - } - } - } -} - -void CounterSaveState(void) -{ - for (uint32_t i = 0; i < MAX_COUNTERS; i++) { - if (pin[GPIO_CNTR1 +i] < 99) { - Settings.pulse_counter[i] = RtcSettings.pulse_counter[i]; - } - } -} - -void CounterShow(bool json) -{ - bool header = false; - uint8_t dsxflg = 0; - for (uint32_t i = 0; i < MAX_COUNTERS; i++) { - if (pin[GPIO_CNTR1 +i] < 99) { - char counter[33]; - if (bitRead(Settings.pulse_counter_type, i)) { - dtostrfd((double)RtcSettings.pulse_counter[i] / 1000000, 6, counter); - } else { - dsxflg++; - snprintf_P(counter, sizeof(counter), PSTR("%lu"), RtcSettings.pulse_counter[i]); - } - - if (json) { - if (!header) { - ResponseAppend_P(PSTR(",\"COUNTER\":{")); - } - ResponseAppend_P(PSTR("%s\"C%d\":%s"), (header)?",":"", i +1, counter); - header = true; -#ifdef USE_DOMOTICZ - if ((0 == tele_period) && (1 == dsxflg)) { - DomoticzSensor(DZ_COUNT, RtcSettings.pulse_counter[i]); - dsxflg++; - } -#endif - if ((0 == tele_period ) && (Settings.flag3.counter_reset_on_tele)) { - RtcSettings.pulse_counter[i] = 0; - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(PSTR("{s}" D_COUNTER "%d{m}%s%s{e}"), - i +1, counter, (bitRead(Settings.pulse_counter_type, i)) ? " " D_UNIT_SECOND : ""); -#endif - } - } - } - if (header) { - ResponseJsonEnd(); - } -} - - - - - -void CmndCounter(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_COUNTERS)) { - if ((XdrvMailbox.data_len > 0) && (pin[GPIO_CNTR1 + XdrvMailbox.index -1] < 99)) { - if ((XdrvMailbox.data[0] == '-') || (XdrvMailbox.data[0] == '+')) { - RtcSettings.pulse_counter[XdrvMailbox.index -1] += XdrvMailbox.payload; - Settings.pulse_counter[XdrvMailbox.index -1] += XdrvMailbox.payload; - } else { - RtcSettings.pulse_counter[XdrvMailbox.index -1] = XdrvMailbox.payload; - Settings.pulse_counter[XdrvMailbox.index -1] = XdrvMailbox.payload; - } - } - ResponseCmndIdxNumber(RtcSettings.pulse_counter[XdrvMailbox.index -1]); - } -} - -void CmndCounterType(void) -{ - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_COUNTERS)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1) && (pin[GPIO_CNTR1 + XdrvMailbox.index -1] < 99)) { - bitWrite(Settings.pulse_counter_type, XdrvMailbox.index -1, XdrvMailbox.payload &1); - RtcSettings.pulse_counter[XdrvMailbox.index -1] = 0; - Settings.pulse_counter[XdrvMailbox.index -1] = 0; - } - ResponseCmndIdxNumber(bitRead(Settings.pulse_counter_type, XdrvMailbox.index -1)); - } -} - -void CmndCounterDebounce(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32001)) { - Settings.pulse_counter_debounce = XdrvMailbox.payload; - } - ResponseCmndNumber(Settings.pulse_counter_debounce); -} - -void CmndCounterDebounceLow(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32001)) { - Settings.pulse_counter_debounce_low = XdrvMailbox.payload; - CounterInit(); - } - ResponseCmndNumber(Settings.pulse_counter_debounce_low); -} - -void CmndCounterDebounceHigh(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32001)) { - Settings.pulse_counter_debounce_high = XdrvMailbox.payload; - CounterInit(); - } - ResponseCmndNumber(Settings.pulse_counter_debounce_high); -} - - - - - -bool Xsns01(uint8_t function) -{ - bool result = false; - - if (Counter.any_counter) { - switch (function) { - case FUNC_EVERY_SECOND: - CounterEverySecond(); - break; - case FUNC_JSON_APPEND: - CounterShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - CounterShow(0); - break; -#endif - case FUNC_SAVE_BEFORE_RESTART: - case FUNC_SAVE_AT_MIDNIGHT: - CounterSaveState(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kCounterCommands, CounterCommand); - break; - } - } else { - switch (function) { - case FUNC_INIT: - CounterInit(); - break; - case FUNC_PIN_STATE: - result = CounterPinState(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_02_analog.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_02_analog.ino" -#ifndef USE_ADC_VCC - - - - -#define XSNS_02 2 - -#define TO_CELSIUS(x) ((x) - 273.15) -#define TO_KELVIN(x) ((x) + 273.15) - - -#define ANALOG_V33 3.3 -#define ANALOG_T0 TO_KELVIN(25.0) - - - - - -#define ANALOG_NTC_BRIDGE_RESISTANCE 32000 -#define ANALOG_NTC_RESISTANCE 10000 -#define ANALOG_NTC_B_COEFFICIENT 3350 - - - - - -#define ANALOG_LDR_BRIDGE_RESISTANCE 10000 -#define ANALOG_LDR_LUX_CALC_SCALAR 12518931 -#define ANALOG_LDR_LUX_CALC_EXPONENT -1.4050 -# 58 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_02_analog.ino" -#define ANALOG_CT_FLAGS 0 -#define ANALOG_CT_MULTIPLIER 2146 -#define ANALOG_CT_VOLTAGE 2300 - -#define CT_FLAG_ENERGY_RESET (1 << 0) - -struct { - float temperature = 0; - float current = 0; - float energy = 0; - uint32_t previous_millis = 0; - uint16_t last_value = 0; -} Adc; - -void AdcInit(void) -{ - if ((Settings.adc_param_type != my_adc0) || (Settings.adc_param1 > 1000000)) { - if (ADC0_TEMP == my_adc0) { - - Settings.adc_param_type = ADC0_TEMP; - Settings.adc_param1 = ANALOG_NTC_BRIDGE_RESISTANCE; - Settings.adc_param2 = ANALOG_NTC_RESISTANCE; - Settings.adc_param3 = ANALOG_NTC_B_COEFFICIENT * 10000; - } - else if (ADC0_LIGHT == my_adc0) { - Settings.adc_param_type = ADC0_LIGHT; - Settings.adc_param1 = ANALOG_LDR_BRIDGE_RESISTANCE; - Settings.adc_param2 = ANALOG_LDR_LUX_CALC_SCALAR; - Settings.adc_param3 = ANALOG_LDR_LUX_CALC_EXPONENT * 10000; - } - else if (ADC0_RANGE == my_adc0) { - Settings.adc_param_type = ADC0_RANGE; - Settings.adc_param1 = 0; - Settings.adc_param2 = 1023; - Settings.adc_param3 = 0; - Settings.adc_param4 = 100; - } - else if (ADC0_CT_POWER == my_adc0) { - Settings.adc_param_type = ADC0_CT_POWER; - Settings.adc_param1 = ANALOG_CT_FLAGS; - Settings.adc_param2 = ANALOG_CT_MULTIPLIER; - Settings.adc_param3 = ANALOG_CT_VOLTAGE; - } - } -} - -uint16_t AdcRead(uint8_t factor) -{ - - - - - - uint8_t samples = 1 << factor; - uint16_t analog = 0; - for (uint32_t i = 0; i < samples; i++) { - analog += analogRead(A0); - delay(1); - } - analog >>= factor; - return analog; -} - -#ifdef USE_RULES -void AdcEvery250ms(void) -{ - if (ADC0_INPUT == my_adc0) { - uint16_t new_value = AdcRead(5); - if ((new_value < Adc.last_value -10) || (new_value > Adc.last_value +10)) { - Adc.last_value = new_value; - uint16_t value = Adc.last_value / 10; - Response_P(PSTR("{\"ANALOG\":{\"A0div10\":%d}}"), (value > 99) ? 100 : value); - XdrvRulesProcess(); - } - } -} -#endif - -uint16_t AdcGetLux(void) -{ - int adc = AdcRead(2); - - double resistorVoltage = ((double)adc / 1023) * ANALOG_V33; - double ldrVoltage = ANALOG_V33 - resistorVoltage; - double ldrResistance = ldrVoltage / resistorVoltage * (double)Settings.adc_param1; - double ldrLux = (double)Settings.adc_param2 * FastPrecisePow(ldrResistance, (double)Settings.adc_param3 / 10000); - - return (uint16_t)ldrLux; -} - -uint16_t AdcGetRange(void) -{ - - - - int adc = AdcRead(2); - double adcrange = ( ((double)Settings.adc_param2 - (double)adc) / ( ((double)Settings.adc_param2 - (double)Settings.adc_param1)) * ((double)Settings.adc_param3 - (double)Settings.adc_param4) + (double)Settings.adc_param4 ); - return (uint16_t)adcrange; -} - -void AdcGetCurrentPower(uint8_t factor) -{ - - - - - - uint8_t samples = 1 << factor; - uint16_t analog = 0; - uint16_t analog_min = 1023; - uint16_t analog_max = 0; - for (uint32_t i = 0; i < samples; i++) { - analog = analogRead(A0); - if (analog < analog_min) { - analog_min = analog; - } - if (analog > analog_max) { - analog_max = analog; - } - delay(1); - } - - Adc.current = (float)(analog_max-analog_min) * ((float)(Settings.adc_param2) / 100000); - float power = Adc.current * (float)(Settings.adc_param3) / 10; - uint32_t current_millis = millis(); - Adc.energy = Adc.energy + ((power * (current_millis - Adc.previous_millis)) / 3600000000); - Adc.previous_millis = current_millis; -} - -void AdcEverySecond(void) -{ - if (ADC0_TEMP == my_adc0) { - int adc = AdcRead(2); - - double Rt = (adc * Settings.adc_param1) / (1024.0 * ANALOG_V33 - (double)adc); - double BC = (double)Settings.adc_param3 / 10000; - double T = BC / (BC / ANALOG_T0 + TaylorLog(Rt / (double)Settings.adc_param2)); - Adc.temperature = ConvertTemp(TO_CELSIUS(T)); - } - else if (ADC0_CT_POWER == my_adc0) { - AdcGetCurrentPower(5); - } -} - -void AdcShow(bool json) -{ - if (ADC0_INPUT == my_adc0) { - uint16_t analog = AdcRead(5); - - if (json) { - ResponseAppend_P(PSTR(",\"ANALOG\":{\"A0\":%d}"), analog); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_ANALOG, "", 0, analog); -#endif - } - } - - else if (ADC0_TEMP == my_adc0) { - char temperature[33]; - dtostrfd(Adc.temperature, Settings.flag2.temperature_resolution, temperature); - - if (json) { - ResponseAppend_P(JSON_SNS_TEMP, "ANALOG", temperature); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_TEMP, temperature); - } -#endif -#ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, Adc.temperature); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, "", temperature, TempUnit()); -#endif - } - } - - else if (ADC0_LIGHT == my_adc0) { - uint16_t adc_light = AdcGetLux(); - - if (json) { - ResponseAppend_P(JSON_SNS_ILLUMINANCE, "ANALOG", adc_light); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_ILLUMINANCE, adc_light); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_ILLUMINANCE, "", adc_light); -#endif - } - } - - else if (ADC0_RANGE == my_adc0) { - uint16_t adc_range = AdcGetRange(); - - if (json) { - ResponseAppend_P(JSON_SNS_RANGE, "ANALOG", adc_range); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_RANGE, "", adc_range); -#endif - } - } - - else if (ADC0_CT_POWER == my_adc0) { - AdcGetCurrentPower(5); - - float voltage = (float)(Settings.adc_param3) / 10; - char voltage_chr[FLOATSZ]; - dtostrfd(voltage, Settings.flag2.voltage_resolution, voltage_chr); - char current_chr[FLOATSZ]; - dtostrfd(Adc.current, Settings.flag2.current_resolution, current_chr); - char power_chr[FLOATSZ]; - dtostrfd(voltage * Adc.current, Settings.flag2.wattage_resolution, power_chr); - char energy_chr[FLOATSZ]; - dtostrfd(Adc.energy, Settings.flag2.energy_resolution, energy_chr); - - if (json) { - ResponseAppend_P(PSTR(",\"ANALOG\":{\"" D_JSON_ENERGY "\":%s,\"" D_JSON_POWERUSAGE "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), - energy_chr, power_chr, voltage_chr, current_chr); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_POWER_ENERGY, power_chr); - DomoticzSensor(DZ_VOLTAGE, voltage_chr); - DomoticzSensor(DZ_CURRENT, current_chr); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_VOLTAGE, voltage_chr); - WSContentSend_PD(HTTP_SNS_CURRENT, current_chr); - WSContentSend_PD(HTTP_SNS_POWER, power_chr); - WSContentSend_PD(HTTP_SNS_ENERGY_TOTAL, energy_chr); -#endif - } - } - -} - - - - - -const char kAdcCommands[] PROGMEM = "|" - D_CMND_ADC "|" D_CMND_ADCS "|" D_CMND_ADCPARAM; - -void (* const AdcCommand[])(void) PROGMEM = { - &CmndAdc, &CmndAdcs, &CmndAdcParam }; - -void CmndAdc(void) -{ - if (ValidAdc() && (XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < ADC0_END)) { - Settings.my_adc0 = XdrvMailbox.payload; - restart_flag = 2; - } - char stemp1[TOPSZ]; - Response_P(PSTR("{\"" D_CMND_ADC "0\":{\"%d\":\"%s\"}}"), Settings.my_adc0, GetTextIndexed(stemp1, sizeof(stemp1), Settings.my_adc0, kAdc0Names)); -} - -void CmndAdcs(void) -{ - Response_P(PSTR("{\"" D_CMND_ADCS "\":{")); - bool jsflg = false; - char stemp1[TOPSZ]; - for (uint32_t i = 0; i < ADC0_END; i++) { - if (jsflg) { - ResponseAppend_P(PSTR(",")); - } - jsflg = true; - ResponseAppend_P(PSTR("\"%d\":\"%s\""), i, GetTextIndexed(stemp1, sizeof(stemp1), i, kAdc0Names)); - } - ResponseJsonEndEnd(); -} - -void CmndAdcParam(void) -{ - if (XdrvMailbox.data_len) { - if ((ADC0_TEMP == XdrvMailbox.payload) || - (ADC0_LIGHT == XdrvMailbox.payload) || - (ADC0_RANGE == XdrvMailbox.payload) || - (ADC0_CT_POWER == XdrvMailbox.payload)) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { - char sub_string[XdrvMailbox.data_len +1]; - - - - Settings.adc_param_type = XdrvMailbox.payload; - Settings.adc_param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); - Settings.adc_param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10); - if (ADC0_RANGE == XdrvMailbox.payload) { - Settings.adc_param3 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 4), nullptr, 10)); - Settings.adc_param4 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 5), nullptr, 10)); - } else { - Settings.adc_param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000); - } - if (ADC0_CT_POWER == XdrvMailbox.payload) { - if ((Settings.adc_param1 & CT_FLAG_ENERGY_RESET) > 0) { - Adc.energy = 0; - Settings.adc_param1 ^= CT_FLAG_ENERGY_RESET; - } - } - } else { - - - - - Settings.adc_param_type = 0; - AdcInit(); - } - } - } - - - Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d"), Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2); - if (ADC0_RANGE == my_adc0) { - ResponseAppend_P(PSTR(",%d,%d"), Settings.adc_param3, Settings.adc_param4); - } else { - int value = Settings.adc_param3; - uint8_t precision; - for (precision = 4; precision > 0; precision--) { - if (value % 10) { break; } - value /= 10; - } - char param3[33]; - dtostrfd(((double)Settings.adc_param3)/10000, precision, param3); - ResponseAppend_P(PSTR(",%s"), param3); - } - ResponseAppend_P(PSTR("]}")); -} - - - - - -bool Xsns02(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_COMMAND: - result = DecodeCommand(kAdcCommands, AdcCommand); - break; - default: - if ((ADC0_INPUT == my_adc0) || - (ADC0_TEMP == my_adc0) || - (ADC0_LIGHT == my_adc0) || - (ADC0_RANGE == my_adc0) || - (ADC0_CT_POWER == my_adc0)) { - switch (function) { -#ifdef USE_RULES - case FUNC_EVERY_250_MSECOND: - AdcEvery250ms(); - break; -#endif - case FUNC_EVERY_SECOND: - AdcEverySecond(); - break; - case FUNC_INIT: - AdcInit(); - break; - case FUNC_JSON_APPEND: - AdcShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - AdcShow(0); - break; -#endif - } - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_04_snfsc.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_04_snfsc.ino" -#ifdef USE_SONOFF_SC -# 57 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_04_snfsc.ino" -#define XSNS_04 4 - -uint16_t sc_value[5] = { 0 }; - -void SonoffScSend(const char *data) -{ - Serial.write(data); - Serial.write('\x1B'); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SERIAL D_TRANSMIT " %s"), data); -} - -void SonoffScInit(void) -{ - - SonoffScSend("AT+START"); - -} - -void SonoffScSerialInput(char *rcvstat) -{ - char *p; - char *str; - uint16_t value[5] = { 0 }; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_SERIAL D_RECEIVED " %s"), rcvstat); - - if (!strncasecmp_P(rcvstat, PSTR("AT+UPDATE="), 10)) { - int8_t i = -1; - for (str = strtok_r(rcvstat, ":", &p); str && i < 5; str = strtok_r(nullptr, ":", &p)) { - value[i++] = atoi(str); - } - if (value[0] > 0) { - for (uint32_t i = 0; i < 5; i++) { - sc_value[i] = value[i]; - } - sc_value[2] = (11 - sc_value[2]) * 10; - sc_value[3] *= 10; - sc_value[4] = (11 - sc_value[4]) * 10; - SonoffScSend("AT+SEND=ok"); - } else { - SonoffScSend("AT+SEND=fail"); - } - } - else if (!strcasecmp_P(rcvstat, PSTR("AT+STATUS?"))) { - SonoffScSend("AT+STATUS=4"); - } -} - - - -#ifdef USE_WEBSERVER -const char HTTP_SNS_SCPLUS[] PROGMEM = - "{s}" D_LIGHT "{m}%d%%{e}{s}" D_NOISE "{m}%d%%{e}{s}" D_AIR_QUALITY "{m}%d%%{e}"; -#endif - -void SonoffScShow(bool json) -{ - if (sc_value[0] > 0) { - float t = ConvertTemp(sc_value[1]); - float h = ConvertHumidity(sc_value[0]); - - if (json) { - ResponseAppend_P(PSTR(",\"SonoffSC\":{")); - ResponseAppendTHD(t, h); - ResponseAppend_P(PSTR(",\"" D_JSON_LIGHT "\":%d,\"" D_JSON_NOISE "\":%d,\"" D_JSON_AIRQUALITY "\":%d}"), sc_value[2], sc_value[3], sc_value[4]); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzTempHumPressureSensor(t, h); - DomoticzSensor(DZ_ILLUMINANCE, sc_value[2]); - DomoticzSensor(DZ_COUNT, sc_value[3]); - DomoticzSensor(DZ_AIRQUALITY, 500 + ((100 - sc_value[4]) * 20)); - } -#endif - -#ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, t); - KnxSensor(KNX_HUMIDITY, h); - } -#endif - -#ifdef USE_WEBSERVER - } else { - WSContentSend_THD("", t, h); - WSContentSend_PD(HTTP_SNS_SCPLUS, sc_value[2], sc_value[3], sc_value[4]); -#endif - } - } -} - - - - - -bool Xsns04(uint8_t function) -{ - bool result = false; - - if (SONOFF_SC == my_module_type) { - switch (function) { - case FUNC_JSON_APPEND: - SonoffScShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - SonoffScShow(0); - break; -#endif - case FUNC_INIT: - SonoffScInit(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_05_ds18x20.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_05_ds18x20.ino" -#ifdef USE_DS18x20 - - - - -#define XSNS_05 5 - - - -#define DS18S20_CHIPID 0x10 -#define DS1822_CHIPID 0x22 -#define DS18B20_CHIPID 0x28 -#define MAX31850_CHIPID 0x3B - -#define W1_SKIP_ROM 0xCC -#define W1_CONVERT_TEMP 0x44 -#define W1_WRITE_EEPROM 0x48 -#define W1_WRITE_SCRATCHPAD 0x4E -#define W1_READ_SCRATCHPAD 0xBE - -#define DS18X20_MAX_SENSORS 8 - -const char kDs18x20Types[] PROGMEM = "DS18x20|DS18S20|DS1822|DS18B20|MAX31850"; - -uint8_t ds18x20_chipids[] = { 0, DS18S20_CHIPID, DS1822_CHIPID, DS18B20_CHIPID, MAX31850_CHIPID }; - -struct DS18X20STRUCT { - uint8_t address[8]; - uint8_t index; - uint8_t valid; - float temperature; -} ds18x20_sensor[DS18X20_MAX_SENSORS]; -uint8_t ds18x20_sensors = 0; -uint8_t ds18x20_pin = 0; -uint8_t ds18x20_pin_out = 0; -bool ds18x20_dual_mode = false; -char ds18x20_types[12]; -#ifdef W1_PARASITE_POWER -uint8_t ds18x20_sensor_curr = 0; -unsigned long w1_power_until = 0; -#endif - - - - - -#define W1_MATCH_ROM 0x55 -#define W1_SEARCH_ROM 0xF0 - -uint8_t onewire_last_discrepancy = 0; -uint8_t onewire_last_family_discrepancy = 0; -bool onewire_last_device_flag = false; -unsigned char onewire_rom_id[8] = { 0 }; - - - -uint8_t OneWireReset(void) -{ - uint8_t retries = 125; - - if (!ds18x20_dual_mode) { - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); - do { - if (--retries == 0) { - return 0; - } - delayMicroseconds(2); - } while (!digitalRead(ds18x20_pin)); - pinMode(ds18x20_pin, OUTPUT); - digitalWrite(ds18x20_pin, LOW); - delayMicroseconds(480); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); - delayMicroseconds(70); - uint8_t r = !digitalRead(ds18x20_pin); - delayMicroseconds(410); - return r; - } else { - digitalWrite(ds18x20_pin_out, HIGH); - do { - if (--retries == 0) { - return 0; - } - delayMicroseconds(2); - } while (!digitalRead(ds18x20_pin)); - digitalWrite(ds18x20_pin_out, LOW); - delayMicroseconds(480); - digitalWrite(ds18x20_pin_out, HIGH); - delayMicroseconds(70); - uint8_t r = !digitalRead(ds18x20_pin); - delayMicroseconds(410); - return r; - } -} - -void OneWireWriteBit(uint8_t v) -{ - static const uint8_t delay_low[2] = { 65, 10 }; - static const uint8_t delay_high[2] = { 5, 55 }; - - v &= 1; - if (!ds18x20_dual_mode) { - digitalWrite(ds18x20_pin, LOW); - pinMode(ds18x20_pin, OUTPUT); - delayMicroseconds(delay_low[v]); - digitalWrite(ds18x20_pin, HIGH); - } else { - digitalWrite(ds18x20_pin_out, LOW); - delayMicroseconds(delay_low[v]); - digitalWrite(ds18x20_pin_out, HIGH); - } - delayMicroseconds(delay_high[v]); -} - -uint8_t OneWire1ReadBit(void) -{ - pinMode(ds18x20_pin, OUTPUT); - digitalWrite(ds18x20_pin, LOW); - delayMicroseconds(3); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); - delayMicroseconds(10); - uint8_t r = digitalRead(ds18x20_pin); - delayMicroseconds(53); - return r; -} - -uint8_t OneWire2ReadBit(void) -{ - digitalWrite(ds18x20_pin_out, LOW); - delayMicroseconds(3); - digitalWrite(ds18x20_pin_out, HIGH); - delayMicroseconds(10); - uint8_t r = digitalRead(ds18x20_pin); - delayMicroseconds(53); - return r; -} - - - -void OneWireWrite(uint8_t v) -{ - for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { - OneWireWriteBit((bit_mask & v) ? 1 : 0); - } -} - -uint8_t OneWireRead(void) -{ - uint8_t r = 0; - - if (!ds18x20_dual_mode) { - for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { - if (OneWire1ReadBit()) { - r |= bit_mask; - } - } - } else { - for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { - if (OneWire2ReadBit()) { - r |= bit_mask; - } - } - } - return r; -} - -void OneWireSelect(const uint8_t rom[8]) -{ - OneWireWrite(W1_MATCH_ROM); - for (uint32_t i = 0; i < 8; i++) { - OneWireWrite(rom[i]); - } -} - -void OneWireResetSearch(void) -{ - onewire_last_discrepancy = 0; - onewire_last_device_flag = false; - onewire_last_family_discrepancy = 0; - for (uint32_t i = 0; i < 8; i++) { - onewire_rom_id[i] = 0; - } -} - -uint8_t OneWireSearch(uint8_t *newAddr) -{ - uint8_t id_bit_number = 1; - uint8_t last_zero = 0; - uint8_t rom_byte_number = 0; - uint8_t search_result = 0; - uint8_t id_bit; - uint8_t cmp_id_bit; - unsigned char rom_byte_mask = 1; - unsigned char search_direction; - - if (!onewire_last_device_flag) { - if (!OneWireReset()) { - onewire_last_discrepancy = 0; - onewire_last_device_flag = false; - onewire_last_family_discrepancy = 0; - return false; - } - OneWireWrite(W1_SEARCH_ROM); - do { - if (!ds18x20_dual_mode) { - id_bit = OneWire1ReadBit(); - cmp_id_bit = OneWire1ReadBit(); - } else { - id_bit = OneWire2ReadBit(); - cmp_id_bit = OneWire2ReadBit(); - } - if ((id_bit == 1) && (cmp_id_bit == 1)) { - break; - } else { - if (id_bit != cmp_id_bit) { - search_direction = id_bit; - } else { - if (id_bit_number < onewire_last_discrepancy) { - search_direction = ((onewire_rom_id[rom_byte_number] & rom_byte_mask) > 0); - } else { - search_direction = (id_bit_number == onewire_last_discrepancy); - } - if (search_direction == 0) { - last_zero = id_bit_number; - if (last_zero < 9) { - onewire_last_family_discrepancy = last_zero; - } - } - } - if (search_direction == 1) { - onewire_rom_id[rom_byte_number] |= rom_byte_mask; - } else { - onewire_rom_id[rom_byte_number] &= ~rom_byte_mask; - } - OneWireWriteBit(search_direction); - id_bit_number++; - rom_byte_mask <<= 1; - if (rom_byte_mask == 0) { - rom_byte_number++; - rom_byte_mask = 1; - } - } - } while (rom_byte_number < 8); - if (!(id_bit_number < 65)) { - onewire_last_discrepancy = last_zero; - if (onewire_last_discrepancy == 0) { - onewire_last_device_flag = true; - } - search_result = true; - } - } - if (!search_result || !onewire_rom_id[0]) { - onewire_last_discrepancy = 0; - onewire_last_device_flag = false; - onewire_last_family_discrepancy = 0; - search_result = false; - } - for (uint32_t i = 0; i < 8; i++) { - newAddr[i] = onewire_rom_id[i]; - } - return search_result; -} - -bool OneWireCrc8(uint8_t *addr) -{ - uint8_t crc = 0; - uint8_t len = 8; - - while (len--) { - uint8_t inbyte = *addr++; - for (uint32_t i = 8; i; i--) { - uint8_t mix = (crc ^ inbyte) & 0x01; - crc >>= 1; - if (mix) { - crc ^= 0x8C; - } - inbyte >>= 1; - } - } - return (crc == *addr); -} - - - -void Ds18x20Init(void) -{ - uint64_t ids[DS18X20_MAX_SENSORS]; - - ds18x20_pin = pin[GPIO_DSB]; - - if (pin[GPIO_DSB_OUT] < 99) { - ds18x20_pin_out = pin[GPIO_DSB_OUT]; - ds18x20_dual_mode = true; - pinMode(ds18x20_pin_out, OUTPUT); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); - } - - OneWireResetSearch(); - - ds18x20_sensors = 0; - while (ds18x20_sensors < DS18X20_MAX_SENSORS) { - if (!OneWireSearch(ds18x20_sensor[ds18x20_sensors].address)) { - break; - } - if (OneWireCrc8(ds18x20_sensor[ds18x20_sensors].address) && - ((ds18x20_sensor[ds18x20_sensors].address[0] == DS18S20_CHIPID) || - (ds18x20_sensor[ds18x20_sensors].address[0] == DS1822_CHIPID) || - (ds18x20_sensor[ds18x20_sensors].address[0] == DS18B20_CHIPID) || - (ds18x20_sensor[ds18x20_sensors].address[0] == MAX31850_CHIPID))) { - ds18x20_sensor[ds18x20_sensors].index = ds18x20_sensors; - ids[ds18x20_sensors] = ds18x20_sensor[ds18x20_sensors].address[0]; - for (uint32_t j = 6; j > 0; j--) { - ids[ds18x20_sensors] = ids[ds18x20_sensors] << 8 | ds18x20_sensor[ds18x20_sensors].address[j]; - } - ds18x20_sensors++; - } - } - for (uint32_t i = 0; i < ds18x20_sensors; i++) { - for (uint32_t j = i + 1; j < ds18x20_sensors; j++) { - if (ids[ds18x20_sensor[i].index] > ids[ds18x20_sensor[j].index]) { - std::swap(ds18x20_sensor[i].index, ds18x20_sensor[j].index); - } - } - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), ds18x20_sensors); -} - -void Ds18x20Convert(void) -{ - OneWireReset(); -#ifdef W1_PARASITE_POWER - - if (++ds18x20_sensor_curr >= ds18x20_sensors) - ds18x20_sensor_curr = 0; - OneWireSelect(ds18x20_sensor[ds18x20_sensor_curr].address); -#else - OneWireWrite(W1_SKIP_ROM); -#endif - OneWireWrite(W1_CONVERT_TEMP); - -} - -bool Ds18x20Read(uint8_t sensor) -{ - uint8_t data[9]; - int8_t sign = 1; - - uint8_t index = ds18x20_sensor[sensor].index; - if (ds18x20_sensor[index].valid) { ds18x20_sensor[index].valid--; } - for (uint32_t retry = 0; retry < 3; retry++) { - OneWireReset(); - OneWireSelect(ds18x20_sensor[index].address); - OneWireWrite(W1_READ_SCRATCHPAD); - for (uint32_t i = 0; i < 9; i++) { - data[i] = OneWireRead(); - } - if (OneWireCrc8(data)) { - switch(ds18x20_sensor[index].address[0]) { - case DS18S20_CHIPID: { - if (data[1] > 0x80) { - data[0] = (~data[0]) +1; - sign = -1; - } - float temp9 = (float)(data[0] >> 1) * sign; - ds18x20_sensor[index].temperature = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); - ds18x20_sensor[index].valid = SENSOR_MAX_MISS; - return true; - } - case DS1822_CHIPID: - case DS18B20_CHIPID: { - if (data[4] != 0x7F) { - data[4] = 0x7F; - OneWireReset(); - OneWireSelect(ds18x20_sensor[index].address); - OneWireWrite(W1_WRITE_SCRATCHPAD); - OneWireWrite(data[2]); - OneWireWrite(data[3]); - OneWireWrite(data[4]); - OneWireSelect(ds18x20_sensor[index].address); - OneWireWrite(W1_WRITE_EEPROM); -#ifdef W1_PARASITE_POWER - w1_power_until = millis() + 10; -#endif - } - uint16_t temp12 = (data[1] << 8) + data[0]; - if (temp12 > 2047) { - temp12 = (~temp12) +1; - sign = -1; - } - ds18x20_sensor[index].temperature = ConvertTemp(sign * temp12 * 0.0625); - ds18x20_sensor[index].valid = SENSOR_MAX_MISS; - return true; - } - case MAX31850_CHIPID: { - int16_t temp14 = (data[1] << 8) + (data[0] & 0xFC); - ds18x20_sensor[index].temperature = ConvertTemp(temp14 * 0.0625); - ds18x20_sensor[index].valid = SENSOR_MAX_MISS; - return true; - } - } - } - } - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR)); - return false; -} - -void Ds18x20Name(uint8_t sensor) -{ - uint8_t index = sizeof(ds18x20_chipids); - while (index) { - if (ds18x20_sensor[ds18x20_sensor[sensor].index].address[0] == ds18x20_chipids[index]) { - break; - } - index--; - } - GetTextIndexed(ds18x20_types, sizeof(ds18x20_types), index, kDs18x20Types); - if (ds18x20_sensors > 1) { - snprintf_P(ds18x20_types, sizeof(ds18x20_types), PSTR("%s%c%d"), ds18x20_types, IndexSeparator(), sensor +1); - } -} - - - -void Ds18x20EverySecond(void) -{ - if (!ds18x20_sensors) { return; } - -#ifdef W1_PARASITE_POWER - - unsigned long now = millis(); - if (now < w1_power_until) - return; -#endif - if (uptime & 1 -#ifdef W1_PARASITE_POWER - - || ds18x20_sensors >= 2 -#endif - ) { - - Ds18x20Convert(); - } else { - for (uint32_t i = 0; i < ds18x20_sensors; i++) { - - if (!Ds18x20Read(i)) { - Ds18x20Name(i); - AddLogMissed(ds18x20_types, ds18x20_sensor[ds18x20_sensor[i].index].valid); -#ifdef USE_DS18x20_RECONFIGURE - if (!ds18x20_sensor[ds18x20_sensor[i].index].valid) { - memset(&ds18x20_sensor, 0, sizeof(ds18x20_sensor)); - Ds18x20Init(); - } -#endif - } - } - } -} - -void Ds18x20Show(bool json) -{ - for (uint32_t i = 0; i < ds18x20_sensors; i++) { - uint8_t index = ds18x20_sensor[i].index; - - if (ds18x20_sensor[index].valid) { - char temperature[33]; - dtostrfd(ds18x20_sensor[index].temperature, Settings.flag2.temperature_resolution, temperature); - - Ds18x20Name(i); - - if (json) { - char address[17]; - for (uint32_t j = 0; j < 6; j++) { - sprintf(address+2*j, "%02X", ds18x20_sensor[index].address[6-j]); - } - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%s}"), ds18x20_types, address, temperature); -#ifdef USE_DOMOTICZ - if ((0 == tele_period) && (0 == i)) { - DomoticzSensor(DZ_TEMP, temperature); - } -#endif -#ifdef USE_KNX - if ((0 == tele_period) && (0 == i)) { - KnxSensor(KNX_TEMPERATURE, ds18x20_sensor[index].temperature); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, ds18x20_types, temperature, TempUnit()); -#endif - } - } - } -} - - - - - -bool Xsns05(uint8_t function) -{ - bool result = false; - - if (pin[GPIO_DSB] < 99) { - switch (function) { - case FUNC_INIT: - Ds18x20Init(); - break; - case FUNC_EVERY_SECOND: - Ds18x20EverySecond(); - break; - case FUNC_JSON_APPEND: - Ds18x20Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Ds18x20Show(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_06_dht.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_06_dht.ino" -#ifdef USE_DHT -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_06_dht.ino" -#define XSNS_06 6 - -#define DHT_MAX_SENSORS 4 -#define DHT_MAX_RETRY 8 - -uint8_t dht_data[5]; -uint8_t dht_sensors = 0; -uint8_t dht_pin_out = 0; -bool dht_active = true; -bool dht_dual_mode = false; - -struct DHTSTRUCT { - uint8_t pin; - uint8_t type; - uint8_t lastresult; - char stype[12]; - float t = NAN; - float h = NAN; -} Dht[DHT_MAX_SENSORS]; - -bool DhtWaitState(uint32_t sensor, uint32_t level) -{ - unsigned long timeout = micros() + 100; - while (digitalRead(Dht[sensor].pin) != level) { - if (TimeReachedUsec(timeout)) { - PrepLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " %s " D_PULSE), - (level) ? D_START_SIGNAL_HIGH : D_START_SIGNAL_LOW); - return false; - } - delayMicroseconds(1); - } - return true; -} - -bool DhtRead(uint32_t sensor) -{ - dht_data[0] = dht_data[1] = dht_data[2] = dht_data[3] = dht_data[4] = 0; - - if (!dht_dual_mode) { - pinMode(Dht[sensor].pin, OUTPUT); - digitalWrite(Dht[sensor].pin, LOW); - } else { - digitalWrite(dht_pin_out, LOW); - } - - switch (Dht[sensor].type) { - case GPIO_DHT11: - delay(19); - break; - case GPIO_DHT22: - delay(2); - break; - case GPIO_SI7021: - delayMicroseconds(500); - break; - } - - if (!dht_dual_mode) { - pinMode(Dht[sensor].pin, INPUT_PULLUP); - } else { - digitalWrite(dht_pin_out, HIGH); - } - - switch (Dht[sensor].type) { - case GPIO_DHT11: - case GPIO_DHT22: - delayMicroseconds(50); - break; - case GPIO_SI7021: - delayMicroseconds(20); - break; - } -# 133 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_06_dht.ino" - uint32_t i = 0; - noInterrupts(); - if (DhtWaitState(sensor, 0) && DhtWaitState(sensor, 1) && DhtWaitState(sensor, 0)) { - for (i = 0; i < 40; i++) { - if (!DhtWaitState(sensor, 1)) { break; } - delayMicroseconds(35); - if (digitalRead(Dht[sensor].pin)) { - dht_data[i / 8] |= (1 << (7 - i % 8)); - } - if (!DhtWaitState(sensor, 0)) { break; } - } - } - interrupts(); - if (i < 40) { return false; } - - uint8_t checksum = (dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) & 0xFF; - if (dht_data[4] != checksum) { - char hex_char[15]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_CHECKSUM_FAILURE " %s =? %02X"), - ToHex_P(dht_data, 5, hex_char, sizeof(hex_char), ' '), checksum); - return false; - } - - float temperature = NAN; - float humidity = NAN; - switch (Dht[sensor].type) { - case GPIO_DHT11: - humidity = dht_data[0]; - temperature = dht_data[2] + ((float)dht_data[3] * 0.1f); - break; - case GPIO_DHT22: - case GPIO_SI7021: - humidity = ((dht_data[0] << 8) | dht_data[1]) * 0.1; - temperature = (((dht_data[2] & 0x7F) << 8 ) | dht_data[3]) * 0.1; - if (dht_data[2] & 0x80) { - temperature *= -1; - } - break; - } - if (isnan(temperature) || isnan(humidity)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT "Invalid NAN reading")); - return false; - } - - if (humidity > 100) { humidity = 100.0; } - if (humidity < 0) { humidity = 0.1; } - Dht[sensor].h = ConvertHumidity(humidity); - Dht[sensor].t = ConvertTemp(temperature); - Dht[sensor].lastresult = 0; - - return true; -} - - - -bool DhtPinState() -{ - if ((XdrvMailbox.index >= GPIO_DHT11) && (XdrvMailbox.index <= GPIO_SI7021)) { - if (dht_sensors < DHT_MAX_SENSORS) { - Dht[dht_sensors].pin = XdrvMailbox.payload; - Dht[dht_sensors].type = XdrvMailbox.index; - dht_sensors++; - XdrvMailbox.index = GPIO_DHT11; - } else { - XdrvMailbox.index = 0; - } - return true; - } - return false; -} - -void DhtInit(void) -{ - if (dht_sensors) { - if (pin[GPIO_DHT11_OUT] < 99) { - dht_pin_out = pin[GPIO_DHT11_OUT]; - dht_dual_mode = true; - dht_sensors = 1; - pinMode(dht_pin_out, OUTPUT); - } - - for (uint32_t i = 0; i < dht_sensors; i++) { - pinMode(Dht[i].pin, INPUT_PULLUP); - Dht[i].lastresult = DHT_MAX_RETRY; - GetTextIndexed(Dht[i].stype, sizeof(Dht[i].stype), Dht[i].type, kSensorNames); - if (dht_sensors > 1) { - snprintf_P(Dht[i].stype, sizeof(Dht[i].stype), PSTR("%s%c%02d"), Dht[i].stype, IndexSeparator(), Dht[i].pin); - } - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT "(v5) " D_SENSORS_FOUND " %d"), dht_sensors); - } else { - dht_active = false; - } -} - -void DhtEverySecond(void) -{ - if (uptime &1) { - for (uint32_t sensor = 0; sensor < dht_sensors; sensor++) { - - if (!DhtRead(sensor)) { - Dht[sensor].lastresult++; - if (Dht[sensor].lastresult > DHT_MAX_RETRY) { - Dht[sensor].t = NAN; - Dht[sensor].h = NAN; - } - } - } - } -} - -void DhtShow(bool json) -{ - for (uint32_t i = 0; i < dht_sensors; i++) { - TempHumDewShow(json, ((0 == tele_period) && (0 == i)), Dht[i].stype, Dht[i].t, Dht[i].h); - } -} - - - - - -bool Xsns06(uint8_t function) -{ - bool result = false; - - if (dht_active) { - switch (function) { - case FUNC_EVERY_SECOND: - DhtEverySecond(); - break; - case FUNC_JSON_APPEND: - DhtShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - DhtShow(0); - break; -#endif - case FUNC_INIT: - DhtInit(); - break; - case FUNC_PIN_STATE: - result = DhtPinState(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_07_sht1x.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_07_sht1x.ino" -#ifdef USE_I2C -#ifdef USE_SHT -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_07_sht1x.ino" -#define XSNS_07 7 -#define XI2C_08 8 - -enum { - SHT1X_CMD_MEASURE_TEMP = B00000011, - SHT1X_CMD_MEASURE_RH = B00000101, - SHT1X_CMD_SOFT_RESET = B00011110 -}; - -uint8_t sht_sda_pin; -uint8_t sht_scl_pin; -uint8_t sht_type = 0; -char sht_types[] = "SHT1X"; -uint8_t sht_valid = 0; -float sht_temperature = 0; -float sht_humidity = 0; - -bool ShtReset(void) -{ - pinMode(sht_sda_pin, INPUT_PULLUP); - pinMode(sht_scl_pin, OUTPUT); - delay(11); - for (uint32_t i = 0; i < 9; i++) { - digitalWrite(sht_scl_pin, HIGH); - digitalWrite(sht_scl_pin, LOW); - } - bool success = ShtSendCommand(SHT1X_CMD_SOFT_RESET); - delay(11); - return success; -} - -bool ShtSendCommand(const uint8_t cmd) -{ - pinMode(sht_sda_pin, OUTPUT); - - digitalWrite(sht_sda_pin, HIGH); - digitalWrite(sht_scl_pin, HIGH); - digitalWrite(sht_sda_pin, LOW); - digitalWrite(sht_scl_pin, LOW); - digitalWrite(sht_scl_pin, HIGH); - digitalWrite(sht_sda_pin, HIGH); - digitalWrite(sht_scl_pin, LOW); - - shiftOut(sht_sda_pin, sht_scl_pin, MSBFIRST, cmd); - - bool ackerror = false; - digitalWrite(sht_scl_pin, HIGH); - pinMode(sht_sda_pin, INPUT_PULLUP); - if (digitalRead(sht_sda_pin) != LOW) { - ackerror = true; - } - digitalWrite(sht_scl_pin, LOW); - delayMicroseconds(1); - if (digitalRead(sht_sda_pin) != HIGH) { - ackerror = true; - } - if (ackerror) { - - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_SHT1 D_SENSOR_DID_NOT_ACK_COMMAND)); - } - return (!ackerror); -} - -bool ShtAwaitResult(void) -{ - - for (uint32_t i = 0; i < 16; i++) { - if (LOW == digitalRead(sht_sda_pin)) { - return true; - } - delay(20); - } - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_SHT1 D_SENSOR_BUSY)); - - return false; -} - -int ShtReadData(void) -{ - int val = 0; - - - val = shiftIn(sht_sda_pin, sht_scl_pin, 8); - val <<= 8; - - pinMode(sht_sda_pin, OUTPUT); - digitalWrite(sht_sda_pin, LOW); - digitalWrite(sht_scl_pin, HIGH); - digitalWrite(sht_scl_pin, LOW); - pinMode(sht_sda_pin, INPUT_PULLUP); - - val |= shiftIn(sht_sda_pin, sht_scl_pin, 8); - - digitalWrite(sht_scl_pin, HIGH); - digitalWrite(sht_scl_pin, LOW); - return val; -} - -bool ShtRead(void) -{ - if (sht_valid) { sht_valid--; } - if (!ShtReset()) { return false; } - if (!ShtSendCommand(SHT1X_CMD_MEASURE_TEMP)) { return false; } - if (!ShtAwaitResult()) { return false; } - float tempRaw = ShtReadData(); - if (!ShtSendCommand(SHT1X_CMD_MEASURE_RH)) { return false; } - if (!ShtAwaitResult()) { return false; } - float humRaw = ShtReadData(); - - - const float d1 = -39.7; - const float d2 = 0.01; - sht_temperature = d1 + (tempRaw * d2); - const float c1 = -2.0468; - const float c2 = 0.0367; - const float c3 = -1.5955E-6; - const float t1 = 0.01; - const float t2 = 0.00008; - float rhLinear = c1 + c2 * humRaw + c3 * humRaw * humRaw; - sht_humidity = (sht_temperature - 25) * (t1 + t2 * humRaw) + rhLinear; - sht_temperature = ConvertTemp(sht_temperature); - sht_humidity = ConvertHumidity(sht_humidity); - - sht_valid = SENSOR_MAX_MISS; - return true; -} - - - -void ShtDetect(void) -{ - sht_sda_pin = pin[GPIO_I2C_SDA]; - sht_scl_pin = pin[GPIO_I2C_SCL]; - if (ShtRead()) { - sht_type = 1; - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_SHT1X_FOUND)); - } else { - Wire.begin(sht_sda_pin, sht_scl_pin); - sht_type = 0; - } -} - -void ShtEverySecond(void) -{ - if (!(uptime %4)) { - - if (!ShtRead()) { - AddLogMissed(sht_types, sht_valid); - } - } -} - -void ShtShow(bool json) -{ - if (sht_valid) { - TempHumDewShow(json, (0 == tele_period), sht_types, sht_temperature, sht_humidity); - } -} - - - - - -bool Xsns07(uint8_t function) -{ - if (!I2cEnabled(XI2C_08)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - ShtDetect(); - } - else if (sht_type) { - switch (function) { - case FUNC_EVERY_SECOND: - ShtEverySecond(); - break; - case FUNC_JSON_APPEND: - ShtShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - ShtShow(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_08_htu21.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_08_htu21.ino" -#ifdef USE_I2C -#ifdef USE_HTU -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_08_htu21.ino" -#define XSNS_08 8 -#define XI2C_09 9 - -#define HTU21_ADDR 0x40 - -#define SI7013_CHIPID 0x0D -#define SI7020_CHIPID 0x14 -#define SI7021_CHIPID 0x15 -#define HTU21_CHIPID 0x32 - -#define HTU21_READTEMP 0xE3 -#define HTU21_READHUM 0xE5 -#define HTU21_WRITEREG 0xE6 -#define HTU21_READREG 0xE7 -#define HTU21_RESET 0xFE -#define HTU21_HEATER_WRITE 0x51 -#define HTU21_HEATER_READ 0x11 -#define HTU21_SERIAL2_READ1 0xFC -#define HTU21_SERIAL2_READ2 0xC9 - -#define HTU21_HEATER_ON 0x04 -#define HTU21_HEATER_OFF 0xFB - -#define HTU21_RES_RH12_T14 0x00 -#define HTU21_RES_RH8_T12 0x01 -#define HTU21_RES_RH10_T13 0x80 -#define HTU21_RES_RH11_T11 0x81 - -#define HTU21_CRC8_POLYNOM 0x13100 - -const char kHtuTypes[] PROGMEM = "HTU21|SI7013|SI7020|SI7021|T/RH?"; - -uint8_t htu_address; -uint8_t htu_type = 0; -uint8_t htu_delay_temp; -uint8_t htu_delay_humidity = 50; -uint8_t htu_valid = 0; -float htu_temperature = 0; -float htu_humidity = 0; -char htu_types[7]; - -uint8_t HtuCheckCrc8(uint16_t data) -{ - for (uint32_t bit = 0; bit < 16; bit++) { - if (data & 0x8000) { - data = (data << 1) ^ HTU21_CRC8_POLYNOM; - } else { - data <<= 1; - } - } - return data >>= 8; -} - -uint8_t HtuReadDeviceId(void) -{ - uint16_t deviceID = 0; - uint8_t checksum = 0; - - Wire.beginTransmission(HTU21_ADDR); - Wire.write(HTU21_SERIAL2_READ1); - Wire.write(HTU21_SERIAL2_READ2); - Wire.endTransmission(); - - Wire.requestFrom(HTU21_ADDR, 3); - deviceID = Wire.read() << 8; - deviceID |= Wire.read(); - checksum = Wire.read(); - if (HtuCheckCrc8(deviceID) == checksum) { - deviceID = deviceID >> 8; - } else { - deviceID = 0; - } - return (uint8_t)deviceID; -} - -void HtuSetResolution(uint8_t resolution) -{ - uint8_t current = I2cRead8(HTU21_ADDR, HTU21_READREG); - current &= 0x7E; - current |= resolution; - I2cWrite8(HTU21_ADDR, HTU21_WRITEREG, current); -} - -void HtuReset(void) -{ - Wire.beginTransmission(HTU21_ADDR); - Wire.write(HTU21_RESET); - Wire.endTransmission(); - delay(15); -} - -void HtuHeater(uint8_t heater) -{ - uint8_t current = I2cRead8(HTU21_ADDR, HTU21_READREG); - - switch(heater) - { - case HTU21_HEATER_ON : current |= heater; - break; - case HTU21_HEATER_OFF : current &= heater; - break; - default : current &= heater; - break; - } - I2cWrite8(HTU21_ADDR, HTU21_WRITEREG, current); -} - -void HtuInit(void) -{ - HtuReset(); - HtuHeater(HTU21_HEATER_OFF); - HtuSetResolution(HTU21_RES_RH12_T14); -} - -bool HtuRead(void) -{ - uint8_t checksum = 0; - uint16_t sensorval = 0; - - if (htu_valid) { htu_valid--; } - - Wire.beginTransmission(HTU21_ADDR); - Wire.write(HTU21_READTEMP); - if (Wire.endTransmission() != 0) { return false; } - delay(htu_delay_temp); - - Wire.requestFrom(HTU21_ADDR, 3); - if (3 == Wire.available()) { - sensorval = Wire.read() << 8; - sensorval |= Wire.read(); - checksum = Wire.read(); - } - if (HtuCheckCrc8(sensorval) != checksum) { return false; } - - htu_temperature = ConvertTemp(0.002681 * (float)sensorval - 46.85); - - Wire.beginTransmission(HTU21_ADDR); - Wire.write(HTU21_READHUM); - if (Wire.endTransmission() != 0) { return false; } - delay(htu_delay_humidity); - - Wire.requestFrom(HTU21_ADDR, 3); - if (3 <= Wire.available()) { - sensorval = Wire.read() << 8; - sensorval |= Wire.read(); - checksum = Wire.read(); - } - if (HtuCheckCrc8(sensorval) != checksum) { return false; } - - sensorval ^= 0x02; - htu_humidity = 0.001907 * (float)sensorval - 6; - if (htu_humidity > 100) { htu_humidity = 100.0; } - if (htu_humidity < 0) { htu_humidity = 0.01; } - - if ((0.00 == htu_humidity) && (0.00 == htu_temperature)) { - htu_humidity = 0.0; - } - if ((htu_temperature > 0.00) && (htu_temperature < 80.00)) { - htu_humidity = (-0.15) * (25 - htu_temperature) + htu_humidity; - } - htu_humidity = ConvertHumidity(htu_humidity); - - htu_valid = SENSOR_MAX_MISS; - return true; -} - - - -void HtuDetect(void) -{ - htu_address = HTU21_ADDR; - if (I2cActive(htu_address)) { return; } - - htu_type = HtuReadDeviceId(); - if (htu_type) { - uint8_t index = 0; - HtuInit(); - switch (htu_type) { - case HTU21_CHIPID: - htu_delay_temp = 50; - htu_delay_humidity = 16; - break; - case SI7021_CHIPID: - index++; - case SI7020_CHIPID: - index++; - case SI7013_CHIPID: - index++; - htu_delay_temp = 12; - htu_delay_humidity = 23; - break; - default: - index = 4; - htu_delay_temp = 50; - htu_delay_humidity = 23; - } - GetTextIndexed(htu_types, sizeof(htu_types), index, kHtuTypes); - I2cSetActiveFound(htu_address, htu_types); - } -} - -void HtuEverySecond(void) -{ - if (uptime &1) { - - if (!HtuRead()) { - AddLogMissed(htu_types, htu_valid); - } - } -} - -void HtuShow(bool json) -{ - if (htu_valid) { - TempHumDewShow(json, (0 == tele_period), htu_types, htu_temperature, htu_humidity); - } -} - - - - - -bool Xsns08(uint8_t function) -{ - if (!I2cEnabled(XI2C_09)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - HtuDetect(); - } - else if (htu_type) { - switch (function) { - case FUNC_EVERY_SECOND: - HtuEverySecond(); - break; - case FUNC_JSON_APPEND: - HtuShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HtuShow(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_09_bmp.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_09_bmp.ino" -#ifdef USE_I2C -#ifdef USE_BMP -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_09_bmp.ino" -#define XSNS_09 9 -#define XI2C_10 10 - -#define BMP_ADDR1 0x76 -#define BMP_ADDR2 0x77 - -#define BMP180_CHIPID 0x55 -#define BMP280_CHIPID 0x58 -#define BME280_CHIPID 0x60 -#define BME680_CHIPID 0x61 - -#define BMP_REGISTER_CHIPID 0xD0 - -#define BMP_REGISTER_RESET 0xE0 - -#define BMP_CMND_RESET 0xB6 - -#define BMP_MAX_SENSORS 2 - -const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280|BME680"; - -typedef struct { - uint8_t bmp_address; - char bmp_name[7]; - uint8_t bmp_type; - uint8_t bmp_model; -#ifdef USE_BME680 - uint8_t bme680_state; - float bmp_gas_resistance; -#endif - float bmp_temperature; - float bmp_pressure; - float bmp_humidity; -} bmp_sensors_t; - -uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 }; -uint8_t bmp_count = 0; -uint8_t bmp_once = 1; - -bmp_sensors_t *bmp_sensors = nullptr; - - - - - -#define BMP180_REG_CONTROL 0xF4 -#define BMP180_REG_RESULT 0xF6 -#define BMP180_TEMPERATURE 0x2E -#define BMP180_PRESSURE3 0xF4 - -#define BMP180_AC1 0xAA -#define BMP180_AC2 0xAC -#define BMP180_AC3 0xAE -#define BMP180_AC4 0xB0 -#define BMP180_AC5 0xB2 -#define BMP180_AC6 0xB4 -#define BMP180_VB1 0xB6 -#define BMP180_VB2 0xB8 -#define BMP180_MB 0xBA -#define BMP180_MC 0xBC -#define BMP180_MD 0xBE - -#define BMP180_OSS 3 - -typedef struct { - int16_t cal_ac1; - int16_t cal_ac2; - int16_t cal_ac3; - int16_t cal_b1; - int16_t cal_b2; - int16_t cal_mc; - int16_t cal_md; - uint16_t cal_ac4; - uint16_t cal_ac5; - uint16_t cal_ac6; -} bmp180_cal_data_t; - -bmp180_cal_data_t *bmp180_cal_data = nullptr; - -bool Bmp180Calibration(uint8_t bmp_idx) -{ - if (!bmp180_cal_data) { - bmp180_cal_data = (bmp180_cal_data_t*)malloc(BMP_MAX_SENSORS * sizeof(bmp180_cal_data_t)); - } - if (!bmp180_cal_data) { return false; } - - bmp180_cal_data[bmp_idx].cal_ac1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC1); - bmp180_cal_data[bmp_idx].cal_ac2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC2); - bmp180_cal_data[bmp_idx].cal_ac3 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC3); - bmp180_cal_data[bmp_idx].cal_ac4 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC4); - bmp180_cal_data[bmp_idx].cal_ac5 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC5); - bmp180_cal_data[bmp_idx].cal_ac6 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC6); - bmp180_cal_data[bmp_idx].cal_b1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB1); - bmp180_cal_data[bmp_idx].cal_b2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB2); - bmp180_cal_data[bmp_idx].cal_mc = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MC); - bmp180_cal_data[bmp_idx].cal_md = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MD); - - - if (!bmp180_cal_data[bmp_idx].cal_ac1 | - !bmp180_cal_data[bmp_idx].cal_ac2 | - !bmp180_cal_data[bmp_idx].cal_ac3 | - !bmp180_cal_data[bmp_idx].cal_ac4 | - !bmp180_cal_data[bmp_idx].cal_ac5 | - !bmp180_cal_data[bmp_idx].cal_ac6 | - !bmp180_cal_data[bmp_idx].cal_b1 | - !bmp180_cal_data[bmp_idx].cal_b2 | - !bmp180_cal_data[bmp_idx].cal_mc | - !bmp180_cal_data[bmp_idx].cal_md) { - return false; - } - - if ((bmp180_cal_data[bmp_idx].cal_ac1 == (int16_t)0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_ac2 == (int16_t)0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_ac3 == (int16_t)0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_ac4 == 0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_ac5 == 0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_ac6 == 0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_b1 == (int16_t)0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_b2 == (int16_t)0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_mc == (int16_t)0xFFFF) | - (bmp180_cal_data[bmp_idx].cal_md == (int16_t)0xFFFF)) { - return false; - } - return true; -} - -void Bmp180Read(uint8_t bmp_idx) -{ - if (!bmp180_cal_data) { return; } - - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); - delay(5); - int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); - int32_t xt1 = (ut - (int32_t)bmp180_cal_data[bmp_idx].cal_ac6) * ((int32_t)bmp180_cal_data[bmp_idx].cal_ac5) >> 15; - int32_t xt2 = ((int32_t)bmp180_cal_data[bmp_idx].cal_mc << 11) / (xt1 + (int32_t)bmp180_cal_data[bmp_idx].cal_md); - int32_t bmp180_b5 = xt1 + xt2; - bmp_sensors[bmp_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0; - - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); - delay(2 + (4 << BMP180_OSS)); - uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); - up >>= (8 - BMP180_OSS); - - int32_t b6 = bmp180_b5 - 4000; - int32_t x1 = ((int32_t)bmp180_cal_data[bmp_idx].cal_b2 * ((b6 * b6) >> 12)) >> 11; - int32_t x2 = ((int32_t)bmp180_cal_data[bmp_idx].cal_ac2 * b6) >> 11; - int32_t x3 = x1 + x2; - int32_t b3 = ((((int32_t)bmp180_cal_data[bmp_idx].cal_ac1 * 4 + x3) << BMP180_OSS) + 2) >> 2; - - x1 = ((int32_t)bmp180_cal_data[bmp_idx].cal_ac3 * b6) >> 13; - x2 = ((int32_t)bmp180_cal_data[bmp_idx].cal_b1 * ((b6 * b6) >> 12)) >> 16; - x3 = ((x1 + x2) + 2) >> 2; - uint32_t b4 = ((uint32_t)bmp180_cal_data[bmp_idx].cal_ac4 * (uint32_t)(x3 + 32768)) >> 15; - uint32_t b7 = ((uint32_t)up - b3) * (uint32_t)(50000UL >> BMP180_OSS); - - int32_t p; - if (b7 < 0x80000000) { - p = (b7 * 2) / b4; - } - else { - p = (b7 / b4) * 2; - } - x1 = (p >> 8) * (p >> 8); - x1 = (x1 * 3038) >> 16; - x2 = (-7357 * p) >> 16; - p += ((x1 + x2 + (int32_t)3791) >> 4); - bmp_sensors[bmp_idx].bmp_pressure = (float)p / 100.0; -} - - - - - - - -#define BME280_REGISTER_CONTROLHUMID 0xF2 -#define BME280_REGISTER_CONTROL 0xF4 -#define BME280_REGISTER_CONFIG 0xF5 -#define BME280_REGISTER_PRESSUREDATA 0xF7 -#define BME280_REGISTER_TEMPDATA 0xFA -#define BME280_REGISTER_HUMIDDATA 0xFD - -#define BME280_REGISTER_DIG_T1 0x88 -#define BME280_REGISTER_DIG_T2 0x8A -#define BME280_REGISTER_DIG_T3 0x8C -#define BME280_REGISTER_DIG_P1 0x8E -#define BME280_REGISTER_DIG_P2 0x90 -#define BME280_REGISTER_DIG_P3 0x92 -#define BME280_REGISTER_DIG_P4 0x94 -#define BME280_REGISTER_DIG_P5 0x96 -#define BME280_REGISTER_DIG_P6 0x98 -#define BME280_REGISTER_DIG_P7 0x9A -#define BME280_REGISTER_DIG_P8 0x9C -#define BME280_REGISTER_DIG_P9 0x9E -#define BME280_REGISTER_DIG_H1 0xA1 -#define BME280_REGISTER_DIG_H2 0xE1 -#define BME280_REGISTER_DIG_H3 0xE3 -#define BME280_REGISTER_DIG_H4 0xE4 -#define BME280_REGISTER_DIG_H5 0xE5 -#define BME280_REGISTER_DIG_H6 0xE7 - -typedef struct { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; - int16_t dig_H2; - int16_t dig_H4; - int16_t dig_H5; - uint8_t dig_H1; - uint8_t dig_H3; - int8_t dig_H6; -} Bme280CalibrationData_t; - -Bme280CalibrationData_t *Bme280CalibrationData = nullptr; - -bool Bmx280Calibrate(uint8_t bmp_idx) -{ - - - if (!Bme280CalibrationData) { - Bme280CalibrationData = (Bme280CalibrationData_t*)malloc(BMP_MAX_SENSORS * sizeof(Bme280CalibrationData_t)); - } - if (!Bme280CalibrationData) { return false; } - - Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1); - Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2); - Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3); - Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1); - Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2); - Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3); - Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4); - Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5); - Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6); - Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7); - Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8); - Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9); - if (BME280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { - Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1); - Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2); - Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3); - Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF); - Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5) >> 4); - Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6); - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00); - - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0); - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27); - } else { - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7); - } - - return true; -} - -void Bme280Read(uint8_t bmp_idx) -{ - if (!Bme280CalibrationData) { return; } - - int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA); - adc_T >>= 4; - - int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1 << 1))) * ((int32_t)Bme280CalibrationData[bmp_idx].dig_T2)) >> 11; - int32_t vart2 = (((((adc_T >> 4) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1)) * ((adc_T >> 4) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1))) >> 12) * - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T3)) >> 14; - int32_t t_fine = vart1 + vart2; - float T = (t_fine * 5 + 128) >> 8; - bmp_sensors[bmp_idx].bmp_temperature = T / 100.0; - - int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA); - adc_P >>= 4; - - int64_t var1 = ((int64_t)t_fine) - 128000; - int64_t var2 = var1 * var1 * (int64_t)Bme280CalibrationData[bmp_idx].dig_P6; - var2 = var2 + ((var1 * (int64_t)Bme280CalibrationData[bmp_idx].dig_P5) << 17); - var2 = var2 + (((int64_t)Bme280CalibrationData[bmp_idx].dig_P4) << 35); - var1 = ((var1 * var1 * (int64_t)Bme280CalibrationData[bmp_idx].dig_P3) >> 8) + ((var1 * (int64_t)Bme280CalibrationData[bmp_idx].dig_P2) << 12); - var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)Bme280CalibrationData[bmp_idx].dig_P1) >> 33; - if (0 == var1) { - return; - } - int64_t p = 1048576 - adc_P; - p = (((p << 31) - var2) * 3125) / var1; - var1 = (((int64_t)Bme280CalibrationData[bmp_idx].dig_P9) * (p >> 13) * (p >> 13)) >> 25; - var2 = (((int64_t)Bme280CalibrationData[bmp_idx].dig_P8) * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((int64_t)Bme280CalibrationData[bmp_idx].dig_P7) << 4); - bmp_sensors[bmp_idx].bmp_pressure = (float)p / 25600.0; - - if (BMP280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { return; } - - int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA); - - int32_t v_x1_u32r = (t_fine - ((int32_t)76800)); - v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H4) << 20) - - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * - (((((((v_x1_u32r * ((int32_t)Bme280CalibrationData[bmp_idx].dig_H6)) >> 10) * - (((v_x1_u32r * ((int32_t)Bme280CalibrationData[bmp_idx].dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + - ((int32_t)2097152)) * ((int32_t)Bme280CalibrationData[bmp_idx].dig_H2) + 8192) >> 14)); - v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * - ((int32_t)Bme280CalibrationData[bmp_idx].dig_H1)) >> 4)); - v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; - v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; - float h = (v_x1_u32r >> 12); - bmp_sensors[bmp_idx].bmp_humidity = h / 1024.0; -} - -#ifdef USE_BME680 - - - - -#include - -struct bme680_dev *gas_sensor = nullptr; - -static void BmeDelayMs(uint32_t ms) -{ - delay(ms); -} - -bool Bme680Init(uint8_t bmp_idx) -{ - if (!gas_sensor) { - gas_sensor = (bme680_dev*)malloc(BMP_MAX_SENSORS * sizeof(bme680_dev)); - } - if (!gas_sensor) { return false; } - - gas_sensor[bmp_idx].dev_id = bmp_sensors[bmp_idx].bmp_address; - gas_sensor[bmp_idx].intf = BME680_I2C_INTF; - gas_sensor[bmp_idx].read = &I2cReadBuffer; - gas_sensor[bmp_idx].write = &I2cWriteBuffer; - gas_sensor[bmp_idx].delay_ms = BmeDelayMs; - - - - gas_sensor[bmp_idx].amb_temp = 25; - - int8_t rslt = BME680_OK; - rslt = bme680_init(&gas_sensor[bmp_idx]); - if (rslt != BME680_OK) { return false; } - - - gas_sensor[bmp_idx].tph_sett.os_hum = BME680_OS_2X; - gas_sensor[bmp_idx].tph_sett.os_pres = BME680_OS_4X; - gas_sensor[bmp_idx].tph_sett.os_temp = BME680_OS_8X; - gas_sensor[bmp_idx].tph_sett.filter = BME680_FILTER_SIZE_3; - - - gas_sensor[bmp_idx].gas_sett.run_gas = BME680_ENABLE_GAS_MEAS; - - gas_sensor[bmp_idx].gas_sett.heatr_temp = 320; - gas_sensor[bmp_idx].gas_sett.heatr_dur = 150; - - - - gas_sensor[bmp_idx].power_mode = BME680_FORCED_MODE; - - - uint8_t set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL; - - - rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor[bmp_idx]); - if (rslt != BME680_OK) { return false; } - - bmp_sensors[bmp_idx].bme680_state = 0; - - return true; -} - -void Bme680Read(uint8_t bmp_idx) -{ - if (!gas_sensor) { return; } - - int8_t rslt = BME680_OK; - - if (BME680_CHIPID == bmp_sensors[bmp_idx].bmp_type) { - if (0 == bmp_sensors[bmp_idx].bme680_state) { - - rslt = bme680_set_sensor_mode(&gas_sensor[bmp_idx]); - if (rslt != BME680_OK) { return; } - - - - - - - - bmp_sensors[bmp_idx].bme680_state = 1; - } else { - bmp_sensors[bmp_idx].bme680_state = 0; - - struct bme680_field_data data; - rslt = bme680_get_sensor_data(&data, &gas_sensor[bmp_idx]); - if (rslt != BME680_OK) { return; } - - bmp_sensors[bmp_idx].bmp_temperature = data.temperature / 100.0; - bmp_sensors[bmp_idx].bmp_humidity = data.humidity / 1000.0; - bmp_sensors[bmp_idx].bmp_pressure = data.pressure / 100.0; - - if (data.status & BME680_GASM_VALID_MSK) { - bmp_sensors[bmp_idx].bmp_gas_resistance = data.gas_resistance / 1000.0; - } else { - bmp_sensors[bmp_idx].bmp_gas_resistance = 0; - } - } - } - return; -} - -#endif - - - -void BmpDetect(void) -{ - int bmp_sensor_size = BMP_MAX_SENSORS * sizeof(bmp_sensors_t); - if (!bmp_sensors) { - bmp_sensors = (bmp_sensors_t*)malloc(bmp_sensor_size); - } - if (!bmp_sensors) { return; } - memset(bmp_sensors, 0, bmp_sensor_size); - - for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) { - if (I2cActive(bmp_addresses[i])) { continue; } - uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); - if (bmp_type) { - bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; - bmp_sensors[bmp_count].bmp_type = bmp_type; - bmp_sensors[bmp_count].bmp_model = 0; - - bool success = false; - switch (bmp_type) { - case BMP180_CHIPID: - success = Bmp180Calibration(bmp_count); - break; - case BME280_CHIPID: - bmp_sensors[bmp_count].bmp_model++; - case BMP280_CHIPID: - bmp_sensors[bmp_count].bmp_model++; - success = Bmx280Calibrate(bmp_count); - break; -#ifdef USE_BME680 - case BME680_CHIPID: - bmp_sensors[bmp_count].bmp_model = 3; - success = Bme680Init(bmp_count); - break; -#endif - } - if (success) { - GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes); - I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name); - bmp_count++; - } - } - } -} - -void BmpRead(void) -{ - for (uint32_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { - switch (bmp_sensors[bmp_idx].bmp_type) { - case BMP180_CHIPID: - Bmp180Read(bmp_idx); - break; - case BMP280_CHIPID: - case BME280_CHIPID: - Bme280Read(bmp_idx); - break; -#ifdef USE_BME680 - case BME680_CHIPID: - Bme680Read(bmp_idx); - break; -#endif - } - } -} - -void BmpShow(bool json) -{ - for (uint32_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { - if (bmp_sensors[bmp_idx].bmp_type) { - float bmp_sealevel = 0.0; - if (bmp_sensors[bmp_idx].bmp_pressure != 0.0) { - bmp_sealevel = (bmp_sensors[bmp_idx].bmp_pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6; - bmp_sealevel = ConvertPressure(bmp_sealevel); - } - float bmp_temperature = ConvertTemp(bmp_sensors[bmp_idx].bmp_temperature); - float bmp_pressure = ConvertPressure(bmp_sensors[bmp_idx].bmp_pressure); - - char name[10]; - strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(name)); - if (bmp_count > 1) { - snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); - } - - char temperature[33]; - dtostrfd(bmp_temperature, Settings.flag2.temperature_resolution, temperature); - char pressure[33]; - dtostrfd(bmp_pressure, Settings.flag2.pressure_resolution, pressure); - char sea_pressure[33]; - dtostrfd(bmp_sealevel, Settings.flag2.pressure_resolution, sea_pressure); - - float bmp_humidity = ConvertHumidity(bmp_sensors[bmp_idx].bmp_humidity); - char humidity[33]; - dtostrfd(bmp_humidity, Settings.flag2.humidity_resolution, humidity); - float f_dewpoint = CalcTempHumToDew(bmp_temperature, bmp_humidity); - char dewpoint[33]; - dtostrfd(f_dewpoint, Settings.flag2.temperature_resolution, dewpoint); -#ifdef USE_BME680 - char gas_resistance[33]; - dtostrfd(bmp_sensors[bmp_idx].bmp_gas_resistance, 2, gas_resistance); -#endif - - if (json) { - char json_humidity[80]; - snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s,\"" D_JSON_DEWPOINT "\":%s"), humidity, dewpoint); - char json_sealevel[40]; - snprintf_P(json_sealevel, sizeof(json_sealevel), PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure); -#ifdef USE_BME680 - char json_gas[40]; - snprintf_P(json_gas, sizeof(json_gas), PSTR(",\"" D_JSON_GAS "\":%s"), gas_resistance); - - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s%s}"), - name, - temperature, - (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", - pressure, - (Settings.altitude != 0) ? json_sealevel : "", - (bmp_sensors[bmp_idx].bmp_model >= 3) ? json_gas : ""); -#else - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s,\"" D_JSON_PRESSURE "\":%s%s}"), - name, temperature, (bmp_sensors[bmp_idx].bmp_model >= 2) ? json_humidity : "", pressure, (Settings.altitude != 0) ? json_sealevel : ""); -#endif - -#ifdef USE_DOMOTICZ - if ((0 == tele_period) && (0 == bmp_idx)) { - DomoticzTempHumPressureSensor(bmp_temperature, bmp_humidity, bmp_pressure); -#ifdef USE_BME680 - if (bmp_sensors[bmp_idx].bmp_model >= 3) { DomoticzSensor(DZ_AIRQUALITY, (uint32_t)bmp_sensors[bmp_idx].bmp_gas_resistance); } -#endif - } -#endif - -#ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, bmp_temperature); - KnxSensor(KNX_HUMIDITY, bmp_humidity); - } -#endif - -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, name, temperature, TempUnit()); - if (bmp_sensors[bmp_idx].bmp_model >= 2) { - WSContentSend_PD(HTTP_SNS_HUM, name, humidity); - WSContentSend_PD(HTTP_SNS_DEW, name, dewpoint, TempUnit()); - } - WSContentSend_PD(HTTP_SNS_PRESSURE, name, pressure, PressureUnit().c_str()); - if (Settings.altitude != 0) { - WSContentSend_PD(HTTP_SNS_SEAPRESSURE, name, sea_pressure, PressureUnit().c_str()); - } -#ifdef USE_BME680 - if (bmp_sensors[bmp_idx].bmp_model >= 3) { - WSContentSend_PD(PSTR("{s}%s " D_GAS "{m}%s " D_UNIT_KILOOHM "{e}"), name, gas_resistance); - } -#endif - -#endif - } - } - } -} - -#ifdef USE_DEEPSLEEP - -void BMP_EnterSleep(void) -{ - for (uint32_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { - switch (bmp_sensors[bmp_idx].bmp_type) { - case BMP180_CHIPID: - case BMP280_CHIPID: - case BME280_CHIPID: - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET); - break; - default: - break; - } - } -} - -#endif - - - - - -bool Xsns09(uint8_t function) -{ - if (!I2cEnabled(XI2C_10)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - BmpDetect(); - } - else if (bmp_count) { - switch (function) { - case FUNC_EVERY_SECOND: - BmpRead(); - break; - case FUNC_JSON_APPEND: - BmpShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - BmpShow(0); - break; -#endif -#ifdef USE_DEEPSLEEP - case FUNC_SAVE_BEFORE_RESTART: - BMP_EnterSleep(); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_10_bh1750.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_10_bh1750.ino" -#ifdef USE_I2C -#ifdef USE_BH1750 - - - - - - -#define XSNS_10 10 -#define XI2C_11 11 - -#define BH1750_ADDR1 0x23 -#define BH1750_ADDR2 0x5C - -#define BH1750_CONTINUOUS_HIGH_RES_MODE2 0x11 -#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 -#define BH1750_CONTINUOUS_LOW_RES_MODE 0x13 - -#define BH1750_MEASUREMENT_TIME_HIGH 0x40 -#define BH1750_MEASUREMENT_TIME_LOW 0x60 - -struct BH1750DATA { - uint8_t address; - uint8_t addresses[2] = { BH1750_ADDR1, BH1750_ADDR2 }; - uint8_t resolution[3] = { BH1750_CONTINUOUS_HIGH_RES_MODE, BH1750_CONTINUOUS_HIGH_RES_MODE2, BH1750_CONTINUOUS_LOW_RES_MODE }; - uint8_t type = 0; - uint8_t valid = 0; - uint8_t mtreg = 69; - uint16_t illuminance = 0; - char types[7] = "BH1750"; -} Bh1750; - - - -bool Bh1750SetResolution(void) -{ - Wire.beginTransmission(Bh1750.address); - Wire.write(Bh1750.resolution[Settings.SensorBits1.bh1750_resolution]); - return (!Wire.endTransmission()); -} - -bool Bh1750SetMTreg(void) -{ - Wire.beginTransmission(Bh1750.address); - uint8_t data = BH1750_MEASUREMENT_TIME_HIGH | ((Bh1750.mtreg >> 5) & 0x07); - Wire.write(data); - if (Wire.endTransmission()) { return false; } - Wire.beginTransmission(Bh1750.address); - data = BH1750_MEASUREMENT_TIME_LOW | (Bh1750.mtreg & 0x1F); - Wire.write(data); - if (Wire.endTransmission()) { return false; } - return Bh1750SetResolution(); -} - -bool Bh1750Read(void) -{ - if (Bh1750.valid) { Bh1750.valid--; } - - if (2 != Wire.requestFrom(Bh1750.address, (uint8_t)2)) { return false; } - float illuminance = (Wire.read() << 8) | Wire.read(); - illuminance /= (1.2 * (69 / (float)Bh1750.mtreg)); - if (1 == Settings.SensorBits1.bh1750_resolution) { - illuminance /= 2; - } - Bh1750.illuminance = illuminance; - - Bh1750.valid = SENSOR_MAX_MISS; - return true; -} - - - -void Bh1750Detect(void) -{ - for (uint32_t i = 0; i < sizeof(Bh1750.addresses); i++) { - Bh1750.address = Bh1750.addresses[i]; - if (I2cActive(Bh1750.address)) { continue; } - - if (Bh1750SetMTreg()) { - I2cSetActiveFound(Bh1750.address, Bh1750.types); - Bh1750.type = 1; - break; - } - } -} - -void Bh1750EverySecond(void) -{ - - if (!Bh1750Read()) { - AddLogMissed(Bh1750.types, Bh1750.valid); - } -} -# 123 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_10_bh1750.ino" -bool Bh1750CommandSensor(void) -{ - if (XdrvMailbox.data_len) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { - Settings.SensorBits1.bh1750_resolution = XdrvMailbox.payload; - Bh1750SetResolution(); - } - else if ((XdrvMailbox.payload > 30) && (XdrvMailbox.payload < 255)) { - Bh1750.mtreg = XdrvMailbox.payload; - Bh1750SetMTreg(); - } - } - Response_P(PSTR("{\"" D_CMND_SENSOR "10\":{\"Resolution\":%d,\"MTime\":%d}}"), Settings.SensorBits1.bh1750_resolution, Bh1750.mtreg); - - return true; -} - -void Bh1750Show(bool json) -{ - if (Bh1750.valid) { - if (json) { - ResponseAppend_P(JSON_SNS_ILLUMINANCE, Bh1750.types, Bh1750.illuminance); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_ILLUMINANCE, Bh1750.illuminance); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_ILLUMINANCE, Bh1750.types, Bh1750.illuminance); -#endif - } - } -} - - - - - -bool Xsns10(uint8_t function) -{ - if (!I2cEnabled(XI2C_11)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Bh1750Detect(); - } - else if (Bh1750.type) { - switch (function) { - case FUNC_EVERY_SECOND: - Bh1750EverySecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_10 == XdrvMailbox.index) { - result = Bh1750CommandSensor(); - } - break; - case FUNC_JSON_APPEND: - Bh1750Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Bh1750Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_11_veml6070.ino" -# 89 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_11_veml6070.ino" -#ifdef USE_I2C -#ifdef USE_VEML6070 - - - - - - -#define XSNS_11 11 -#define XI2C_12 12 - -#define VEML6070_ADDR_H 0x39 -#define VEML6070_ADDR_L 0x38 -#define VEML6070_INTEGRATION_TIME 3 -#define VEML6070_ENABLE 1 -#define VEML6070_DISABLE 0 -#define VEML6070_RSET_DEFAULT 270000 -#define VEML6070_UV_MAX_INDEX 15 -#define VEML6070_UV_MAX_DEFAULT 11 -#define VEML6070_POWER_COEFFCIENT 0.025 -#define VEML6070_TABLE_COEFFCIENT 32.86270591 - - - - - -const char kVemlTypes[] PROGMEM = "VEML6070"; -double uv_risk_map[VEML6070_UV_MAX_INDEX] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; -double uvrisk = 0; -double uvpower = 0; -uint16_t uvlevel = 0; -uint8_t veml6070_addr_low = VEML6070_ADDR_L; -uint8_t veml6070_addr_high = VEML6070_ADDR_H; -uint8_t itime = VEML6070_INTEGRATION_TIME; -uint8_t veml6070_type = 0; -char veml6070_name[9]; -char str_uvrisk_text[10]; - - - -void Veml6070Detect(void) -{ - if (I2cActive(VEML6070_ADDR_L)) { return; } - - - Wire.beginTransmission(VEML6070_ADDR_L); - Wire.write((itime << 2) | 0x02); - uint8_t status = Wire.endTransmission(); - - if (!status) { - veml6070_type = 1; - Veml6070UvTableInit(); - uint8_t veml_model = 0; - GetTextIndexed(veml6070_name, sizeof(veml6070_name), veml_model, kVemlTypes); - I2cSetActiveFound(VEML6070_ADDR_L, veml6070_name); - } -} - - - -void Veml6070UvTableInit(void) -{ - - for (uint32_t i = 0; i < VEML6070_UV_MAX_INDEX; i++) { -#ifdef USE_VEML6070_RSET - if ( (USE_VEML6070_RSET >= 220000) && (USE_VEML6070_RSET <= 1000000) ) { - uv_risk_map[i] = ( (USE_VEML6070_RSET / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); - } else { - uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 resistor error %d"), USE_VEML6070_RSET); - } -#else - uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 resistor default used %d"), VEML6070_RSET_DEFAULT); -#endif - } -} - - - -void Veml6070EverySecond(void) -{ - - Veml6070ModeCmd(1); - uvlevel = Veml6070ReadUv(); - uvrisk = Veml6070UvRiskLevel(uvlevel); - uvpower = Veml6070UvPower(uvrisk); - Veml6070ModeCmd(0); -} - - - -void Veml6070ModeCmd(bool mode_cmd) -{ - - - Wire.beginTransmission(VEML6070_ADDR_L); - Wire.write((mode_cmd << 0) | 0x02 | (itime << 2)); - uint8_t status = Wire.endTransmission(); - - if (!status) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 mode_cmd")); - } -} - - - -uint16_t Veml6070ReadUv(void) -{ - uint16_t uv_raw = 0; - - if (Wire.requestFrom(VEML6070_ADDR_H, 1) != 1) { - return -1; - } - uv_raw = Wire.read(); - uv_raw <<= 8; - - if (Wire.requestFrom(VEML6070_ADDR_L, 1) != 1) { - return -1; - } - uv_raw |= Wire.read(); - - return uv_raw; -} - - - -double Veml6070UvRiskLevel(uint16_t uv_level) -{ - double risk = 0; - if (uv_level < uv_risk_map[VEML6070_UV_MAX_INDEX-1]) { - risk = (double)uv_level / uv_risk_map[0]; - - if ( (risk >= 0) && (risk <= 2.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_1); } - else if ( (risk >= 3.0) && (risk <= 5.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_2); } - else if ( (risk >= 6.0) && (risk <= 7.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_3); } - else if ( (risk >= 8.0) && (risk <= 10.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_4); } - else if ( (risk >= 11.0) && (risk <= 12.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_5); } - else if ( (risk >= 13.0) && (risk <= 25.0) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_6); } - else { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_7); } - return risk; - } else { - - snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_7); - return ( risk = 99 ); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "VEML6070 out of range %d"), risk); - } -} - - - -double Veml6070UvPower(double uvrisk) -{ - - double power = 0; - return ( power = VEML6070_POWER_COEFFCIENT * uvrisk ); -} - - - - -#ifdef USE_WEBSERVER - -#ifdef USE_VEML6070_SHOW_RAW - const char HTTP_SNS_UV_LEVEL[] PROGMEM = "{s}VEML6070 " D_UV_LEVEL "{m}%s " D_UNIT_INCREMENTS "{e}"; -#endif - - const char HTTP_SNS_UV_INDEX[] PROGMEM = "{s}VEML6070 " D_UV_INDEX "{m}%s %s{e}"; - const char HTTP_SNS_UV_POWER[] PROGMEM = "{s}VEML6070 " D_UV_POWER "{m}%s " D_UNIT_WATT_METER_QUADRAT "{e}"; -#endif - - - -void Veml6070Show(bool json) -{ - - char str_uvlevel[33]; - dtostrfd((double)uvlevel, 0, str_uvlevel); - char str_uvrisk[33]; - dtostrfd(uvrisk, 2, str_uvrisk); - char str_uvpower[33]; - dtostrfd(uvpower, 3, str_uvpower); - if (json) { -#ifdef USE_VEML6070_SHOW_RAW - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"), - veml6070_name, str_uvlevel, str_uvrisk, str_uvrisk_text, str_uvpower); -#else - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"), - veml6070_name, str_uvrisk, str_uvrisk_text, str_uvpower); -#endif -#ifdef USE_DOMOTICZ - if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel); } -#endif -#ifdef USE_WEBSERVER - } else { -#ifdef USE_VEML6070_SHOW_RAW - WSContentSend_PD(HTTP_SNS_UV_LEVEL, str_uvlevel); -#endif - WSContentSend_PD(HTTP_SNS_UV_INDEX, str_uvrisk, str_uvrisk_text); - WSContentSend_PD(HTTP_SNS_UV_POWER, str_uvpower); -#endif - } -} - - - - - -bool Xsns11(uint8_t function) -{ - if (!I2cEnabled(XI2C_12)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Veml6070Detect(); - } - else if (veml6070_type) { - switch (function) { - case FUNC_EVERY_SECOND: - Veml6070EverySecond(); - break; - case FUNC_JSON_APPEND: - Veml6070Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Veml6070Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_12_ads1115.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_12_ads1115.ino" -#ifdef USE_I2C -#ifdef USE_ADS1115 -# 43 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_12_ads1115.ino" -#define XSNS_12 12 -#define XI2C_13 13 - -#define ADS1115_ADDRESS_ADDR_GND 0x48 -#define ADS1115_ADDRESS_ADDR_VDD 0x49 -#define ADS1115_ADDRESS_ADDR_SDA 0x4A -#define ADS1115_ADDRESS_ADDR_SCL 0x4B - -#define ADS1115_CONVERSIONDELAY (8) - - - - -#define ADS1115_REG_POINTER_MASK (0x03) -#define ADS1115_REG_POINTER_CONVERT (0x00) -#define ADS1115_REG_POINTER_CONFIG (0x01) -#define ADS1115_REG_POINTER_LOWTHRESH (0x02) -#define ADS1115_REG_POINTER_HITHRESH (0x03) - - - - -#define ADS1115_REG_CONFIG_OS_MASK (0x8000) -#define ADS1115_REG_CONFIG_OS_SINGLE (0x8000) -#define ADS1115_REG_CONFIG_OS_BUSY (0x0000) -#define ADS1115_REG_CONFIG_OS_NOTBUSY (0x8000) - -#define ADS1115_REG_CONFIG_MUX_MASK (0x7000) -#define ADS1115_REG_CONFIG_MUX_DIFF_0_1 (0x0000) -#define ADS1115_REG_CONFIG_MUX_DIFF_0_3 (0x1000) -#define ADS1115_REG_CONFIG_MUX_DIFF_1_3 (0x2000) -#define ADS1115_REG_CONFIG_MUX_DIFF_2_3 (0x3000) -#define ADS1115_REG_CONFIG_MUX_SINGLE_0 (0x4000) -#define ADS1115_REG_CONFIG_MUX_SINGLE_1 (0x5000) -#define ADS1115_REG_CONFIG_MUX_SINGLE_2 (0x6000) -#define ADS1115_REG_CONFIG_MUX_SINGLE_3 (0x7000) - -#define ADS1115_REG_CONFIG_PGA_MASK (0x0E00) -#define ADS1115_REG_CONFIG_PGA_6_144V (0x0000) -#define ADS1115_REG_CONFIG_PGA_4_096V (0x0200) -#define ADS1115_REG_CONFIG_PGA_2_048V (0x0400) -#define ADS1115_REG_CONFIG_PGA_1_024V (0x0600) -#define ADS1115_REG_CONFIG_PGA_0_512V (0x0800) -#define ADS1115_REG_CONFIG_PGA_0_256V (0x0A00) - -#define ADS1115_REG_CONFIG_MODE_MASK (0x0100) -#define ADS1115_REG_CONFIG_MODE_CONTIN (0x0000) -#define ADS1115_REG_CONFIG_MODE_SINGLE (0x0100) - -#define ADS1115_REG_CONFIG_DR_MASK (0x00E0) -#define ADS1115_REG_CONFIG_DR_128SPS (0x0000) -#define ADS1115_REG_CONFIG_DR_250SPS (0x0020) -#define ADS1115_REG_CONFIG_DR_490SPS (0x0040) -#define ADS1115_REG_CONFIG_DR_920SPS (0x0060) -#define ADS1115_REG_CONFIG_DR_1600SPS (0x0080) -#define ADS1115_REG_CONFIG_DR_2400SPS (0x00A0) -#define ADS1115_REG_CONFIG_DR_3300SPS (0x00C0) -#define ADS1115_REG_CONFIG_DR_6000SPS (0x00E0) - -#define ADS1115_REG_CONFIG_CMODE_MASK (0x0010) -#define ADS1115_REG_CONFIG_CMODE_TRAD (0x0000) -#define ADS1115_REG_CONFIG_CMODE_WINDOW (0x0010) - -#define ADS1115_REG_CONFIG_CPOL_MASK (0x0008) -#define ADS1115_REG_CONFIG_CPOL_ACTVLOW (0x0000) -#define ADS1115_REG_CONFIG_CPOL_ACTVHI (0x0008) - -#define ADS1115_REG_CONFIG_CLAT_MASK (0x0004) -#define ADS1115_REG_CONFIG_CLAT_NONLAT (0x0000) -#define ADS1115_REG_CONFIG_CLAT_LATCH (0x0004) - -#define ADS1115_REG_CONFIG_CQUE_MASK (0x0003) -#define ADS1115_REG_CONFIG_CQUE_1CONV (0x0000) -#define ADS1115_REG_CONFIG_CQUE_2CONV (0x0001) -#define ADS1115_REG_CONFIG_CQUE_4CONV (0x0002) -#define ADS1115_REG_CONFIG_CQUE_NONE (0x0003) - -struct ADS1115 { - uint8_t count = 0; - uint8_t address; - uint8_t addresses[4] = { ADS1115_ADDRESS_ADDR_GND, ADS1115_ADDRESS_ADDR_VDD, ADS1115_ADDRESS_ADDR_SDA, ADS1115_ADDRESS_ADDR_SCL }; - uint8_t found[4] = {false,false,false,false}; -} Ads1115; - - - -void Ads1115StartComparator(uint8_t channel, uint16_t mode) -{ - - uint16_t config = mode | - ADS1115_REG_CONFIG_CQUE_NONE | - ADS1115_REG_CONFIG_CLAT_NONLAT | - ADS1115_REG_CONFIG_PGA_6_144V | - ADS1115_REG_CONFIG_CPOL_ACTVLOW | - ADS1115_REG_CONFIG_CMODE_TRAD | - ADS1115_REG_CONFIG_DR_6000SPS; - - - config |= (ADS1115_REG_CONFIG_MUX_SINGLE_0 + (0x1000 * channel)); - - - I2cWrite16(Ads1115.address, ADS1115_REG_POINTER_CONFIG, config); -} - -int16_t Ads1115GetConversion(uint8_t channel) -{ - Ads1115StartComparator(channel, ADS1115_REG_CONFIG_MODE_SINGLE); - - delay(ADS1115_CONVERSIONDELAY); - - I2cRead16(Ads1115.address, ADS1115_REG_POINTER_CONVERT); - - Ads1115StartComparator(channel, ADS1115_REG_CONFIG_MODE_CONTIN); - delay(ADS1115_CONVERSIONDELAY); - - uint16_t res = I2cRead16(Ads1115.address, ADS1115_REG_POINTER_CONVERT); - return (int16_t)res; -} - - - -void Ads1115Detect(void) -{ - for (uint32_t i = 0; i < sizeof(Ads1115.addresses); i++) { - if (!Ads1115.found[i]) { - Ads1115.address = Ads1115.addresses[i]; - if (I2cActive(Ads1115.address)) { continue; } - uint16_t buffer; - if (I2cValidRead16(&buffer, Ads1115.address, ADS1115_REG_POINTER_CONVERT) && - I2cValidRead16(&buffer, Ads1115.address, ADS1115_REG_POINTER_CONFIG)) { - Ads1115StartComparator(i, ADS1115_REG_CONFIG_MODE_CONTIN); - I2cSetActiveFound(Ads1115.address, "ADS1115"); - Ads1115.found[i] = 1; - Ads1115.count++; - } - } - } -} - -void Ads1115Show(bool json) -{ - int16_t values[4]; - - for (uint32_t t = 0; t < sizeof(Ads1115.addresses); t++) { - - if (Ads1115.found[t]) { - - uint8_t old_address = Ads1115.address; - Ads1115.address = Ads1115.addresses[t]; - for (uint32_t i = 0; i < 4; i++) { - values[i] = Ads1115GetConversion(i); - - } - Ads1115.address = old_address; - - char label[15]; - if (1 == Ads1115.count) { - - snprintf_P(label, sizeof(label), PSTR("ADS1115")); - } else { - - snprintf_P(label, sizeof(label), PSTR("ADS1115%c%02x"), IndexSeparator(), Ads1115.addresses[t]); - } - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{"), label); - for (uint32_t i = 0; i < 4; i++) { - ResponseAppend_P(PSTR("%s\"A%d\":%d"), (0 == i) ? "" : ",", i, values[i]); - } - ResponseJsonEnd(); - } -#ifdef USE_WEBSERVER - else { - for (uint32_t i = 0; i < 4; i++) { - WSContentSend_PD(HTTP_SNS_ANALOG, label, i, values[i]); - } - } -#endif - } - } -} - - - - - -bool Xsns12(uint8_t function) -{ - if (!I2cEnabled(XI2C_13)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Ads1115Detect(); - } - else if (Ads1115.count) { - switch (function) { - case FUNC_JSON_APPEND: - Ads1115Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Ads1115Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_13_ina219.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_13_ina219.ino" -#ifdef USE_I2C -#ifdef USE_INA219 -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_13_ina219.ino" -#define XSNS_13 13 -#define XI2C_14 14 - -#define INA219_ADDRESS1 (0x40) -#define INA219_ADDRESS2 (0x41) -#define INA219_ADDRESS3 (0x44) -#define INA219_ADDRESS4 (0x45) - -#define INA219_READ (0x01) -#define INA219_REG_CONFIG (0x00) - -#define INA219_CONFIG_RESET (0x8000) - -#define INA219_CONFIG_BVOLTAGERANGE_MASK (0x2000) -#define INA219_CONFIG_BVOLTAGERANGE_16V (0x0000) -#define INA219_CONFIG_BVOLTAGERANGE_32V (0x2000) - -#define INA219_CONFIG_GAIN_MASK (0x1800) -#define INA219_CONFIG_GAIN_1_40MV (0x0000) -#define INA219_CONFIG_GAIN_2_80MV (0x0800) -#define INA219_CONFIG_GAIN_4_160MV (0x1000) -#define INA219_CONFIG_GAIN_8_320MV (0x1800) - -#define INA219_CONFIG_BADCRES_MASK (0x0780) -#define INA219_CONFIG_BADCRES_9BIT_1S_84US (0x0<<7) -#define INA219_CONFIG_BADCRES_10BIT_1S_148US (0x1<<7) -#define INA219_CONFIG_BADCRES_11BIT_1S_276US (0x2<<7) -#define INA219_CONFIG_BADCRES_12BIT_1S_532US (0x3<<7) -#define INA219_CONFIG_BADCRES_12BIT_2S_1060US (0x9<<7) -#define INA219_CONFIG_BADCRES_12BIT_4S_2130US (0xA<<7) -#define INA219_CONFIG_BADCRES_12BIT_8S_4260US (0xB<<7) -#define INA219_CONFIG_BADCRES_12BIT_16S_8510US (0xC<<7) -#define INA219_CONFIG_BADCRES_12BIT_32S_17MS (0xD<<7) -#define INA219_CONFIG_BADCRES_12BIT_64S_34MS (0xE<<7) -#define INA219_CONFIG_BADCRES_12BIT_128S_69MS (0xF<<7) - -#define INA219_CONFIG_SADCRES_MASK (0x0078) -#define INA219_CONFIG_SADCRES_9BIT_1S_84US (0x0<<3) -#define INA219_CONFIG_SADCRES_10BIT_1S_148US (0x1<<3) -#define INA219_CONFIG_SADCRES_11BIT_1S_276US (0x2<<3) -#define INA219_CONFIG_SADCRES_12BIT_1S_532US (0x3<<3) -#define INA219_CONFIG_SADCRES_12BIT_2S_1060US (0x9<<3) -#define INA219_CONFIG_SADCRES_12BIT_4S_2130US (0xA<<3) -#define INA219_CONFIG_SADCRES_12BIT_8S_4260US (0xB<<3) -#define INA219_CONFIG_SADCRES_12BIT_16S_8510US (0xC<<3) -#define INA219_CONFIG_SADCRES_12BIT_32S_17MS (0xD<<3) -#define INA219_CONFIG_SADCRES_12BIT_64S_34MS (0xE<<3) -#define INA219_CONFIG_SADCRES_12BIT_128S_69MS (0xF<<3) - -#define INA219_CONFIG_MODE_MASK (0x0007) -#define INA219_CONFIG_MODE_POWERDOWN (0x0000) -#define INA219_CONFIG_MODE_SVOLT_TRIGGERED (0x0001) -#define INA219_CONFIG_MODE_BVOLT_TRIGGERED (0x0002) -#define INA219_CONFIG_MODE_SANDBVOLT_TRIGGERED (0x0003) -#define INA219_CONFIG_MODE_ADCOFF (0x0004) -#define INA219_CONFIG_MODE_SVOLT_CONTINUOUS (0x0005) -#define INA219_CONFIG_MODE_BVOLT_CONTINUOUS (0x0006) -#define INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS (0x0007) - -#define INA219_REG_SHUNTVOLTAGE (0x01) -#define INA219_REG_BUSVOLTAGE (0x02) -#define INA219_REG_POWER (0x03) -#define INA219_REG_CURRENT (0x04) -#define INA219_REG_CALIBRATION (0x05) - -#define INA219_DEFAULT_SHUNT_RESISTOR_MILLIOHMS (100.0) - -uint8_t ina219_type[4] = {0,0,0,0}; -uint8_t ina219_addresses[] = { INA219_ADDRESS1, INA219_ADDRESS2, INA219_ADDRESS3, INA219_ADDRESS4 }; - -#ifdef DEBUG_TASMOTA_SENSOR - -char __ina219_dbg1[10]; -char __ina219_dbg2[10]; -#endif - - - - -float ina219_current_multiplier; - -uint8_t ina219_valid[4] = {0,0,0,0}; -float ina219_voltage[4] = {0,0,0,0}; -float ina219_current[4] = {0,0,0,0}; -char ina219_types[] = "INA219"; -uint8_t ina219_count = 0; -# 132 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_13_ina219.ino" -bool Ina219SetCalibration(uint8_t mode, uint16_t addr) -{ - uint16_t config = 0; - - DEBUG_SENSOR_LOG("Ina219SetCalibration: mode=%d",mode); - if (mode < 5) - { - - ina219_current_multiplier = 1.0 / INA219_DEFAULT_SHUNT_RESISTOR_MILLIOHMS; - #ifdef DEBUG_TASMOTA_SENSOR - dtostrfd(ina219_current_multiplier,5,__ina219_dbg1); - DEBUG_SENSOR_LOG("Ina219SetCalibration: cur_mul=%s",__ina219_dbg1); - #endif - } - else if (mode >= 10) - { - int mult = mode % 10; - int shunt_milliOhms = mode / 10; - for ( ; mult > 0 ; mult-- ) - shunt_milliOhms *= 10; - ina219_current_multiplier = 1.0 / shunt_milliOhms; - #ifdef DEBUG_TASMOTA_SENSOR - dtostrfd(ina219_current_multiplier,5,__ina219_dbg1); - DEBUG_SENSOR_LOG("Ina219SetCalibration: shunt=%dmO => cur_mul=%s",shunt_milliOhms,__ina219_dbg1); - #endif - } - config = INA219_CONFIG_BVOLTAGERANGE_32V - | INA219_CONFIG_GAIN_8_320MV - | INA219_CONFIG_BADCRES_12BIT_16S_8510US - | INA219_CONFIG_SADCRES_12BIT_16S_8510US - | INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; - - return I2cWrite16(addr, INA219_REG_CONFIG, config); -} - -float Ina219GetShuntVoltage_mV(uint16_t addr) -{ - - int16_t value = I2cReadS16(addr, INA219_REG_SHUNTVOLTAGE); - DEBUG_SENSOR_LOG("Ina219GetShuntVoltage_mV: ShReg = 0x%04X",value); - - return value * 0.01; -} - -float Ina219GetBusVoltage_V(uint16_t addr) -{ - - uint16_t value = I2cRead16(addr, INA219_REG_BUSVOLTAGE) >> 3; - DEBUG_SENSOR_LOG("Ina219GetBusVoltage_V: BusReg = 0x%04X",value); - - return value * 0.004; -} -# 201 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_13_ina219.ino" -bool Ina219Read(void) -{ - for (int i=0; i= 0) && (XdrvMailbox.payload <= 255)) { - Settings.ina219_mode = XdrvMailbox.payload; - restart_flag = 2; - } - Response_P(S_JSON_SENSOR_INDEX_NVALUE, XSNS_13, Settings.ina219_mode); - - return true; -} - - - -void Ina219Detect(void) -{ - for (uint32_t i = 0; i < sizeof(ina219_type); i++) { - uint16_t addr = ina219_addresses[i]; - if (I2cActive(addr)) { continue; } - if (Ina219SetCalibration(Settings.ina219_mode, addr)) { - I2cSetActiveFound(addr, ina219_types); - ina219_type[i] = 1; - ina219_count++; - } - } -} - -void Ina219EverySecond(void) -{ - - Ina219Read(); -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_INA219_DATA[] PROGMEM = - "{s}%s " D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}" - "{s}%s " D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}" - "{s}%s " D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; -#endif - -void Ina219Show(bool json) -{ - int num_found=0; - for (int i=0; i1) - snprintf_P(name, sizeof(name), PSTR("%s%c%d"), ina219_types, IndexSeparator(), sensor_num); - else - snprintf_P(name, sizeof(name), PSTR("%s"), ina219_types); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"Id\":%02x,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"), - name, ina219_addresses[i], voltage, current, power); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_VOLTAGE, voltage); - DomoticzSensor(DZ_CURRENT, current); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_INA219_DATA, name, voltage, name, current, name, power); -#endif - } - } -} - - - - - -bool Xsns13(uint8_t function) -{ - if (!I2cEnabled(XI2C_14)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Ina219Detect(); - } - else if (ina219_count) { - switch (function) { - case FUNC_COMMAND_SENSOR: - if (XSNS_13 == XdrvMailbox.index) { - result = Ina219CommandSensor(); - } - break; - case FUNC_EVERY_SECOND: - Ina219EverySecond(); - break; - case FUNC_JSON_APPEND: - Ina219Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Ina219Show(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_14_sht3x.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_14_sht3x.ino" -#ifdef USE_I2C -#ifdef USE_SHT3X - - - - - - -#define XSNS_14 14 -#define XI2C_15 15 - -#define SHT3X_ADDR_GND 0x44 -#define SHT3X_ADDR_VDD 0x45 -#define SHTC3_ADDR 0x70 - -#define SHT3X_MAX_SENSORS 3 - -const char kShtTypes[] PROGMEM = "SHT3X|SHT3X|SHTC3"; -uint8_t sht3x_addresses[] = { SHT3X_ADDR_GND, SHT3X_ADDR_VDD, SHTC3_ADDR }; - -uint8_t sht3x_count = 0; -struct SHT3XSTRUCT { - uint8_t address; - char types[6]; -} sht3x_sensors[SHT3X_MAX_SENSORS]; - -bool Sht3xRead(float &t, float &h, uint8_t sht3x_address) -{ - unsigned int data[6]; - - t = NAN; - h = NAN; - - Wire.beginTransmission(sht3x_address); - if (SHTC3_ADDR == sht3x_address) { - Wire.write(0x35); - Wire.write(0x17); - Wire.endTransmission(); - Wire.beginTransmission(sht3x_address); - Wire.write(0x78); - Wire.write(0x66); - } else { - Wire.write(0x2C); - Wire.write(0x06); - } - if (Wire.endTransmission() != 0) { - return false; - } - delay(30); - Wire.requestFrom(sht3x_address, (uint8_t)6); - for (uint32_t i = 0; i < 6; i++) { - data[i] = Wire.read(); - }; - t = ConvertTemp((float)((((data[0] << 8) | data[1]) * 175) / 65535.0) - 45); - h = ConvertHumidity((float)((((data[3] << 8) | data[4]) * 100) / 65535.0)); - return (!isnan(t) && !isnan(h) && (h != 0)); -} - - - -void Sht3xDetect(void) -{ - for (uint32_t i = 0; i < SHT3X_MAX_SENSORS; i++) { - if (I2cActive(sht3x_addresses[i])) { continue; } - float t; - float h; - if (Sht3xRead(t, h, sht3x_addresses[i])) { - sht3x_sensors[sht3x_count].address = sht3x_addresses[i]; - GetTextIndexed(sht3x_sensors[sht3x_count].types, sizeof(sht3x_sensors[sht3x_count].types), i, kShtTypes); - I2cSetActiveFound(sht3x_sensors[sht3x_count].address, sht3x_sensors[sht3x_count].types); - sht3x_count++; - } - } -} - -void Sht3xShow(bool json) -{ - for (uint32_t i = 0; i < sht3x_count; i++) { - float t; - float h; - if (Sht3xRead(t, h, sht3x_sensors[i].address)) { - char types[11]; - snprintf_P(types, sizeof(types), PSTR("%s%c0x%02X"), sht3x_sensors[i].types, IndexSeparator(), sht3x_sensors[i].address); - TempHumDewShow(json, ((0 == tele_period) && (0 == i)), types, t, h); - } - } -} - - - - - -bool Xsns14(uint8_t function) -{ - if (!I2cEnabled(XI2C_15)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Sht3xDetect(); - } - else if (sht3x_count) { - switch (function) { - case FUNC_JSON_APPEND: - Sht3xShow(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Sht3xShow(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_15_mhz19.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_15_mhz19.ino" -#ifdef USE_MHZ19 -# 33 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_15_mhz19.ino" -#define XSNS_15 15 - -enum MhzFilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILTER_FAST, MHZ19_FILTER_MEDIUM, MHZ19_FILTER_SLOW}; - -#define MHZ19_FILTER_OPTION MHZ19_FILTER_FAST -# 58 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_15_mhz19.ino" -#include - -#ifndef CO2_LOW -#define CO2_LOW 800 -#endif -#ifndef CO2_HIGH -#define CO2_HIGH 1200 -#endif - -#define MHZ19_READ_TIMEOUT 400 -#define MHZ19_RETRY_COUNT 8 - -TasmotaSerial *MhzSerial; - -const char kMhzModels[] PROGMEM = "|B"; - -const char ABC_ENABLED[] = "ABC is Enabled"; -const char ABC_DISABLED[] = "ABC is Disabled"; - -enum MhzCommands { MHZ_CMND_READPPM, MHZ_CMND_ABCENABLE, MHZ_CMND_ABCDISABLE, MHZ_CMND_ZEROPOINT, MHZ_CMND_RESET, MHZ_CMND_RANGE_1000, MHZ_CMND_RANGE_2000, MHZ_CMND_RANGE_3000, MHZ_CMND_RANGE_5000 }; -const uint8_t kMhzCommands[][4] PROGMEM = { - - {0x86,0x00,0x00,0x00}, - {0x79,0xA0,0x00,0x00}, - {0x79,0x00,0x00,0x00}, - {0x87,0x00,0x00,0x00}, - {0x8D,0x00,0x00,0x00}, - {0x99,0x00,0x03,0xE8}, - {0x99,0x00,0x07,0xD0}, - {0x99,0x00,0x0B,0xB8}, - {0x99,0x00,0x13,0x88}}; - -uint8_t mhz_type = 1; -uint16_t mhz_last_ppm = 0; -uint8_t mhz_filter = MHZ19_FILTER_OPTION; -bool mhz_abc_must_apply = false; - -float mhz_temperature = 0; -uint8_t mhz_retry = MHZ19_RETRY_COUNT; -uint8_t mhz_received = 0; -uint8_t mhz_state = 0; - - - -uint8_t MhzCalculateChecksum(uint8_t *array) -{ - uint8_t checksum = 0; - for (uint32_t i = 1; i < 8; i++) { - checksum += array[i]; - } - checksum = 255 - checksum; - return (checksum +1); -} - -size_t MhzSendCmd(uint8_t command_id) -{ - uint8_t mhz_send[9] = { 0 }; - - mhz_send[0] = 0xFF; - mhz_send[1] = 0x01; - memcpy_P(&mhz_send[2], kMhzCommands[command_id], sizeof(uint16_t)); - - - - - memcpy_P(&mhz_send[6], kMhzCommands[command_id] + sizeof(uint16_t), sizeof(uint16_t)); - mhz_send[8] = MhzCalculateChecksum(mhz_send); - - - - return MhzSerial->write(mhz_send, sizeof(mhz_send)); -} - - - -bool MhzCheckAndApplyFilter(uint16_t ppm, uint8_t s) -{ - if (1 == s) { - return false; - } - if (mhz_last_ppm < 400 || mhz_last_ppm > 5000) { - - - mhz_last_ppm = ppm; - return true; - } - int32_t difference = ppm - mhz_last_ppm; - if (s > 0 && s < 64 && mhz_filter != MHZ19_FILTER_OFF) { -# 154 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_15_mhz19.ino" - difference *= s; - difference /= 64; - } - if (MHZ19_FILTER_OFF == mhz_filter) { - if (s != 0 && s != 64) { - return false; - } - } else { - difference >>= (mhz_filter -1); - } - mhz_last_ppm = static_cast(mhz_last_ppm + difference); - return true; -} - -void MhzEverySecond(void) -{ - mhz_state++; - if (8 == mhz_state) { - mhz_state = 0; - - if (mhz_retry) { - mhz_retry--; - if (!mhz_retry) { - mhz_last_ppm = 0; - mhz_temperature = 0; - } - } - - MhzSerial->flush(); - MhzSendCmd(MHZ_CMND_READPPM); - mhz_received = 0; - } - - if ((mhz_state > 2) && !mhz_received) { - uint8_t mhz_response[9]; - - unsigned long start = millis(); - uint8_t counter = 0; - while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) { - if (MhzSerial->available() > 0) { - mhz_response[counter++] = MhzSerial->read(); - } else { - delay(5); - } - } - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, mhz_response, counter); - - if (counter < 9) { - - return; - } - - uint8_t crc = MhzCalculateChecksum(mhz_response); - if (mhz_response[8] != crc) { - - return; - } - if (0xFF != mhz_response[0] || 0x86 != mhz_response[1]) { - - return; - } - - mhz_received = 1; - - uint16_t u = (mhz_response[6] << 8) | mhz_response[7]; - if (15000 == u) { - if (Settings.SensorBits1.mhz19b_abc_disable) { - - - mhz_abc_must_apply = true; - } - } else { - uint16_t ppm = (mhz_response[2] << 8) | mhz_response[3]; - mhz_temperature = ConvertTemp((float)mhz_response[4] - 40); - uint8_t s = mhz_response[5]; - mhz_type = (s) ? 1 : 2; - if (MhzCheckAndApplyFilter(ppm, s)) { - mhz_retry = MHZ19_RETRY_COUNT; -#ifdef USE_LIGHT - LightSetSignal(CO2_LOW, CO2_HIGH, mhz_last_ppm); -#endif - - if (0 == s || 64 == s) { - if (mhz_abc_must_apply) { - mhz_abc_must_apply = false; - if (!Settings.SensorBits1.mhz19b_abc_disable) { - MhzSendCmd(MHZ_CMND_ABCENABLE); - } else { - MhzSendCmd(MHZ_CMND_ABCDISABLE); - } - } - } - - } - } - - } -} -# 268 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_15_mhz19.ino" -#define D_JSON_RANGE_1000 "1000 ppm range" -#define D_JSON_RANGE_2000 "2000 ppm range" -#define D_JSON_RANGE_3000 "3000 ppm range" -#define D_JSON_RANGE_5000 "5000 ppm range" - -bool MhzCommandSensor(void) -{ - bool serviced = true; - - switch (XdrvMailbox.payload) { - case 0: - Settings.SensorBits1.mhz19b_abc_disable = true; - MhzSendCmd(MHZ_CMND_ABCDISABLE); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_DISABLED); - break; - case 1: - Settings.SensorBits1.mhz19b_abc_disable = false; - MhzSendCmd(MHZ_CMND_ABCENABLE); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_ENABLED); - break; - case 2: - MhzSendCmd(MHZ_CMND_ZEROPOINT); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_ZERO_POINT_CALIBRATION); - break; - case 9: - MhzSendCmd(MHZ_CMND_RESET); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RESET); - break; - case 1000: - MhzSendCmd(MHZ_CMND_RANGE_1000); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_1000); - break; - case 2000: - MhzSendCmd(MHZ_CMND_RANGE_2000); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_2000); - break; - case 3000: - MhzSendCmd(MHZ_CMND_RANGE_3000); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_3000); - break; - case 5000: - MhzSendCmd(MHZ_CMND_RANGE_5000); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, D_JSON_RANGE_5000); - break; - default: - if (!Settings.SensorBits1.mhz19b_abc_disable) { - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_ENABLED); - } else { - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_15, ABC_DISABLED); - } - } - - return serviced; -} - - - -void MhzInit(void) -{ - mhz_type = 0; - if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) { - MhzSerial = new TasmotaSerial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD], 1); - if (MhzSerial->begin(9600)) { - if (MhzSerial->hardwareSerial()) { ClaimSerial(); } - mhz_type = 1; - } - - } -} - -void MhzShow(bool json) -{ - char types[7] = "MHZ19B"; - char temperature[33]; - dtostrfd(mhz_temperature, Settings.flag2.temperature_resolution, temperature); - char model[3]; - GetTextIndexed(model, sizeof(model), mhz_type -1, kMhzModels); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_MODEL "\":\"%s\",\"" D_JSON_CO2 "\":%d,\"" D_JSON_TEMPERATURE "\":%s}"), types, model, mhz_last_ppm, temperature); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_AIRQUALITY, mhz_last_ppm); - DomoticzSensor(DZ_TEMP, temperature); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CO2, types, mhz_last_ppm); - WSContentSend_PD(HTTP_SNS_TEMP, types, temperature, TempUnit()); -#endif - } -} - - - - - -bool Xsns15(uint8_t function) -{ - bool result = false; - - if (mhz_type) { - switch (function) { - case FUNC_INIT: - MhzInit(); - break; - case FUNC_EVERY_SECOND: - MhzEverySecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_15 == XdrvMailbox.index) { - result = MhzCommandSensor(); - } - break; - case FUNC_JSON_APPEND: - MhzShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MhzShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_16_tsl2561.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_16_tsl2561.ino" -#ifdef USE_I2C -#ifdef USE_TSL2561 -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_16_tsl2561.ino" -#define XSNS_16 16 -#define XI2C_16 16 - -#include - -Tsl2561 Tsl(Wire); - -uint8_t tsl2561_type = 0; -uint8_t tsl2561_valid = 0; -uint32_t tsl2561_milliLux = 0; -char tsl2561_types[] = "TSL2561"; - -bool Tsl2561Read(void) -{ - if (tsl2561_valid) { tsl2561_valid--; } - - uint8_t id; - bool gain; - Tsl2561::exposure_t exposure; - uint16_t scaledFull, scaledIr; - uint32_t full, ir; - - if (Tsl.on()) { - if (Tsl.id(id) - && Tsl2561Util::autoGain(Tsl, gain, exposure, scaledFull, scaledIr) - && Tsl2561Util::normalizedLuminosity(gain, exposure, full = scaledFull, ir = scaledIr) - && Tsl2561Util::milliLux(full, ir, tsl2561_milliLux, Tsl2561::packageCS(id))) { - } else{ - tsl2561_milliLux = 0; - } - } - tsl2561_valid = SENSOR_MAX_MISS; - return true; -} - -void Tsl2561Detect(void) -{ - if (I2cSetDevice(0x29) || I2cSetDevice(0x39) || I2cSetDevice(0x49)) { - uint8_t id; - Tsl.begin(); - if (!Tsl.id(id)) return; - if (Tsl.on()) { - tsl2561_type = 1; - I2cSetActiveFound(Tsl.address(), tsl2561_types); - } - } -} - -void Tsl2561EverySecond(void) -{ - if (!(uptime %2)) { - - if (!Tsl2561Read()) { - AddLogMissed(tsl2561_types, tsl2561_valid); - } - } -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_TSL2561[] PROGMEM = - "{s}TSL2561 " D_ILLUMINANCE "{m}%u.%03u " D_UNIT_LUX "{e}"; -#endif - -void Tsl2561Show(bool json) -{ - if (tsl2561_valid) { - if (json) { - ResponseAppend_P(PSTR(",\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%u.%03u}"), - tsl2561_milliLux / 1000, tsl2561_milliLux % 1000); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, (tsl2561_milliLux + 500) / 1000); } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TSL2561, tsl2561_milliLux / 1000, tsl2561_milliLux % 1000); -#endif - } - } -} - - - - - -bool Xsns16(uint8_t function) -{ - if (!I2cEnabled(XI2C_16)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Tsl2561Detect(); - } - else if (tsl2561_type) { - switch (function) { - case FUNC_EVERY_SECOND: - Tsl2561EverySecond(); - break; - case FUNC_JSON_APPEND: - Tsl2561Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Tsl2561Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_17_senseair.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_17_senseair.ino" -#ifdef USE_SENSEAIR -# 29 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_17_senseair.ino" -#define XSNS_17 17 - -#define SENSEAIR_MODBUS_SPEED 9600 -#define SENSEAIR_DEVICE_ADDRESS 0xFE -#define SENSEAIR_READ_REGISTER 0x04 - -#ifndef CO2_LOW -#define CO2_LOW 800 -#endif -#ifndef CO2_HIGH -#define CO2_HIGH 1200 -#endif - -#include -TasmotaModbus *SenseairModbus; - -const char kSenseairTypes[] PROGMEM = "Kx0|S8"; - -uint8_t senseair_type = 1; -char senseair_types[7]; - -uint16_t senseair_co2 = 0; -float senseair_temperature = 0; -float senseair_humidity = 0; - - - -const uint8_t start_addresses[] { 0x1A, 0x00, 0x03, 0x04, 0x05, 0x1C, 0x0A }; - -uint8_t senseair_read_state = 0; -uint8_t senseair_send_retry = 0; - -void Senseair250ms(void) -{ - - - - - uint16_t value = 0; - bool data_ready = SenseairModbus->ReceiveReady(); - - if (data_ready) { - uint8_t error = SenseairModbus->Receive16BitRegister(&value); - if (error) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir response error %d"), error); - } else { - switch(senseair_read_state) { - case 0: - senseair_type = 2; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir type id low %04X"), value); - break; - case 1: - if (value) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir error %04X"), value); - } - break; - case 2: - senseair_co2 = value; -#ifdef USE_LIGHT - LightSetSignal(CO2_LOW, CO2_HIGH, senseair_co2); -#endif - break; - case 3: - senseair_temperature = ConvertTemp((float)value / 100); - break; - case 4: - senseair_humidity = ConvertHumidity((float)value / 100); - break; - case 5: - { - bool relay_state = value >> 8 & 1; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir relay state %d"), relay_state); - break; - } - case 6: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir temp adjustment %d"), value); - break; - } - } - senseair_read_state++; - if (2 == senseair_type) { - if (3 == senseair_read_state) { - senseair_read_state = 1; - } - } else { - if (sizeof(start_addresses) == senseair_read_state) { - senseair_read_state = 1; - } - } - } - - if (0 == senseair_send_retry || data_ready) { - senseair_send_retry = 5; - SenseairModbus->Send(SENSEAIR_DEVICE_ADDRESS, SENSEAIR_READ_REGISTER, (uint16_t)start_addresses[senseair_read_state], 1); - } else { - senseair_send_retry--; - } - - -} - - - -void SenseairInit(void) -{ - senseair_type = 0; - if ((pin[GPIO_SAIR_RX] < 99) && (pin[GPIO_SAIR_TX] < 99)) { - SenseairModbus = new TasmotaModbus(pin[GPIO_SAIR_RX], pin[GPIO_SAIR_TX]); - uint8_t result = SenseairModbus->Begin(SENSEAIR_MODBUS_SPEED); - if (result) { - if (2 == result) { ClaimSerial(); } - senseair_type = 1; - } - } -} - -void SenseairShow(bool json) -{ - GetTextIndexed(senseair_types, sizeof(senseair_types), senseair_type -1, kSenseairTypes); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_CO2 "\":%d"), senseair_types, senseair_co2); - if (senseair_type != 2) { - ResponseAppend_P(PSTR(",")); - ResponseAppendTHD(senseair_temperature, senseair_humidity); - } - ResponseJsonEnd(); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_AIRQUALITY, senseair_co2); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CO2, senseair_types, senseair_co2); - if (senseair_type != 2) { - WSContentSend_THD(senseair_types, senseair_temperature, senseair_humidity); - } -#endif - } -} - - - - - -bool Xsns17(uint8_t function) -{ - bool result = false; - - if (senseair_type) { - switch (function) { - case FUNC_INIT: - SenseairInit(); - break; - case FUNC_EVERY_250_MSECOND: - Senseair250ms(); - break; - case FUNC_JSON_APPEND: - SenseairShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - SenseairShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_18_pms5003.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_18_pms5003.ino" -#ifdef USE_PMS5003 -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_18_pms5003.ino" -#define XSNS_18 18 - -#include - -#ifndef WARMUP_PERIOD -#define WARMUP_PERIOD 30 -#endif - -#ifndef MIN_INTERVAL_PERIOD -#define MIN_INTERVAL_PERIOD 60 -#endif - -TasmotaSerial *PmsSerial; - -struct PMS5003 { - uint16_t time = 0; - uint8_t type = 1; - uint8_t valid = 0; - uint8_t wake_mode = 1; - uint8_t ready = 1; -} Pms; - -enum PmsCommands -{ - CMD_MODE_ACTIVE, - CMD_SLEEP, - CMD_WAKEUP, - CMD_MODE_PASSIVE, - CMD_READ_DATA -}; - -const uint8_t kPmsCommands[][7] PROGMEM = { - - {0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71}, - {0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73}, - {0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74}, - {0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70}, - {0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71}}; - -struct pmsX003data { - uint16_t framelen; - uint16_t pm10_standard, pm25_standard, pm100_standard; - uint16_t pm10_env, pm25_env, pm100_env; -#ifdef PMS_MODEL_PMS3003 - uint16_t reserved1, reserved2, reserved3; -#else - uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um; - uint16_t unused; -#endif - uint16_t checksum; -} pms_data; - - - -size_t PmsSendCmd(uint8_t command_id) -{ - return PmsSerial->write(kPmsCommands[command_id], sizeof(kPmsCommands[command_id])); -} - - - -bool PmsReadData(void) -{ - if (! PmsSerial->available()) { - return false; - } - while ((PmsSerial->peek() != 0x42) && PmsSerial->available()) { - PmsSerial->read(); - } -#ifdef PMS_MODEL_PMS3003 - if (PmsSerial->available() < 22) { -#else - if (PmsSerial->available() < 32) { -#endif - return false; - } - -#ifdef PMS_MODEL_PMS3003 - uint8_t buffer[22]; - PmsSerial->readBytes(buffer, 22); -#else - uint8_t buffer[32]; - PmsSerial->readBytes(buffer, 32); -#endif - uint16_t sum = 0; - PmsSerial->flush(); - -#ifdef PMS_MODEL_PMS3003 - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, 22); -#else - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, 32); -#endif - - -#ifdef PMS_MODEL_PMS3003 - for (uint32_t i = 0; i < 20; i++) { -#else - for (uint32_t i = 0; i < 30; i++) { -#endif - sum += buffer[i]; - } - -#ifdef PMS_MODEL_PMS3003 - uint16_t buffer_u16[10]; - for (uint32_t i = 0; i < 10; i++) { -#else - uint16_t buffer_u16[15]; - for (uint32_t i = 0; i < 15; i++) { -#endif - buffer_u16[i] = buffer[2 + i*2 + 1]; - buffer_u16[i] += (buffer[2 + i*2] << 8); - } -#ifdef PMS_MODEL_PMS3003 - if (sum != buffer_u16[9]) { -#else - if (sum != buffer_u16[14]) { -#endif - AddLog_P(LOG_LEVEL_DEBUG, PSTR("PMS: " D_CHECKSUM_FAILURE)); - return false; - } - -#ifdef PMS_MODEL_PMS3003 - memcpy((void *)&pms_data, (void *)buffer_u16, 20); -#else - memcpy((void *)&pms_data, (void *)buffer_u16, 30); -#endif - Pms.valid = 10; - - return true; -} -# 172 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_18_pms5003.ino" -bool PmsCommandSensor(void) -{ - if ((pin[GPIO_PMS5003_TX] < 99) && (XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32001)) { - if (XdrvMailbox.payload < MIN_INTERVAL_PERIOD) { - - Settings.pms_wake_interval = 0; - Pms.wake_mode = 1; - Pms.ready = 1; - PmsSendCmd(CMD_MODE_ACTIVE); - PmsSendCmd(CMD_WAKEUP); - } else { - - Settings.pms_wake_interval = XdrvMailbox.payload; - PmsSendCmd(CMD_MODE_PASSIVE); - PmsSendCmd(CMD_SLEEP); - Pms.wake_mode = 0; - Pms.ready = 0; - } - } - - Response_P(S_JSON_SENSOR_INDEX_NVALUE, XSNS_18, Settings.pms_wake_interval); - - return true; -} - - - -void PmsSecond(void) -{ - if (Settings.pms_wake_interval >= MIN_INTERVAL_PERIOD) { - - Pms.time++; - if ((Settings.pms_wake_interval - Pms.time <= WARMUP_PERIOD) && !Pms.wake_mode) { - - Pms.wake_mode = 1; - PmsSendCmd(CMD_WAKEUP); - } - if (Pms.time >= Settings.pms_wake_interval) { - - PmsSendCmd(CMD_READ_DATA); - Pms.ready = 1; - Pms.time = 0; - } - } - - if (Pms.ready) { - if (PmsReadData()) { - Pms.valid = 10; - if (Settings.pms_wake_interval >= MIN_INTERVAL_PERIOD) { - PmsSendCmd(CMD_SLEEP); - Pms.wake_mode = 0; - Pms.ready = 0; - } - } else { - if (Pms.valid) { - Pms.valid--; - if (Settings.pms_wake_interval >= MIN_INTERVAL_PERIOD) { - PmsSendCmd(CMD_READ_DATA); - Pms.ready = 1; - } - } - } - } -} - - - -void PmsInit(void) -{ - Pms.type = 0; - if (pin[GPIO_PMS5003_RX] < 99) { - PmsSerial = new TasmotaSerial(pin[GPIO_PMS5003_RX], (pin[GPIO_PMS5003_TX] < 99) ? pin[GPIO_PMS5003_TX] : -1, 1); - if (PmsSerial->begin(9600)) { - if (PmsSerial->hardwareSerial()) { ClaimSerial(); } - - if (99 == pin[GPIO_PMS5003_TX]) { - Settings.pms_wake_interval = 0; - Pms.ready = 1; - } - - Pms.type = 1; - } - } -} - -#ifdef USE_WEBSERVER -#ifdef PMS_MODEL_PMS3003 -const char HTTP_PMS3003_SNS[] PROGMEM = - - - - "{s}PMS3003 " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS3003 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS3003 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; -#else -const char HTTP_PMS5003_SNS[] PROGMEM = - - - - "{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 0.3 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 0.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; -#endif -#endif - -void PmsShow(bool json) -{ - if (Pms.valid) { - if (json) { -#ifdef PMS_MODEL_PMS3003 - ResponseAppend_P(PSTR(",\"PMS3003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d}"), - pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard, - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env); -#else - ResponseAppend_P(PSTR(",\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"), - pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard, - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env, - pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um); -#endif -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_COUNT, pms_data.pm10_env); - DomoticzSensor(DZ_VOLTAGE, pms_data.pm25_env); - DomoticzSensor(DZ_CURRENT, pms_data.pm100_env); - } -#endif -#ifdef USE_WEBSERVER - } else { - -#ifdef PMS_MODEL_PMS3003 - WSContentSend_PD(HTTP_PMS3003_SNS, - - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env); -#else - WSContentSend_PD(HTTP_PMS5003_SNS, - - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env, - pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um); -#endif -#endif - } - } -} - - - - - -bool Xsns18(uint8_t function) -{ - bool result = false; - - if (Pms.type) { - switch (function) { - case FUNC_INIT: - PmsInit(); - break; - case FUNC_EVERY_SECOND: - PmsSecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_18 == XdrvMailbox.index) { - result = PmsCommandSensor(); - } - break; - case FUNC_JSON_APPEND: - PmsShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - PmsShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_19_mgs.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_19_mgs.ino" -#ifdef USE_I2C -#ifdef USE_MGS - - - - - - - -#define XSNS_19 19 -#define XI2C_17 17 - -#ifndef MGS_SENSOR_ADDR -#define MGS_SENSOR_ADDR 0x04 -#endif - -#include "MutichannelGasSensor.h" - -bool mgs_detected = false; - -void MGSInit(void) { - gas.begin(MGS_SENSOR_ADDR); -} - -void MGSPrepare(void) -{ - if (I2cActive(MGS_SENSOR_ADDR)) { return; } - - gas.begin(MGS_SENSOR_ADDR); - if (!gas.isError()) { - I2cSetActiveFound(MGS_SENSOR_ADDR, "MultiGas"); - mgs_detected = true; - } -} - -char* measure_gas(int gas_type, char* buffer) -{ - float f = gas.calcGas(gas_type); - dtostrfd(f, 2, buffer); - return buffer; -} - -#ifdef USE_WEBSERVER -const char HTTP_MGS_GAS[] PROGMEM = "{s}MGS %s{m}%s " D_UNIT_PARTS_PER_MILLION "{e}"; -#endif - -void MGSShow(bool json) -{ - char buffer[33]; - if (json) { - ResponseAppend_P(PSTR(",\"MGS\":{\"NH3\":%s"), measure_gas(NH3, buffer)); - ResponseAppend_P(PSTR(",\"CO\":%s"), measure_gas(CO, buffer)); - ResponseAppend_P(PSTR(",\"NO2\":%s"), measure_gas(NO2, buffer)); - ResponseAppend_P(PSTR(",\"C3H8\":%s"), measure_gas(C3H8, buffer)); - ResponseAppend_P(PSTR(",\"C4H10\":%s"), measure_gas(C4H10, buffer)); - ResponseAppend_P(PSTR(",\"CH4\":%s"), measure_gas(GAS_CH4, buffer)); - ResponseAppend_P(PSTR(",\"H2\":%s"), measure_gas(H2, buffer)); - ResponseAppend_P(PSTR(",\"C2H5OH\":%s}"), measure_gas(C2H5OH, buffer)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_MGS_GAS, "NH3", measure_gas(NH3, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "CO", measure_gas(CO, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "NO2", measure_gas(NO2, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "C3H8", measure_gas(C3H8, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "C4H10", measure_gas(C4H10, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "CH4", measure_gas(GAS_CH4, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "H2", measure_gas(H2, buffer)); - WSContentSend_PD(HTTP_MGS_GAS, "C2H5OH", measure_gas(C2H5OH, buffer)); -#endif - } -} - - - - - -bool Xsns19(uint8_t function) -{ - if (!I2cEnabled(XI2C_17)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - MGSPrepare(); - } - else if (mgs_detected) { - switch (function) { - case FUNC_JSON_APPEND: - MGSShow(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MGSShow(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_20_novasds.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_20_novasds.ino" -#ifdef USE_NOVA_SDS -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_20_novasds.ino" -#define XSNS_20 20 - -#include - -#ifndef STARTING_OFFSET -#define STARTING_OFFSET 30 -#endif -#if STARTING_OFFSET < 10 -#error "Please set STARTING_OFFSET >= 10" -#endif -#ifndef NOVA_SDS_RECDATA_TIMEOUT -#define NOVA_SDS_RECDATA_TIMEOUT 150 -#endif -#ifndef NOVA_SDS_DEVICE_ID -#define NOVA_SDS_DEVICE_ID 0xFFFF -#endif - -TasmotaSerial *NovaSdsSerial; - -uint8_t novasds_type = 1; -uint8_t novasds_valid = 0; -uint8_t cont_mode = 1; - -struct sds011data { - uint16_t pm100; - uint16_t pm25; -} novasds_data; -uint16_t pm100_sum; -uint16_t pm25_sum; - - -#define NOVA_SDS_REPORTING_MODE 2 -#define NOVA_SDS_QUERY_DATA 4 -#define NOVA_SDS_SET_DEVICE_ID 5 -#define NOVA_SDS_SLEEP_AND_WORK 6 -#define NOVA_SDS_WORKING_PERIOD 8 -#define NOVA_SDS_CHECK_FIRMWARE_VER 7 - #define NOVA_SDS_QUERY_MODE 0 - #define NOVA_SDS_SET_MODE 1 - #define NOVA_SDS_REPORT_ACTIVE 0 - #define NOVA_SDS_REPORT_QUERY 1 - #define NOVA_SDS_SLEEP 0 - #define NOVA_SDS_WORK 1 - - -bool NovaSdsCommand(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint16_t sensorid, uint8_t *buffer) -{ - uint8_t novasds_cmnd[19] = {0xAA, 0xB4, byte1, byte2, byte3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (uint8_t)(sensorid & 0xFF), (uint8_t)((sensorid>>8) & 0xFF), 0x00, 0xAB}; - - - for (uint32_t i = 2; i < 17; i++) { - novasds_cmnd[17] += novasds_cmnd[i]; - } - - - - - - NovaSdsSerial->write(novasds_cmnd, sizeof(novasds_cmnd)); - NovaSdsSerial->flush(); - - - unsigned long cmndtime = millis(); - while ( (TimePassedSince(cmndtime) < NOVA_SDS_RECDATA_TIMEOUT) && ( ! NovaSdsSerial->available() ) ); - if ( ! NovaSdsSerial->available() ) { - - return false; - } - uint8_t recbuf[10]; - memset(recbuf, 0, sizeof(recbuf)); - - while ( (TimePassedSince(cmndtime) < NOVA_SDS_RECDATA_TIMEOUT) && ( NovaSdsSerial->available() > 0) && (0xAA != (recbuf[0] = NovaSdsSerial->read())) ); - if ( 0xAA != recbuf[0] ) { - - return false; - } - - - NovaSdsSerial->readBytes(&recbuf[1], 9); - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, recbuf, sizeof(recbuf)); - - if ( nullptr != buffer ) { - - memcpy(buffer, recbuf, sizeof(recbuf)); - } - - - if ((0xAB != recbuf[9] ) || (recbuf[8] != ((recbuf[2] + recbuf[3] + recbuf[4] + recbuf[5] + recbuf[6] + recbuf[7]) & 0xFF))) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("SDS: " D_CHECKSUM_FAILURE)); - return false; - } - - return true; -} - -void NovaSdsSetWorkPeriod(void) -{ - - NovaSdsCommand(NOVA_SDS_WORKING_PERIOD, NOVA_SDS_SET_MODE, 0, NOVA_SDS_DEVICE_ID, nullptr); - - NovaSdsCommand(NOVA_SDS_REPORTING_MODE, NOVA_SDS_SET_MODE, NOVA_SDS_REPORT_QUERY, NOVA_SDS_DEVICE_ID, nullptr); -} - -bool NovaSdsReadData(void) -{ - uint8_t d[10]; - if ( ! NovaSdsCommand(NOVA_SDS_QUERY_DATA, 0, 0, NOVA_SDS_DEVICE_ID, d) ) { - return false; - } - novasds_data.pm25 = (d[2] + 256 * d[3]); - novasds_data.pm100 = (d[4] + 256 * d[5]); - - return true; -} - - - -void NovaSdsSecond(void) -{ - if (!novasds_valid) - { - NovaSdsSetWorkPeriod(); - novasds_valid=1; - } - if((Settings.tele_period - Settings.novasds_startingoffset <= 0)) - { - if(!cont_mode) - { - cont_mode = 1; - NovaSdsCommand(NOVA_SDS_SLEEP_AND_WORK, NOVA_SDS_SET_MODE, NOVA_SDS_WORK, NOVA_SDS_DEVICE_ID, nullptr); - } - } - else - cont_mode = 0; - - if(tele_period == Settings.tele_period - Settings.novasds_startingoffset && !cont_mode) - { - NovaSdsCommand(NOVA_SDS_SLEEP_AND_WORK, NOVA_SDS_SET_MODE, NOVA_SDS_WORK, NOVA_SDS_DEVICE_ID, nullptr); - } - if(tele_period >= Settings.tele_period-5 && tele_period <= Settings.tele_period-2) - { - if(!(NovaSdsReadData())) novasds_valid=0; - pm100_sum += novasds_data.pm100; - pm25_sum += novasds_data.pm25; - } - if(tele_period == Settings.tele_period-1) - { - novasds_data.pm100 = pm100_sum >> 2; - novasds_data.pm25 = pm25_sum >> 2; - if(!cont_mode) - NovaSdsCommand(NOVA_SDS_SLEEP_AND_WORK, NOVA_SDS_SET_MODE, NOVA_SDS_SLEEP, NOVA_SDS_DEVICE_ID, nullptr); - pm100_sum = pm25_sum = 0; - } -} - - - - - - - -bool NovaSdsCommandSensor(void) -{ - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 256)) { - if( XdrvMailbox.payload < 10 ) Settings.novasds_startingoffset = 10; - else Settings.novasds_startingoffset = XdrvMailbox.payload; - } - Response_P(S_JSON_SENSOR_INDEX_NVALUE, XSNS_20, Settings.novasds_startingoffset); - - return true; -} - -void NovaSdsInit(void) -{ - novasds_type = 0; - if (pin[GPIO_SDS0X1_RX] < 99 && pin[GPIO_SDS0X1_TX] < 99) { - NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1_RX], pin[GPIO_SDS0X1_TX], 1); - if (NovaSdsSerial->begin(9600)) { - if (NovaSdsSerial->hardwareSerial()) { - ClaimSerial(); - } - novasds_type = 1; - NovaSdsSetWorkPeriod(); - } - } -} - -#ifdef USE_WEBSERVER -const char HTTP_SDS0X1_SNS[] PROGMEM = - "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; -#endif - -void NovaSdsShow(bool json) -{ - if (novasds_valid) { - float pm10f = (float)(novasds_data.pm100) / 10.0f; - float pm2_5f = (float)(novasds_data.pm25) / 10.0f; - char pm10[33]; - dtostrfd(pm10f, 1, pm10); - char pm2_5[33]; - dtostrfd(pm2_5f, 1, pm2_5); - if (json) { - ResponseAppend_P(PSTR(",\"SDS0X1\":{\"PM2.5\":%s,\"PM10\":%s}"), pm2_5, pm10); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_VOLTAGE, pm2_5); - DomoticzSensor(DZ_CURRENT, pm10); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SDS0X1_SNS, pm2_5, pm10); -#endif - } - } -} - - - - - -bool Xsns20(uint8_t function) -{ - bool result = false; - - if (novasds_type) { - switch (function) { - case FUNC_INIT: - NovaSdsInit(); - break; - case FUNC_EVERY_SECOND: - NovaSdsSecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_20 == XdrvMailbox.index) { - result = NovaSdsCommandSensor(); - } - break; - case FUNC_JSON_APPEND: - NovaSdsShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - NovaSdsShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_21_sgp30.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_21_sgp30.ino" -#ifdef USE_I2C -#ifdef USE_SGP30 -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_21_sgp30.ino" -#define XSNS_21 21 -#define XI2C_18 18 - -#define SGP30_ADDRESS 0x58 - -#include "Adafruit_SGP30.h" -Adafruit_SGP30 sgp; - -bool sgp30_type = false; -bool sgp30_ready = false; -float sgp30_abshum; - - - -void sgp30_Init(void) -{ - if (I2cActive(SGP30_ADDRESS)) { return; } - - if (sgp.begin()) { - sgp30_type = true; - - I2cSetActiveFound(SGP30_ADDRESS, "SGP30"); - } -} - - -#define POW_FUNC FastPrecisePow - -float sgp30_AbsoluteHumidity(float temperature, float humidity,char tempUnit) { - - - - - - float temp = NAN; - const float mw = 18.01534; - const float r = 8.31447215; - - if (isnan(temperature) || isnan(humidity) ) { - return NAN; - } - - if (tempUnit != 'C') { - temperature = (temperature - 32.0) * (5.0 / 9.0); - } - - temp = POW_FUNC(2.718281828, (17.67 * temperature) / (temperature + 243.5)); - - - return (6.112 * temp * humidity * mw) / ((273.15 + temperature) * r); -} - -#define SAVE_PERIOD 30 - -void Sgp30Update(void) -{ - sgp30_ready = false; - if (!sgp.IAQmeasure()) { - return; - } - if (global_update && (global_humidity > 0) && (global_temperature != 9999)) { - - sgp30_abshum=sgp30_AbsoluteHumidity(global_temperature,global_humidity,TempUnit()); - sgp.setHumidity(sgp30_abshum*1000); - } - sgp30_ready = true; - - - if (!(uptime%SAVE_PERIOD)) { - - uint16_t TVOC_base; - uint16_t eCO2_base; - - if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; - - } -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_SGP30[] PROGMEM = - "{s}SGP30 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" - "{s}SGP30 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; -const char HTTP_SNS_AHUM[] PROGMEM = "{s}SGP30 Abs Humidity{m}%s g/m3{e}"; -#endif - -#define D_JSON_AHUM "aHumidity" - -void Sgp30Show(bool json) -{ - if (sgp30_ready) { - char abs_hum[33]; - - if (json) { - ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC); - if (global_update && global_humidity>0 && global_temperature!=9999) { - - dtostrfd(sgp30_abshum,4,abs_hum); - ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum); - } - ResponseJsonEnd(); -#ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, sgp.eCO2); -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_SGP30, sgp.eCO2, sgp.TVOC); - if (global_update) { - WSContentSend_PD(HTTP_SNS_AHUM, abs_hum); - } -#endif - } - } -} - - - - - -bool Xsns21(uint8_t function) -{ - if (!I2cEnabled(XI2C_18)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - sgp30_Init(); - } - else if (sgp30_type) { - switch (function) { - case FUNC_EVERY_SECOND: - Sgp30Update(); - break; - case FUNC_JSON_APPEND: - Sgp30Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Sgp30Show(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_22_sr04.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_22_sr04.ino" -#ifdef USE_SR04 - -#include -#include -# 32 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_22_sr04.ino" -#define XSNS_22 22 - -uint8_t sr04_type = 1; -real64_t distance; - -NewPing* sonar = nullptr; -TasmotaSerial* sonar_serial = nullptr; - -uint8_t Sr04TModeDetect(void) -{ - sr04_type = 0; - if (99 == pin[GPIO_SR04_ECHO]) { return sr04_type; } - - int sr04_echo_pin = pin[GPIO_SR04_ECHO]; - int sr04_trig_pin = (pin[GPIO_SR04_TRIG] < 99) ? pin[GPIO_SR04_TRIG] : -1; - sonar_serial = new TasmotaSerial(sr04_echo_pin, sr04_trig_pin, 1); - - if (sonar_serial->begin(9600,1)) { - DEBUG_SENSOR_LOG(PSTR("SR04: Detect mode")); - - if (sr04_trig_pin != -1) { - sr04_type = (Sr04TMiddleValue(Sr04TMode3Distance(), Sr04TMode3Distance(), Sr04TMode3Distance()) != NO_ECHO) ? 3 : 1; - } else { - sr04_type = 2; - } - } else { - sr04_type = 1; - } - - if (sr04_type < 2) { - delete sonar_serial; - sonar_serial = nullptr; - if (-1 == sr04_trig_pin) { - sr04_trig_pin = pin[GPIO_SR04_ECHO]; - } - sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, 300); - } else { - if (sonar_serial->hardwareSerial()) { - ClaimSerial(); - } - } - - AddLog_P2(LOG_LEVEL_INFO,PSTR("SR04: Mode %d"), sr04_type); - return sr04_type; -} - -uint16_t Sr04TMiddleValue(uint16_t first, uint16_t second, uint16_t third) -{ - uint16_t ret = first; - if (first > second) { - first = second; - second = ret; - } - - if (third < first) { - return first; - } else if (third > second) { - return second; - } else { - return third; - } -} - -uint16_t Sr04TMode3Distance() { - - sonar_serial->write(0x55); - sonar_serial->flush(); - - return Sr04TMode2Distance(); -} - -uint16_t Sr04TMode2Distance(void) -{ - sonar_serial->setTimeout(300); - const char startByte = 0xff; - - if (!sonar_serial->find(startByte)) { - - return NO_ECHO; - } - - delay(5); - - uint8_t crc = sonar_serial->read(); - - uint16_t distance = ((uint16_t)crc) << 8; - - - distance += sonar_serial->read(); - crc += distance & 0x00ff; - crc += 0x00FF; - - - if (crc != sonar_serial->read()) { - AddLog_P2(LOG_LEVEL_ERROR,PSTR("SR04: Reading CRC error.")); - return NO_ECHO; - } - - return distance; -} - -void Sr04TReading(void) { - - if (sonar_serial==nullptr && sonar==nullptr) { - Sr04TModeDetect(); - } - - switch (sr04_type) { - case 3: - distance = (real64_t)(Sr04TMiddleValue(Sr04TMode3Distance(),Sr04TMode3Distance(),Sr04TMode3Distance()))/ 10; - break; - case 2: - - while(sonar_serial->available()) sonar_serial->read(); - distance = (real64_t)(Sr04TMiddleValue(Sr04TMode2Distance(),Sr04TMode2Distance(),Sr04TMode2Distance()))/10; - break; - case 1: - distance = (real64_t)(sonar->ping_median(5))/ US_ROUNDTRIP_CM; - break; - default: - distance = NO_ECHO; - } - - return; -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_DISTANCE[] PROGMEM = - "{s}SR04 " D_DISTANCE "{m}%s" D_UNIT_CENTIMETER "{e}"; -#endif - -void Sr04Show(bool json) -{ - - if (distance != 0) { - char distance_chr[33]; - dtostrfd(distance, 3, distance_chr); - - if(json) { - ResponseAppend_P(PSTR(",\"SR04\":{\"" D_JSON_DISTANCE "\":%s}"), distance_chr); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_COUNT, distance_chr); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_DISTANCE, distance_chr); -#endif - } - } -} - - - - - -bool Xsns22(uint8_t function) -{ - bool result = false; - - if (sr04_type) { - switch (function) { - case FUNC_INIT: - result = (pin[GPIO_SR04_ECHO]<99); - break; - case FUNC_EVERY_SECOND: - Sr04TReading(); - result = true; - break; - case FUNC_JSON_APPEND: - Sr04Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Sr04Show(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_24_si1145.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_24_si1145.ino" -#ifdef USE_I2C -#ifdef USE_SI1145 -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_24_si1145.ino" -#define XSNS_24 24 -#define XI2C_19 19 - -#define SI114X_ADDR 0X60 - - - -#define SI114X_QUERY 0X80 -#define SI114X_SET 0XA0 -#define SI114X_NOP 0X00 -#define SI114X_RESET 0X01 -#define SI114X_BUSADDR 0X02 -#define SI114X_PS_FORCE 0X05 -#define SI114X_GET_CAL 0X12 -#define SI114X_ALS_FORCE 0X06 -#define SI114X_PSALS_FORCE 0X07 -#define SI114X_PS_PAUSE 0X09 -#define SI114X_ALS_PAUSE 0X0A -#define SI114X_PSALS_PAUSE 0X0B -#define SI114X_PS_AUTO 0X0D -#define SI114X_ALS_AUTO 0X0E -#define SI114X_PSALS_AUTO 0X0F - - - -#define SI114X_PART_ID 0X00 -#define SI114X_REV_ID 0X01 -#define SI114X_SEQ_ID 0X02 -#define SI114X_INT_CFG 0X03 -#define SI114X_IRQ_ENABLE 0X04 -#define SI114X_IRQ_MODE1 0x05 -#define SI114X_IRQ_MODE2 0x06 -#define SI114X_HW_KEY 0X07 -#define SI114X_MEAS_RATE0 0X08 -#define SI114X_MEAS_RATE1 0X09 -#define SI114X_PS_RATE 0X0A -#define SI114X_PS_LED21 0X0F -#define SI114X_PS_LED3 0X10 -#define SI114X_UCOEFF0 0X13 -#define SI114X_UCOEFF1 0X14 -#define SI114X_UCOEFF2 0X15 -#define SI114X_UCOEFF3 0X16 -#define SI114X_WR 0X17 -#define SI114X_COMMAND 0X18 -#define SI114X_RESPONSE 0X20 -#define SI114X_IRQ_STATUS 0X21 -#define SI114X_ALS_VIS_DATA0 0X22 -#define SI114X_ALS_VIS_DATA1 0X23 -#define SI114X_ALS_IR_DATA0 0X24 -#define SI114X_ALS_IR_DATA1 0X25 -#define SI114X_PS1_DATA0 0X26 -#define SI114X_PS1_DATA1 0X27 -#define SI114X_PS2_DATA0 0X28 -#define SI114X_PS2_DATA1 0X29 -#define SI114X_PS3_DATA0 0X2A -#define SI114X_PS3_DATA1 0X2B -#define SI114X_AUX_DATA0_UVINDEX0 0X2C -#define SI114X_AUX_DATA1_UVINDEX1 0X2D -#define SI114X_RD 0X2E -#define SI114X_CHIP_STAT 0X30 - - - -#define SI114X_CHLIST 0X01 -#define SI114X_CHLIST_ENUV 0x80 -#define SI114X_CHLIST_ENAUX 0x40 -#define SI114X_CHLIST_ENALSIR 0x20 -#define SI114X_CHLIST_ENALSVIS 0x10 -#define SI114X_CHLIST_ENPS1 0x01 -#define SI114X_CHLIST_ENPS2 0x02 -#define SI114X_CHLIST_ENPS3 0x04 - -#define SI114X_PSLED12_SELECT 0X02 -#define SI114X_PSLED3_SELECT 0X03 - -#define SI114X_PS_ENCODE 0X05 -#define SI114X_ALS_ENCODE 0X06 - -#define SI114X_PS1_ADCMUX 0X07 -#define SI114X_PS2_ADCMUX 0X08 -#define SI114X_PS3_ADCMUX 0X09 - -#define SI114X_PS_ADC_COUNTER 0X0A -#define SI114X_PS_ADC_GAIN 0X0B -#define SI114X_PS_ADC_MISC 0X0C - -#define SI114X_ALS_IR_ADC_MUX 0X0E -#define SI114X_AUX_ADC_MUX 0X0F - -#define SI114X_ALS_VIS_ADC_COUNTER 0X10 -#define SI114X_ALS_VIS_ADC_GAIN 0X11 -#define SI114X_ALS_VIS_ADC_MISC 0X12 - -#define SI114X_LED_REC 0X1C - -#define SI114X_ALS_IR_ADC_COUNTER 0X1D -#define SI114X_ALS_IR_ADC_GAIN 0X1E -#define SI114X_ALS_IR_ADC_MISC 0X1F - - - - -#define SI114X_ADCMUX_SMALL_IR 0x00 -#define SI114X_ADCMUX_VISIABLE 0x02 -#define SI114X_ADCMUX_LARGE_IR 0x03 -#define SI114X_ADCMUX_NO 0x06 -#define SI114X_ADCMUX_GND 0x25 -#define SI114X_ADCMUX_TEMPERATURE 0x65 -#define SI114X_ADCMUX_VDD 0x75 - -#define SI114X_PSLED12_SELECT_PS1_NONE 0x00 -#define SI114X_PSLED12_SELECT_PS1_LED1 0x01 -#define SI114X_PSLED12_SELECT_PS1_LED2 0x02 -#define SI114X_PSLED12_SELECT_PS1_LED3 0x04 -#define SI114X_PSLED12_SELECT_PS2_NONE 0x00 -#define SI114X_PSLED12_SELECT_PS2_LED1 0x10 -#define SI114X_PSLED12_SELECT_PS2_LED2 0x20 -#define SI114X_PSLED12_SELECT_PS2_LED3 0x40 -#define SI114X_PSLED3_SELECT_PS2_NONE 0x00 -#define SI114X_PSLED3_SELECT_PS2_LED1 0x10 -#define SI114X_PSLED3_SELECT_PS2_LED2 0x20 -#define SI114X_PSLED3_SELECT_PS2_LED3 0x40 - -#define SI114X_ADC_GAIN_DIV1 0X00 -#define SI114X_ADC_GAIN_DIV2 0X01 -#define SI114X_ADC_GAIN_DIV4 0X02 -#define SI114X_ADC_GAIN_DIV8 0X03 -#define SI114X_ADC_GAIN_DIV16 0X04 -#define SI114X_ADC_GAIN_DIV32 0X05 - -#define SI114X_LED_CURRENT_5MA 0X01 -#define SI114X_LED_CURRENT_11MA 0X02 -#define SI114X_LED_CURRENT_22MA 0X03 -#define SI114X_LED_CURRENT_45MA 0X04 - -#define SI114X_ADC_COUNTER_1ADCCLK 0X00 -#define SI114X_ADC_COUNTER_7ADCCLK 0X01 -#define SI114X_ADC_COUNTER_15ADCCLK 0X02 -#define SI114X_ADC_COUNTER_31ADCCLK 0X03 -#define SI114X_ADC_COUNTER_63ADCCLK 0X04 -#define SI114X_ADC_COUNTER_127ADCCLK 0X05 -#define SI114X_ADC_COUNTER_255ADCCLK 0X06 -#define SI114X_ADC_COUNTER_511ADCCLK 0X07 - -#define SI114X_ADC_MISC_LOWRANGE 0X00 -#define SI114X_ADC_MISC_HIGHRANGE 0X20 -#define SI114X_ADC_MISC_ADC_NORMALPROXIMITY 0X00 -#define SI114X_ADC_MISC_ADC_RAWADC 0X04 - -#define SI114X_INT_CFG_INTOE 0X01 - -#define SI114X_IRQEN_ALS 0x01 -#define SI114X_IRQEN_PS1 0x04 -#define SI114X_IRQEN_PS2 0x08 -#define SI114X_IRQEN_PS3 0x10 - -uint16_t si1145_visible; -uint16_t si1145_infrared; -uint16_t si1145_uvindex; - -bool si1145_type = false; -uint8_t si1145_valid = 0; - - - -uint8_t Si1145ReadByte(uint8_t reg) -{ - return I2cRead8(SI114X_ADDR, reg); -} - -uint16_t Si1145ReadHalfWord(uint8_t reg) -{ - return I2cRead16LE(SI114X_ADDR, reg); -} - -bool Si1145WriteByte(uint8_t reg, uint16_t val) -{ - I2cWrite8(SI114X_ADDR, reg, val); -} - -uint8_t Si1145WriteParamData(uint8_t p, uint8_t v) -{ - Si1145WriteByte(SI114X_WR, v); - Si1145WriteByte(SI114X_COMMAND, p | SI114X_SET); - return Si1145ReadByte(SI114X_RD); -} - - - -bool Si1145Present(void) -{ - return (Si1145ReadByte(SI114X_PART_ID) == 0X45); -} - -void Si1145Reset(void) -{ - Si1145WriteByte(SI114X_MEAS_RATE0, 0); - Si1145WriteByte(SI114X_MEAS_RATE1, 0); - Si1145WriteByte(SI114X_IRQ_ENABLE, 0); - Si1145WriteByte(SI114X_IRQ_MODE1, 0); - Si1145WriteByte(SI114X_IRQ_MODE2, 0); - Si1145WriteByte(SI114X_INT_CFG, 0); - Si1145WriteByte(SI114X_IRQ_STATUS, 0xFF); - - Si1145WriteByte(SI114X_COMMAND, SI114X_RESET); - delay(10); - Si1145WriteByte(SI114X_HW_KEY, 0x17); - delay(10); -} - -void Si1145DeInit(void) -{ - - - Si1145WriteByte(SI114X_UCOEFF0, 0x29); - Si1145WriteByte(SI114X_UCOEFF1, 0x89); - Si1145WriteByte(SI114X_UCOEFF2, 0x02); - Si1145WriteByte(SI114X_UCOEFF3, 0x00); - Si1145WriteParamData(SI114X_CHLIST, SI114X_CHLIST_ENUV | SI114X_CHLIST_ENALSIR | SI114X_CHLIST_ENALSVIS | SI114X_CHLIST_ENPS1); - - - - Si1145WriteParamData(SI114X_PS1_ADCMUX, SI114X_ADCMUX_LARGE_IR); - Si1145WriteByte(SI114X_PS_LED21, SI114X_LED_CURRENT_22MA); - Si1145WriteParamData(SI114X_PSLED12_SELECT, SI114X_PSLED12_SELECT_PS1_LED1); - - - - Si1145WriteParamData(SI114X_PS_ADC_GAIN, SI114X_ADC_GAIN_DIV1); - Si1145WriteParamData(SI114X_PS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK); - Si1145WriteParamData(SI114X_PS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE | SI114X_ADC_MISC_ADC_RAWADC); - - - - Si1145WriteParamData(SI114X_ALS_VIS_ADC_GAIN, SI114X_ADC_GAIN_DIV1); - Si1145WriteParamData(SI114X_ALS_VIS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK); - Si1145WriteParamData(SI114X_ALS_VIS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE); - - - - Si1145WriteParamData(SI114X_ALS_IR_ADC_GAIN, SI114X_ADC_GAIN_DIV1); - Si1145WriteParamData(SI114X_ALS_IR_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK); - Si1145WriteParamData(SI114X_ALS_IR_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE); - - - - Si1145WriteByte(SI114X_INT_CFG, SI114X_INT_CFG_INTOE); - Si1145WriteByte(SI114X_IRQ_ENABLE, SI114X_IRQEN_ALS); - - - - Si1145WriteByte(SI114X_MEAS_RATE0, 0xFF); - Si1145WriteByte(SI114X_COMMAND, SI114X_PSALS_AUTO); -} - -bool Si1145Begin(void) -{ - if (!Si1145Present()) { return false; } - - Si1145Reset(); - Si1145DeInit(); - return true; -} - - -uint16_t Si1145ReadUV(void) -{ - return Si1145ReadHalfWord(SI114X_AUX_DATA0_UVINDEX0); -} - - -uint16_t Si1145ReadVisible(void) -{ - return Si1145ReadHalfWord(SI114X_ALS_VIS_DATA0); -} - - -uint16_t Si1145ReadIR(void) -{ - return Si1145ReadHalfWord(SI114X_ALS_IR_DATA0); -} - - - -bool Si1145Read(void) -{ - if (si1145_valid) { si1145_valid--; } - - if (!Si1145Present()) { return false; } - - si1145_visible = Si1145ReadVisible(); - si1145_infrared = Si1145ReadIR(); - si1145_uvindex = Si1145ReadUV(); - si1145_valid = SENSOR_MAX_MISS; - return true; -} - -void Si1145Detect(void) -{ - if (I2cActive(SI114X_ADDR)) { return; } - - if (Si1145Begin()) { - si1145_type = true; - I2cSetActiveFound(SI114X_ADDR, "SI1145"); - } -} - -void Si1145Update(void) -{ - if (!Si1145Read()) { - AddLogMissed("SI1145", si1145_valid); - } -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_SI1145[] PROGMEM = - "{s}SI1145 " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}" - "{s}SI1145 " D_INFRARED "{m}%d " D_UNIT_LUX "{e}" - "{s}SI1145 " D_UV_INDEX "{m}%d.%d{e}"; -#endif - -void Si1145Show(bool json) -{ - if (si1145_valid) { - if (json) { - ResponseAppend_P(PSTR(",\"SI1145\":{\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_INFRARED "\":%d,\"" D_JSON_UV_INDEX "\":%d.%d}"), - si1145_visible, si1145_infrared, si1145_uvindex /100, si1145_uvindex %100); -#ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, si1145_visible); -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_SI1145, si1145_visible, si1145_infrared, si1145_uvindex /100, si1145_uvindex %100); -#endif - } - } -} - - - - - -bool Xsns24(uint8_t function) -{ - if (!I2cEnabled(XI2C_19)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Si1145Detect(); - } - else if (si1145_type) { - switch (function) { - case FUNC_EVERY_SECOND: - Si1145Update(); - break; - case FUNC_JSON_APPEND: - Si1145Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Si1145Show(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_26_lm75ad.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_26_lm75ad.ino" -#ifdef USE_I2C -#ifdef USE_LM75AD -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_26_lm75ad.ino" -#define XSNS_26 26 -#define XI2C_20 20 - -#define LM75AD_ADDRESS1 0x48 -#define LM75AD_ADDRESS2 0x49 -#define LM75AD_ADDRESS3 0x4A -#define LM75AD_ADDRESS4 0x4B -#define LM75AD_ADDRESS5 0x4C -#define LM75AD_ADDRESS6 0x4D -#define LM75AD_ADDRESS7 0x4E -#define LM75AD_ADDRESS8 0x4F - -#define LM75_TEMP_REGISTER 0x00 -#define LM75_CONF_REGISTER 0x01 -#define LM75_THYST_REGISTER 0x02 -#define LM75_TOS_REGISTER 0x03 - -bool lm75ad_type = false; -uint8_t lm75ad_address; -uint8_t lm75ad_addresses[] = { LM75AD_ADDRESS1, LM75AD_ADDRESS2, LM75AD_ADDRESS3, LM75AD_ADDRESS4, LM75AD_ADDRESS5, LM75AD_ADDRESS6, LM75AD_ADDRESS7, LM75AD_ADDRESS8 }; - -void LM75ADDetect(void) -{ - for (uint32_t i = 0; i < sizeof(lm75ad_addresses); i++) { - lm75ad_address = lm75ad_addresses[i]; - if (I2cActive(lm75ad_address)) { - continue; } - if (!I2cSetDevice(lm75ad_address)) { - break; - } - uint16_t buffer; - if (I2cValidRead16(&buffer, lm75ad_address, LM75_THYST_REGISTER)) { - if (buffer == 0x4B00) { - lm75ad_type = true; - I2cSetActiveFound(lm75ad_address, "LM75AD"); - break; - } - } - } -} - -float LM75ADGetTemp(void) -{ - int16_t sign = 1; - - uint16_t t = I2cRead16(lm75ad_address, LM75_TEMP_REGISTER); - if (t & 0x8000) { - t = (~t) +0x20; - sign = -1; - } - t = t >> 5; - return ConvertTemp(sign * t * 0.125); -} - -void LM75ADShow(bool json) -{ - float t = LM75ADGetTemp(); - char temperature[33]; - dtostrfd(t, Settings.flag2.temperature_resolution, temperature); - - if (json) { - ResponseAppend_P(PSTR(",\"LM75AD\":{\"" D_JSON_TEMPERATURE "\":%s}"), temperature); -#ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_TEMP, temperature); -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, "LM75AD", temperature, TempUnit()); -#endif - } -} - - - - - -bool Xsns26(uint8_t function) -{ - if (!I2cEnabled(XI2C_20)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - LM75ADDetect(); - } - else if (lm75ad_type) { - switch (function) { - case FUNC_JSON_APPEND: - LM75ADShow(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - LM75ADShow(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -# 28 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -#ifdef USE_I2C -#ifdef USE_APDS9960 -# 39 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -#define XSNS_27 27 -#define XI2C_21 21 -# 55 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -#define APDS9960_I2C_ADDR 0x39 - -#define APDS9960_CHIPID_1 0xAB -#define APDS9960_CHIPID_2 0x9C -#define APDS9960_CHIPID_3 0xA8 - -#define APDS9930_CHIPID_1 0x12 -#define APDS9930_CHIPID_2 0x39 - - -#define GESTURE_THRESHOLD_OUT 10 -#define GESTURE_SENSITIVITY_1 50 -#define GESTURE_SENSITIVITY_2 20 - -uint8_t APDS9960addr; -uint8_t APDS9960type = 0; -char APDS9960stype[] = "APDS9960"; -char currentGesture[6]; -uint8_t gesture_mode = 1; - - -volatile uint8_t recovery_loop_counter = 0; -#define APDS9960_LONG_RECOVERY 50 -#define APDS9960_MAX_GESTURE_CYCLES 50 -bool APDS9960_overload = false; - -#ifdef USE_WEBSERVER -const char HTTP_APDS_9960_SNS[] PROGMEM = - "{s}" "Red" "{m}%s{e}" - "{s}" "Green" "{m}%s{e}" - "{s}" "Blue" "{m}%s{e}" - "{s}" "Ambient" "{m}%s " D_UNIT_LUX "{e}" - "{s}" "CCT" "{m}%s " "K" "{e}" - "{s}" "Proximity" "{m}%s{e}"; -#endif -# 98 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -#define FIFO_PAUSE_TIME 30 - - -#define APDS9960_ENABLE 0x80 -#define APDS9960_ATIME 0x81 -#define APDS9960_WTIME 0x83 -#define APDS9960_AILTL 0x84 -#define APDS9960_AILTH 0x85 -#define APDS9960_AIHTL 0x86 -#define APDS9960_AIHTH 0x87 -#define APDS9960_PILT 0x89 -#define APDS9960_PIHT 0x8B -#define APDS9960_PERS 0x8C -#define APDS9960_CONFIG1 0x8D -#define APDS9960_PPULSE 0x8E -#define APDS9960_CONTROL 0x8F -#define APDS9960_CONFIG2 0x90 -#define APDS9960_ID 0x92 -#define APDS9960_STATUS 0x93 -#define APDS9960_CDATAL 0x94 -#define APDS9960_CDATAH 0x95 -#define APDS9960_RDATAL 0x96 -#define APDS9960_RDATAH 0x97 -#define APDS9960_GDATAL 0x98 -#define APDS9960_GDATAH 0x99 -#define APDS9960_BDATAL 0x9A -#define APDS9960_BDATAH 0x9B -#define APDS9960_PDATA 0x9C -#define APDS9960_POFFSET_UR 0x9D -#define APDS9960_POFFSET_DL 0x9E -#define APDS9960_CONFIG3 0x9F -#define APDS9960_GPENTH 0xA0 -#define APDS9960_GEXTH 0xA1 -#define APDS9960_GCONF1 0xA2 -#define APDS9960_GCONF2 0xA3 -#define APDS9960_GOFFSET_U 0xA4 -#define APDS9960_GOFFSET_D 0xA5 -#define APDS9960_GOFFSET_L 0xA7 -#define APDS9960_GOFFSET_R 0xA9 -#define APDS9960_GPULSE 0xA6 -#define APDS9960_GCONF3 0xAA -#define APDS9960_GCONF4 0xAB -#define APDS9960_GFLVL 0xAE -#define APDS9960_GSTATUS 0xAF -#define APDS9960_IFORCE 0xE4 -#define APDS9960_PICLEAR 0xE5 -#define APDS9960_CICLEAR 0xE6 -#define APDS9960_AICLEAR 0xE7 -#define APDS9960_GFIFO_U 0xFC -#define APDS9960_GFIFO_D 0xFD -#define APDS9960_GFIFO_L 0xFE -#define APDS9960_GFIFO_R 0xFF - - -#define APDS9960_PON 0b00000001 -#define APDS9960_AEN 0b00000010 -#define APDS9960_PEN 0b00000100 -#define APDS9960_WEN 0b00001000 -#define APSD9960_AIEN 0b00010000 -#define APDS9960_PIEN 0b00100000 -#define APDS9960_GEN 0b01000000 -#define APDS9960_GVALID 0b00000001 - - -#define OFF 0 -#define ON 1 - - -#define POWER 0 -#define AMBIENT_LIGHT 1 -#define PROXIMITY 2 -#define WAIT 3 -#define AMBIENT_LIGHT_INT 4 -#define PROXIMITY_INT 5 -#define GESTURE 6 -#define ALL 7 - - -#define LED_DRIVE_100MA 0 -#define LED_DRIVE_50MA 1 -#define LED_DRIVE_25MA 2 -#define LED_DRIVE_12_5MA 3 - - -#define PGAIN_1X 0 -#define PGAIN_2X 1 -#define PGAIN_4X 2 -#define PGAIN_8X 3 - - -#define AGAIN_1X 0 -#define AGAIN_4X 1 -#define AGAIN_16X 2 -#define AGAIN_64X 3 - - -#define GGAIN_1X 0 -#define GGAIN_2X 1 -#define GGAIN_4X 2 -#define GGAIN_8X 3 - - -#define LED_BOOST_100 0 -#define LED_BOOST_150 1 -#define LED_BOOST_200 2 -#define LED_BOOST_300 3 - - -#define GWTIME_0MS 0 -#define GWTIME_2_8MS 1 -#define GWTIME_5_6MS 2 -#define GWTIME_8_4MS 3 -#define GWTIME_14_0MS 4 -#define GWTIME_22_4MS 5 -#define GWTIME_30_8MS 6 -#define GWTIME_39_2MS 7 - - -#define DEFAULT_ATIME 0xdb -#define DEFAULT_WTIME 246 -#define DEFAULT_PROX_PPULSE 0x87 -#define DEFAULT_GESTURE_PPULSE 0x89 -#define DEFAULT_POFFSET_UR 0 -#define DEFAULT_POFFSET_DL 0 -#define DEFAULT_CONFIG1 0x60 -#define DEFAULT_LDRIVE LED_DRIVE_100MA -#define DEFAULT_PGAIN PGAIN_4X -#define DEFAULT_AGAIN AGAIN_4X -#define DEFAULT_PILT 0 -#define DEFAULT_PIHT 50 -#define DEFAULT_AILT 0xFFFF -#define DEFAULT_AIHT 0 -#define DEFAULT_PERS 0x11 -#define DEFAULT_CONFIG2 0x01 -#define DEFAULT_CONFIG3 0 -#define DEFAULT_GPENTH 40 -#define DEFAULT_GEXTH 30 -#define DEFAULT_GCONF1 0x40 -#define DEFAULT_GGAIN GGAIN_4X -#define DEFAULT_GLDRIVE LED_DRIVE_100MA -#define DEFAULT_GWTIME GWTIME_2_8MS -#define DEFAULT_GOFFSET 0 -#define DEFAULT_GPULSE 0xC9 -#define DEFAULT_GCONF3 0 -#define DEFAULT_GIEN 0 - -#define APDS9960_ERROR 0xFF - - -enum { - DIR_NONE, - DIR_LEFT, - DIR_RIGHT, - DIR_UP, - DIR_DOWN, - DIR_ALL -}; - - -enum { - APDS9960_NA_STATE, - APDS9960_ALL_STATE -}; - - -typedef struct gesture_data_type { - uint8_t u_data[32]; - uint8_t d_data[32]; - uint8_t l_data[32]; - uint8_t r_data[32]; - uint8_t index; - uint8_t total_gestures; - uint8_t in_threshold; - uint8_t out_threshold; -} gesture_data_type; - - - gesture_data_type gesture_data_; - int16_t gesture_ud_delta_ = 0; - int16_t gesture_lr_delta_ = 0; - int16_t gesture_ud_count_ = 0; - int16_t gesture_lr_count_ = 0; - int16_t gesture_state_ = 0; - int16_t gesture_motion_ = DIR_NONE; - - typedef struct color_data_type { - uint16_t a; - uint16_t r; - uint16_t g; - uint16_t b; - uint8_t p; - uint16_t cct; - uint16_t lux; - } color_data_type; - - color_data_type color_data; - uint8_t APDS9960_aTime = DEFAULT_ATIME; -# 307 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - bool wireWriteByte(uint8_t val) - { - Wire.beginTransmission(APDS9960_I2C_ADDR); - Wire.write(val); - if( Wire.endTransmission() != 0 ) { - return false; - } - - return true; - } -# 326 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -int8_t wireReadDataBlock( uint8_t reg, - uint8_t *val, - uint16_t len) -{ - unsigned char i = 0; - - - if (!wireWriteByte(reg)) { - return -1; - } - - - Wire.requestFrom(APDS9960_I2C_ADDR, len); - while (Wire.available()) { - if (i >= len) { - return -1; - } - val[i] = Wire.read(); - i++; - } - - return i; -} - - - - - - - -void calculateColorTemperature(void) -{ - float X, Y, Z; - float xc, yc; - float n; - float cct; - - - - - - X = (-0.14282F * color_data.r) + (1.54924F * color_data.g) + (-0.95641F * color_data.b); - Y = (-0.32466F * color_data.r) + (1.57837F * color_data.g) + (-0.73191F * color_data.b); - Z = (-0.68202F * color_data.r) + (0.77073F * color_data.g) + ( 0.56332F * color_data.b); - - - xc = (X) / (X + Y + Z); - yc = (Y) / (X + Y + Z); - - - n = (xc - 0.3320F) / (0.1858F - yc); - - - color_data.cct = (449.0F * FastPrecisePowf(n, 3)) + (3525.0F * FastPrecisePowf(n, 2)) + (6823.3F * n) + 5520.33F; - - return; -} -# 393 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getProxIntLowThresh(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PILT) ; - return val; - } - - - - - - - void setProxIntLowThresh(uint8_t threshold) - { - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PILT, threshold); - } - - - - - - - uint8_t getProxIntHighThresh(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PIHT) ; - return val; - } - - - - - - - - void setProxIntHighThresh(uint8_t threshold) - { - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PIHT, threshold); - } -# 449 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getLEDDrive(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL) ; - - val = (val >> 6) & 0b00000011; - - return val; - } -# 472 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setLEDDrive(uint8_t drive) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL); - - - drive &= 0b00000011; - drive = drive << 6; - val &= 0b00111111; - val |= drive; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONTROL, val); - } -# 501 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getProximityGain(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL) ; - - val = (val >> 2) & 0b00000011; - - return val; - } -# 524 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setProximityGain(uint8_t drive) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL); - - - drive &= 0b00000011; - drive = drive << 2; - val &= 0b11110011; - val |= drive; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONTROL, val); - } -# 565 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setAmbientLightGain(uint8_t drive) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONTROL); - - - drive &= 0b00000011; - val &= 0b11111100; - val |= drive; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONTROL, val); - } -# 592 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getLEDBoost(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG2) ; - - - val = (val >> 4) & 0b00000011; - - return val; - } -# 616 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setLEDBoost(uint8_t boost) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG2) ; - - boost &= 0b00000011; - boost = boost << 4; - val &= 0b11001111; - val |= boost; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG2, val) ; - } - - - - - - - uint8_t getProxGainCompEnable(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ; - - - val = (val >> 5) & 0b00000001; - - return val; - } - - - - - - - void setProxGainCompEnable(uint8_t enable) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ; - - - enable &= 0b00000001; - enable = enable << 5; - val &= 0b11011111; - val |= enable; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG3, val) ; - } -# 684 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getProxPhotoMask(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ; - - - val &= 0b00001111; - - return val; - } -# 709 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setProxPhotoMask(uint8_t mask) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_CONFIG3) ; - - - mask &= 0b00001111; - val &= 0b11110000; - val |= mask; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG3, val) ; - } - - - - - - - uint8_t getGestureEnterThresh(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GPENTH) ; - - return val; - } - - - - - - - void setGestureEnterThresh(uint8_t threshold) - { - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GPENTH, threshold) ; - - } - - - - - - - uint8_t getGestureExitThresh(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GEXTH) ; - - return val; - } - - - - - - - void setGestureExitThresh(uint8_t threshold) - { - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GEXTH, threshold) ; - } -# 787 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getGestureGain(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ; - - - val = (val >> 5) & 0b00000011; - - return val; - } -# 811 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setGestureGain(uint8_t gain) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ; - - - gain &= 0b00000011; - gain = gain << 5; - val &= 0b10011111; - val |= gain; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF2, val) ; - } -# 839 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getGestureLEDDrive(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ; - - - val = (val >> 3) & 0b00000011; - - return val; - } -# 863 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setGestureLEDDrive(uint8_t drive) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ; - - - drive &= 0b00000011; - drive = drive << 3; - val &= 0b11100111; - val |= drive; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF2, val) ; - } -# 895 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - uint8_t getGestureWaitTime(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ; - - - val &= 0b00000111; - - return val; - } -# 923 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void setGestureWaitTime(uint8_t time) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF2) ; - - - time &= 0b00000111; - val &= 0b11111000; - val |= time; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF2, val) ; - } - - - - - - - void getLightIntLowThreshold(uint16_t &threshold) - { - uint8_t val_byte; - threshold = 0; - - - val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_AILTL) ; - threshold = val_byte; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AILTH, val_byte) ; - threshold = threshold + ((uint16_t)val_byte << 8); - } - - - - - - - - void setLightIntLowThreshold(uint16_t threshold) - { - uint8_t val_low; - uint8_t val_high; - - - val_low = threshold & 0x00FF; - val_high = (threshold & 0xFF00) >> 8; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AILTL, val_low) ; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AILTH, val_high) ; - - } - - - - - - - - void getLightIntHighThreshold(uint16_t &threshold) - { - uint8_t val_byte; - threshold = 0; - - - val_byte = I2cRead8(APDS9960_I2C_ADDR, APDS9960_AIHTL); - threshold = val_byte; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AIHTH, val_byte) ; - threshold = threshold + ((uint16_t)val_byte << 8); - } - - - - - - - void setLightIntHighThreshold(uint16_t threshold) - { - uint8_t val_low; - uint8_t val_high; - - - val_low = threshold & 0x00FF; - val_high = (threshold & 0xFF00) >> 8; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AIHTL, val_low); - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_AIHTH, val_high) ; - } - - - - - - - - void getProximityIntLowThreshold(uint8_t &threshold) - { - threshold = 0; - - - threshold = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PILT); - - } - - - - - - - void setProximityIntLowThreshold(uint8_t threshold) - { - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PILT, threshold) ; - } -# 1056 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" - void getProximityIntHighThreshold(uint8_t &threshold) - { - threshold = 0; - - - threshold = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PIHT) ; - - } - - - - - - - void setProximityIntHighThreshold(uint8_t threshold) - { - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PIHT, threshold) ; - } - - - - - - - uint8_t getAmbientLightIntEnable(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ; - - - val = (val >> 4) & 0b00000001; - - return val; - } - - - - - - - void setAmbientLightIntEnable(uint8_t enable) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE); - - - enable &= 0b00000001; - enable = enable << 4; - val &= 0b11101111; - val |= enable; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ENABLE, val) ; - } - - - - - - - uint8_t getProximityIntEnable(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ; - - - val = (val >> 5) & 0b00000001; - - return val; - } - - - - - - - void setProximityIntEnable(uint8_t enable) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ; - - - enable &= 0b00000001; - enable = enable << 5; - val &= 0b11011111; - val |= enable; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ENABLE, val) ; - } - - - - - - - uint8_t getGestureIntEnable(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ; - - - val = (val >> 1) & 0b00000001; - - return val; - } - - - - - - - void setGestureIntEnable(uint8_t enable) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ; - - - enable &= 0b00000001; - enable = enable << 1; - val &= 0b11111101; - val |= enable; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF4, val) ; - } - - - - - - void clearAmbientLightInt(void) - { - uint8_t throwaway; - throwaway = I2cRead8(APDS9960_I2C_ADDR, APDS9960_AICLEAR); - } - - - - - - void clearProximityInt(void) - { - uint8_t throwaway; - throwaway = I2cRead8(APDS9960_I2C_ADDR, APDS9960_PICLEAR) ; - - } - - - - - - - uint8_t getGestureMode(void) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ; - - - val &= 0b00000001; - - return val; - } - - - - - - - void setGestureMode(uint8_t mode) - { - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GCONF4) ; - - - mode &= 0b00000001; - val &= 0b11111110; - val |= mode; - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF4, val) ; - } - - -bool APDS9960_init(void) -{ - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, DEFAULT_ATIME) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_WTIME, DEFAULT_WTIME) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PPULSE, DEFAULT_PROX_PPULSE) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_POFFSET_UR, DEFAULT_POFFSET_UR) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_POFFSET_DL, DEFAULT_POFFSET_DL) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG1, DEFAULT_CONFIG1) ; - - setLEDDrive(DEFAULT_LDRIVE); - - setProximityGain(DEFAULT_PGAIN); - - setAmbientLightGain(DEFAULT_AGAIN); - - setProxIntLowThresh(DEFAULT_PILT) ; - - setProxIntHighThresh(DEFAULT_PIHT); - - setLightIntLowThreshold(DEFAULT_AILT) ; - - setLightIntHighThreshold(DEFAULT_AIHT) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PERS, DEFAULT_PERS) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG2, DEFAULT_CONFIG2) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_CONFIG3, DEFAULT_CONFIG3) ; - - - setGestureEnterThresh(DEFAULT_GPENTH); - - setGestureExitThresh(DEFAULT_GEXTH) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF1, DEFAULT_GCONF1) ; - - setGestureGain(DEFAULT_GGAIN) ; - - setGestureLEDDrive(DEFAULT_GLDRIVE) ; - - setGestureWaitTime(DEFAULT_GWTIME) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_U, DEFAULT_GOFFSET) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_D, DEFAULT_GOFFSET) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_L, DEFAULT_GOFFSET) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GOFFSET_R, DEFAULT_GOFFSET) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GPULSE, DEFAULT_GPULSE) ; - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_GCONF3, DEFAULT_GCONF3) ; - - setGestureIntEnable(DEFAULT_GIEN); - - disablePower(); - - return true; -} -# 1334 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -uint8_t getMode(void) -{ - uint8_t enable_value; - - - enable_value = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ENABLE) ; - - return enable_value; -} - - - - - - - -void setMode(uint8_t mode, uint8_t enable) -{ - uint8_t reg_val; - - - reg_val = getMode(); - - - - enable = enable & 0x01; - if( mode >= 0 && mode <= 6 ) { - if (enable) { - reg_val |= (1 << mode); - } else { - reg_val &= ~(1 << mode); - } - } else if( mode == ALL ) { - if (enable) { - reg_val = 0x7F; - } else { - reg_val = 0x00; - } - } - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ENABLE, reg_val) ; -} - - - - - - -void enableLightSensor(void) -{ - - setAmbientLightGain(DEFAULT_AGAIN); - setAmbientLightIntEnable(0); - enablePower() ; - setMode(AMBIENT_LIGHT, 1) ; -} - - - - - -void disableLightSensor(void) -{ - setAmbientLightIntEnable(0) ; - setMode(AMBIENT_LIGHT, 0) ; -} - - - - - - -void enableProximitySensor(void) -{ - - setProximityGain(DEFAULT_PGAIN); - setLEDDrive(DEFAULT_LDRIVE) ; - setProximityIntEnable(0) ; - enablePower(); - setMode(PROXIMITY, 1) ; -} - - - - - -void disableProximitySensor(void) -{ - setProximityIntEnable(0) ; - setMode(PROXIMITY, 0) ; -} - - - - - - -void enableGestureSensor(void) -{ - - - - - - - - resetGestureParameters(); - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_WTIME, 0xFF) ; - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ; - setLEDBoost(LED_BOOST_100); - setGestureIntEnable(0) ; - setGestureMode(1); - enablePower() ; - setMode(WAIT, 1) ; - setMode(PROXIMITY, 1) ; - setMode(GESTURE, 1); -} - - - - - -void disableGestureSensor(void) -{ - resetGestureParameters(); - setGestureIntEnable(0) ; - setGestureMode(0) ; - setMode(GESTURE, 0) ; -} - - - - - - -bool isGestureAvailable(void) -{ - uint8_t val; - - - val = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GSTATUS) ; - - - val &= APDS9960_GVALID; - - - if( val == 1) { - return true; - } else { - return false; - } -} - - - - - - -int16_t readGesture(void) -{ - uint8_t fifo_level = 0; - uint8_t bytes_read = 0; - uint8_t fifo_data[128]; - uint8_t gstatus; - uint16_t motion; - uint16_t i; - uint8_t gesture_loop_counter = 0; - - - if( !isGestureAvailable() || !(getMode() & 0b01000001) ) { - return DIR_NONE; - } - - - while(1) { - if (gesture_loop_counter == APDS9960_MAX_GESTURE_CYCLES){ - disableGestureSensor(); - APDS9960_overload = true; - AddLog_P(LOG_LEVEL_DEBUG, PSTR("Sensor overload")); - } - gesture_loop_counter += 1; - - delay(FIFO_PAUSE_TIME); - - - gstatus = I2cRead8(APDS9960_I2C_ADDR, APDS9960_GSTATUS); - - - if( (gstatus & APDS9960_GVALID) == APDS9960_GVALID ) { - - - fifo_level = I2cRead8(APDS9960_I2C_ADDR,APDS9960_GFLVL) ; - - - if( fifo_level > 0) { - bytes_read = wireReadDataBlock( APDS9960_GFIFO_U, - (uint8_t*)fifo_data, - (fifo_level * 4) ); - if( bytes_read == -1 ) { - return APDS9960_ERROR; - } - - - if( bytes_read >= 4 ) { - for( i = 0; i < bytes_read; i += 4 ) { - gesture_data_.u_data[gesture_data_.index] = \ - fifo_data[i + 0]; - gesture_data_.d_data[gesture_data_.index] = \ - fifo_data[i + 1]; - gesture_data_.l_data[gesture_data_.index] = \ - fifo_data[i + 2]; - gesture_data_.r_data[gesture_data_.index] = \ - fifo_data[i + 3]; - gesture_data_.index++; - gesture_data_.total_gestures++; - } - - if( processGestureData() ) { - if( decodeGesture() ) { - - } - } - - gesture_data_.index = 0; - gesture_data_.total_gestures = 0; - } - } - } else { - - - delay(FIFO_PAUSE_TIME); - decodeGesture(); - motion = gesture_motion_; - resetGestureParameters(); - return motion; - } - } -} - - - - - -void enablePower(void) -{ - setMode(POWER, 1) ; -} - - - - - -void disablePower(void) -{ - setMode(POWER, 0) ; -} -# 1601 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -void readAllColorAndProximityData(void) -{ - if (I2cReadBuffer(APDS9960_I2C_ADDR, APDS9960_CDATAL, (uint8_t *) &color_data, (uint16_t)9)) - { - - - } -} -# 1617 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -void resetGestureParameters(void) -{ - gesture_data_.index = 0; - gesture_data_.total_gestures = 0; - - gesture_ud_delta_ = 0; - gesture_lr_delta_ = 0; - - gesture_ud_count_ = 0; - gesture_lr_count_ = 0; - - gesture_state_ = 0; - gesture_motion_ = DIR_NONE; -} - - - - - - -bool processGestureData(void) -{ - uint8_t u_first = 0; - uint8_t d_first = 0; - uint8_t l_first = 0; - uint8_t r_first = 0; - uint8_t u_last = 0; - uint8_t d_last = 0; - uint8_t l_last = 0; - uint8_t r_last = 0; - uint16_t ud_ratio_first; - uint16_t lr_ratio_first; - uint16_t ud_ratio_last; - uint16_t lr_ratio_last; - uint16_t ud_delta; - uint16_t lr_delta; - uint16_t i; - - - if( gesture_data_.total_gestures <= 4 ) { - return false; - } - - - if( (gesture_data_.total_gestures <= 32) && \ - (gesture_data_.total_gestures > 0) ) { - - - for( i = 0; i < gesture_data_.total_gestures; i++ ) { - if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) && - (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) && - (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) && - (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) { - - u_first = gesture_data_.u_data[i]; - d_first = gesture_data_.d_data[i]; - l_first = gesture_data_.l_data[i]; - r_first = gesture_data_.r_data[i]; - break; - } - } - - - if( (u_first == 0) || (d_first == 0) || \ - (l_first == 0) || (r_first == 0) ) { - - return false; - } - - for( i = gesture_data_.total_gestures - 1; i >= 0; i-- ) { - - if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) && - (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) && - (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) && - (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) { - - u_last = gesture_data_.u_data[i]; - d_last = gesture_data_.d_data[i]; - l_last = gesture_data_.l_data[i]; - r_last = gesture_data_.r_data[i]; - break; - } - } - } - - - ud_ratio_first = ((u_first - d_first) * 100) / (u_first + d_first); - lr_ratio_first = ((l_first - r_first) * 100) / (l_first + r_first); - ud_ratio_last = ((u_last - d_last) * 100) / (u_last + d_last); - lr_ratio_last = ((l_last - r_last) * 100) / (l_last + r_last); - - - ud_delta = ud_ratio_last - ud_ratio_first; - lr_delta = lr_ratio_last - lr_ratio_first; - - - gesture_ud_delta_ += ud_delta; - gesture_lr_delta_ += lr_delta; - - - if( gesture_ud_delta_ >= GESTURE_SENSITIVITY_1 ) { - gesture_ud_count_ = 1; - } else if( gesture_ud_delta_ <= -GESTURE_SENSITIVITY_1 ) { - gesture_ud_count_ = -1; - } else { - gesture_ud_count_ = 0; - } - - - if( gesture_lr_delta_ >= GESTURE_SENSITIVITY_1 ) { - gesture_lr_count_ = 1; - } else if( gesture_lr_delta_ <= -GESTURE_SENSITIVITY_1 ) { - gesture_lr_count_ = -1; - } else { - gesture_lr_count_ = 0; - } - return false; -} - - - - - - -bool decodeGesture(void) -{ - - - if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 0) ) { - gesture_motion_ = DIR_UP; - } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 0) ) { - gesture_motion_ = DIR_DOWN; - } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 1) ) { - gesture_motion_ = DIR_RIGHT; - } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == -1) ) { - gesture_motion_ = DIR_LEFT; - } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 1) ) { - if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { - gesture_motion_ = DIR_UP; - } else { - gesture_motion_ = DIR_RIGHT; - } - } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == -1) ) { - if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { - gesture_motion_ = DIR_DOWN; - } else { - gesture_motion_ = DIR_LEFT; - } - } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == -1) ) { - if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { - gesture_motion_ = DIR_UP; - } else { - gesture_motion_ = DIR_LEFT; - } - } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 1) ) { - if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { - gesture_motion_ = DIR_DOWN; - } else { - gesture_motion_ = DIR_RIGHT; - } - } else { - return false; - } - - return true; -} - -void handleGesture(void) { - if (isGestureAvailable() ) { - switch (readGesture()) { - case DIR_UP: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("UP")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Up")); - break; - case DIR_DOWN: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("DOWN")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Down")); - break; - case DIR_LEFT: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("LEFT")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left")); - break; - case DIR_RIGHT: - AddLog_P(LOG_LEVEL_DEBUG, PSTR("RIGHT")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right")); - break; - default: - if(APDS9960_overload) - { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("LONG")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Long")); - } - else{ - AddLog_P(LOG_LEVEL_DEBUG, PSTR("NONE")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("None")); - } - } - MqttPublishSensor(); - } -} - -void APDS9960_adjustATime(void) -{ - - I2cValidRead16LE(&color_data.a, APDS9960_I2C_ADDR, APDS9960_CDATAL); - - - if (color_data.a < (uint16_t)20){ - APDS9960_aTime = 0x40; - } - else if (color_data.a < (uint16_t)40){ - APDS9960_aTime = 0x80; - } - else if (color_data.a < (uint16_t)50){ - APDS9960_aTime = DEFAULT_ATIME; - } - else if (color_data.a < (uint16_t)70){ - APDS9960_aTime = 0xc0; - } - if (color_data.a < 200){ - APDS9960_aTime = 0xe9; - } - - - - else{ - APDS9960_aTime = 0xff; - } - - - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, APDS9960_aTime); - enablePower(); - enableLightSensor(); - delay(20); -} - - -void APDS9960_loop(void) -{ - if (recovery_loop_counter > 0){ - recovery_loop_counter -= 1; - } - if (recovery_loop_counter == 1 && APDS9960_overload){ - enableGestureSensor(); - APDS9960_overload = false; - Response_P(PSTR("{\"Gesture\":\"On\"}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data); - gesture_mode = 1; - } - - if (gesture_mode) { - if (recovery_loop_counter == 0){ - handleGesture(); - - if (APDS9960_overload) - { - disableGestureSensor(); - recovery_loop_counter = APDS9960_LONG_RECOVERY; - Response_P(PSTR("{\"Gesture\":\"Off\"}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data); - gesture_mode = 0; - } - } - } -} - -void APDS9960_detect(void) -{ - if (APDS9960type || I2cActive(APDS9960_I2C_ADDR)) { return; } - - APDS9960type = I2cRead8(APDS9960_I2C_ADDR, APDS9960_ID); - if (APDS9960type == APDS9960_CHIPID_1 || APDS9960type == APDS9960_CHIPID_2 || APDS9960type == APDS9960_CHIPID_3) { - if (APDS9960_init()) { - I2cSetActiveFound(APDS9960_I2C_ADDR, APDS9960stype); - - enableProximitySensor(); - enableGestureSensor(); - } else { - APDS9960type = 0; - } - } else { - APDS9960type = 0; - } - currentGesture[0] = '\0'; -} - - - - - -void APDS9960_show(bool json) -{ - if (!APDS9960type) { return; } - - if (!gesture_mode && !APDS9960_overload) { - char red_chr[10]; - char green_chr[10]; - char blue_chr[10]; - char ambient_chr[10]; - char cct_chr[10]; - char prox_chr[10]; - - readAllColorAndProximityData(); - - sprintf (ambient_chr, "%u", color_data.a/4); - sprintf (red_chr, "%u", color_data.r); - sprintf (green_chr, "%u", color_data.g); - sprintf (blue_chr, "%u", color_data.b ); - sprintf (prox_chr, "%u", color_data.p ); - - - - - - calculateColorTemperature(); - sprintf (cct_chr, "%u", color_data.cct); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"Red\":%s,\"Green\":%s,\"Blue\":%s,\"Ambient\":%s,\"CCT\":%s,\"Proximity\":%s}"), - APDS9960stype, red_chr, green_chr, blue_chr, ambient_chr, cct_chr, prox_chr); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_APDS_9960_SNS, red_chr, green_chr, blue_chr, ambient_chr, cct_chr, prox_chr ); -#endif - } - } - else { - if (json && (currentGesture[0] != '\0' )) { - ResponseAppend_P(PSTR(",\"%s\":{\"%s\":1}"), APDS9960stype, currentGesture); - currentGesture[0] = '\0'; - } - } -} -# 1962 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_27_apds9960.ino" -bool APDS9960CommandSensor(void) -{ - bool serviced = true; - - switch (XdrvMailbox.payload) { - case 0: - disableGestureSensor(); - gesture_mode = 0; - enableLightSensor(); - APDS9960_overload = false; - break; - case 1: - if (APDS9960type) { - setGestureGain(DEFAULT_GGAIN); - setProximityGain(DEFAULT_PGAIN); - disableLightSensor(); - enableGestureSensor(); - gesture_mode = 1; - } - break; - case 2: - if (APDS9960type) { - setGestureGain(GGAIN_2X); - setProximityGain(PGAIN_2X); - disableLightSensor(); - enableGestureSensor(); - gesture_mode = 1; - } - break; - default: - int temp_aTime = (uint8_t)XdrvMailbox.payload; - if (temp_aTime > 2 && temp_aTime < 256){ - disablePower(); - I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, temp_aTime); - enablePower(); - enableLightSensor(); - } - break; - } - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_27, GetStateText(gesture_mode)); - - return serviced; -} - - - - - -bool Xsns27(uint8_t function) -{ - if (!I2cEnabled(XI2C_21)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - APDS9960_detect(); - } - else if (APDS9960type) { - switch (function) { - case FUNC_EVERY_50_MSECOND: - APDS9960_loop(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_27 == XdrvMailbox.index) { - result = APDS9960CommandSensor(); - } - break; - case FUNC_JSON_APPEND: - APDS9960_show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - APDS9960_show(0); - break; -#endif - } - } - return result; -} -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_28_tm1638.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_28_tm1638.ino" -#ifdef USE_TM1638 - - - - - - -#define XSNS_28 28 - -#define TM1638_COLOR_NONE 0 -#define TM1638_COLOR_RED 1 -#define TM1638_COLOR_GREEN 2 - -#define TM1638_CLOCK_DELAY 1 - -uint8_t tm1638_type = 1; -uint8_t tm1638_clock_pin = 0; -uint8_t tm1638_data_pin = 0; -uint8_t tm1638_strobe_pin = 0; -uint8_t tm1638_displays = 8; -uint8_t tm1638_active_display = 1; -uint8_t tm1638_intensity = 0; -uint8_t tm1638_state = 0; - - - - - - -void Tm16XXSend(uint8_t data) -{ - for (uint32_t i = 0; i < 8; i++) { - digitalWrite(tm1638_data_pin, !!(data & (1 << i))); - digitalWrite(tm1638_clock_pin, LOW); - delayMicroseconds(TM1638_CLOCK_DELAY); - digitalWrite(tm1638_clock_pin, HIGH); - } -} - -void Tm16XXSendCommand(uint8_t cmd) -{ - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(cmd); - digitalWrite(tm1638_strobe_pin, HIGH); -} - -void TM16XXSendData(uint8_t address, uint8_t data) -{ - Tm16XXSendCommand(0x44); - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0xC0 | address); - Tm16XXSend(data); - digitalWrite(tm1638_strobe_pin, HIGH); -} - -uint8_t Tm16XXReceive(void) -{ - uint8_t temp = 0; - - - pinMode(tm1638_data_pin, INPUT); - digitalWrite(tm1638_data_pin, HIGH); - - for (uint32_t i = 0; i < 8; ++i) { - digitalWrite(tm1638_clock_pin, LOW); - delayMicroseconds(TM1638_CLOCK_DELAY); - temp |= digitalRead(tm1638_data_pin) << i; - digitalWrite(tm1638_clock_pin, HIGH); - } - - - pinMode(tm1638_data_pin, OUTPUT); - digitalWrite(tm1638_data_pin, LOW); - - return temp; -} - - - -void Tm16XXClearDisplay(void) -{ - for (uint32_t i = 0; i < tm1638_displays; i++) { - TM16XXSendData(i << 1, 0); - } -} - -void Tm1638SetLED(uint8_t color, uint8_t pos) -{ - TM16XXSendData((pos << 1) + 1, color); -} - -void Tm1638SetLEDs(word leds) -{ - for (uint32_t i = 0; i < tm1638_displays; i++) { - uint8_t color = 0; - - if ((leds & (1 << i)) != 0) { - color |= TM1638_COLOR_RED; - } - - if ((leds & (1 << (i + 8))) != 0) { - color |= TM1638_COLOR_GREEN; - } - - Tm1638SetLED(color, i); - } -} - -uint8_t Tm1638GetButtons(void) -{ - uint8_t keys = 0; - - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0x42); - for (uint32_t i = 0; i < 4; i++) { - keys |= Tm16XXReceive() << i; - } - digitalWrite(tm1638_strobe_pin, HIGH); - - return keys; -} - - - -void TmInit(void) -{ - tm1638_type = 0; - if ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99)) { - tm1638_clock_pin = pin[GPIO_TM16CLK]; - tm1638_data_pin = pin[GPIO_TM16DIO]; - tm1638_strobe_pin = pin[GPIO_TM16STB]; - - pinMode(tm1638_data_pin, OUTPUT); - pinMode(tm1638_clock_pin, OUTPUT); - pinMode(tm1638_strobe_pin, OUTPUT); - - digitalWrite(tm1638_strobe_pin, HIGH); - digitalWrite(tm1638_clock_pin, HIGH); - - Tm16XXSendCommand(0x40); - Tm16XXSendCommand(0x80 | (tm1638_active_display ? 8 : 0) | tmin(7, tm1638_intensity)); - - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0xC0); - for (uint32_t i = 0; i < 16; i++) { - Tm16XXSend(0x00); - } - digitalWrite(tm1638_strobe_pin, HIGH); - - tm1638_type = 1; - tm1638_state = 1; - } -} - -void TmLoop(void) -{ - if (tm1638_state) { - uint8_t buttons = Tm1638GetButtons(); - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - SwitchSetVirtual(i, (buttons &1) ^1); - uint8_t color = (SwitchGetVirtual(i)) ? TM1638_COLOR_NONE : TM1638_COLOR_RED; - Tm1638SetLED(color, i); - buttons >>= 1; - } - SwitchHandler(1); - } -} -# 201 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_28_tm1638.ino" -bool Xsns28(uint8_t function) -{ - bool result = false; - - if (tm1638_type) { - switch (function) { - case FUNC_INIT: - TmInit(); - break; - case FUNC_EVERY_50_MSECOND: - TmLoop(); - break; -# 223 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_28_tm1638.ino" - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_29_mcp230xx.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_29_mcp230xx.ino" -#ifdef USE_I2C -#ifdef USE_MCP230xx -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_29_mcp230xx.ino" -#define XSNS_29 29 -#define XI2C_22 22 - - - - - -uint8_t MCP230xx_IODIR = 0x00; -uint8_t MCP230xx_GPINTEN = 0x02; -uint8_t MCP230xx_IOCON = 0x05; -uint8_t MCP230xx_GPPU = 0x06; -uint8_t MCP230xx_INTF = 0x07; -uint8_t MCP230xx_INTCAP = 0x08; -uint8_t MCP230xx_GPIO = 0x09; - -uint8_t mcp230xx_type = 0; -uint8_t mcp230xx_pincount = 0; -uint8_t mcp230xx_int_en = 0; -uint8_t mcp230xx_int_prio_counter = 0; -uint8_t mcp230xx_int_counter_en = 0; -uint8_t mcp230xx_int_retainer_en = 0; -uint8_t mcp230xx_int_sec_counter = 0; - -uint8_t mcp230xx_int_report_defer_counter[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -uint16_t mcp230xx_int_counter[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -uint8_t mcp230xx_int_retainer[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -unsigned long int_millis[16]; - -const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29_D%i\":{\"MODE\":%i,\"PULL_UP\":\"%s\",\"INT_MODE\":\"%s\",\"STATE\":\"%s\"}}"; - -const char MCP230XX_INTCFG_RESPONSE[] PROGMEM = "{\"MCP230xx_INT%s\":{\"D_%i\":%i}}"; - -#ifdef USE_MCP230xx_OUTPUT -const char MCP230XX_CMND_RESPONSE[] PROGMEM = "{\"S29cmnd_D%i\":{\"COMMAND\":\"%s\",\"STATE\":\"%s\"}}"; -#endif - -void MCP230xx_CheckForIntCounter(void) { - uint8_t en = 0; - for (uint32_t ca=0;ca<16;ca++) { - if (Settings.mcp230xx_config[ca].int_count_en) { - en=1; - } - } - if (!Settings.mcp230xx_int_timer) en=0; - mcp230xx_int_counter_en=en; - if (!mcp230xx_int_counter_en) { - for (uint32_t ca=0;ca<16;ca++) { - mcp230xx_int_counter[ca] = 0; - } - } -} - -void MCP230xx_CheckForIntRetainer(void) { - uint8_t en = 0; - for (uint32_t ca=0;ca<16;ca++) { - if (Settings.mcp230xx_config[ca].int_retain_flag) { - en=1; - } - } - mcp230xx_int_retainer_en=en; - if (!mcp230xx_int_retainer_en) { - for (uint32_t ca=0;ca<16;ca++) { - mcp230xx_int_retainer[ca] = 0; - } - } -} - -const char* ConvertNumTxt(uint8_t statu, uint8_t pinmod=0) { -#ifdef USE_MCP230xx_OUTPUT -if ((6 == pinmod) && (statu < 2)) { statu = abs(statu-1); } -#endif - switch (statu) { - case 0: - return "OFF"; - break; - case 1: - return "ON"; - break; -#ifdef USE_MCP230xx_OUTPUT - case 2: - return "TOGGLE"; - break; -#endif - } - return ""; -} - -const char* IntModeTxt(uint8_t intmo) { - switch (intmo) { - case 0: - return "ALL"; - break; - case 1: - return "EVENT"; - break; - case 2: - return "TELE"; - break; - case 3: - return "DISABLED"; - break; - } - return ""; -} - -uint8_t MCP230xx_readGPIO(uint8_t port) { - return I2cRead8(USE_MCP230xx_ADDR, MCP230xx_GPIO + port); -} - -void MCP230xx_ApplySettings(void) -{ - uint8_t int_en = 0; - for (uint32_t mcp230xx_port = 0; mcp230xx_port < mcp230xx_type; mcp230xx_port++) { - uint8_t reg_gppu = 0; - uint8_t reg_gpinten = 0; - uint8_t reg_iodir = 0xFF; -#ifdef USE_MCP230xx_OUTPUT - uint8_t reg_portpins = 0x00; -#endif - for (uint32_t idx = 0; idx < 8; idx++) { - switch (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pinmode) { - case 0 ... 1: - reg_iodir |= (1 << idx); - break; - case 2 ... 4: - reg_iodir |= (1 << idx); - reg_gpinten |= (1 << idx); - int_en = 1; - break; -#ifdef USE_MCP230xx_OUTPUT - case 5 ... 6: - reg_iodir &= ~(1 << idx); - if (Settings.flag.save_state) { - reg_portpins |= (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].saved_state << idx); - } else { - if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) { - reg_portpins |= (1 << idx); - } - } - break; -#endif - default: - break; - } -#ifdef USE_MCP230xx_OUTPUT - if ((Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) && (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pinmode < 5)) { - reg_gppu |= (1 << idx); - } -#else - if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) { - reg_gppu |= (1 << idx); - } -#endif - } - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPPU+mcp230xx_port, reg_gppu); - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPINTEN+mcp230xx_port, reg_gpinten); - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_IODIR+mcp230xx_port, reg_iodir); -#ifdef USE_MCP230xx_OUTPUT - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO+mcp230xx_port, reg_portpins); -#endif - } - for (uint32_t idx=0;idx 0) { - if (I2cValidRead8(&mcp230xx_intcap, USE_MCP230xx_ADDR, MCP230xx_INTCAP+mcp230xx_port)) { - for (uint32_t intp = 0; intp < 8; intp++) { - if ((intf >> intp) & 0x01) { - report_int = 0; - if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].pinmode > 1) { - switch (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].pinmode) { - case 2: - report_int = 1; - break; - case 3: - if (((mcp230xx_intcap >> intp) & 0x01) == 0) report_int = 1; - break; - case 4: - if (((mcp230xx_intcap >> intp) & 0x01) == 1) report_int = 1; - break; - default: - break; - } - - if ((mcp230xx_int_counter_en) && (report_int)) { - if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_count_en) { - mcp230xx_int_counter[intp+(mcp230xx_port*8)]++; - } - } - - if (report_int) { - if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_report_defer) { - mcp230xx_int_report_defer_counter[intp+(mcp230xx_port*8)]++; - if (mcp230xx_int_report_defer_counter[intp+(mcp230xx_port*8)] >= Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_report_defer) { - mcp230xx_int_report_defer_counter[intp+(mcp230xx_port*8)]=0; - } else { - report_int = 0; - } - } - } - - if (report_int) { - if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_retain_flag) { - mcp230xx_int_retainer[intp+(mcp230xx_port*8)] = 1; - report_int = 0; - } - } - if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_count_en) { - report_int = 0; - } - if (report_int) { - bool int_tele = false; - bool int_event = false; - unsigned long millis_now = millis(); - unsigned long millis_since_last_int = millis_now - int_millis[intp+(mcp230xx_port*8)]; - int_millis[intp+(mcp230xx_port*8)]=millis_now; - switch (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_report_mode) { - case 0: - int_tele=true; - int_event=true; - break; - case 1: - int_event=true; - break; - case 2: - int_tele=true; - break; - } - if (int_tele) { - ResponseTime_P(PSTR(",\"MCP230XX_INT\":{\"D%i\":%i,\"MS\":%lu}}"), - intp+(mcp230xx_port*8), ((mcp230xx_intcap >> intp) & 0x01),millis_since_last_int); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("MCP230XX_INT")); - } - if (int_event) { - char command[19]; - sprintf(command,"event MCPINT_D%i=%i",intp+(mcp230xx_port*8),((mcp230xx_intcap >> intp) & 0x01)); - ExecuteCommand(command, SRC_RULE); - } - } - } - } - } - } - } - } - } -} - -void MCP230xx_Show(bool json) -{ - if (json) { - uint8_t gpio = MCP230xx_readGPIO(0); - ResponseAppend_P(PSTR(",\"MCP230XX\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i"), - (gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); - if (2 == mcp230xx_type) { - gpio = MCP230xx_readGPIO(1); - ResponseAppend_P(PSTR(",\"D8\":%i,\"D9\":%i,\"D10\":%i,\"D11\":%i,\"D12\":%i,\"D13\":%i,\"D14\":%i,\"D15\":%i"), - (gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); - } - ResponseJsonEnd(); - } -} - -#ifdef USE_MCP230xx_OUTPUT - -void MCP230xx_SetOutPin(uint8_t pin,uint8_t pinstate) { - uint8_t portpins; - uint8_t port = 0; - uint8_t pinmo = Settings.mcp230xx_config[pin].pinmode; - uint8_t interlock = Settings.flag.interlock; - int pinadd = (pin % 2)+1-(3*(pin % 2)); - char cmnd[7], stt[4]; - if (pin > 7) { port = 1; } - portpins = MCP230xx_readGPIO(port); - if (interlock && (pinmo == Settings.mcp230xx_config[pin+pinadd].pinmode)) { - if (pinstate < 2) { - if (6 == pinmo) { - if (pinstate) portpins |= (1 << (pin-(port*8))); else portpins |= (1 << (pin+pinadd-(port*8))),portpins &= ~(1 << (pin-(port*8))); - } else { - if (pinstate) portpins &= ~(1 << (pin+pinadd-(port*8))),portpins |= (1 << (pin-(port*8))); else portpins &= ~(1 << (pin-(port*8))); - } - } else { - if (6 == pinmo) { - portpins |= (1 << (pin+pinadd-(port*8))),portpins ^= (1 << (pin-(port*8))); - } else { - portpins &= ~(1 << (pin+pinadd-(port*8))),portpins ^= (1 << (pin-(port*8))); - } - } - } else { - if (pinstate < 2) { - if (pinstate) portpins |= (1 << (pin-(port*8))); else portpins &= ~(1 << (pin-(port*8))); - } else { - portpins ^= (1 << (pin-(port*8))); - } - } - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO + port, portpins); - if (Settings.flag.save_state) { - Settings.mcp230xx_config[pin].saved_state=portpins>>(pin-(port*8))&1; - Settings.mcp230xx_config[pin+pinadd].saved_state=portpins>>(pin+pinadd-(port*8))&1; - } - sprintf(cmnd,ConvertNumTxt(pinstate, pinmo)); - sprintf(stt,ConvertNumTxt((portpins >> (pin-(port*8))&1), pinmo)); - if (interlock && (pinmo == Settings.mcp230xx_config[pin+pinadd].pinmode)) { - char stt1[4]; - sprintf(stt1,ConvertNumTxt((portpins >> (pin+pinadd-(port*8))&1), pinmo)); - Response_P(PSTR("{\"S29cmnd_D%i\":{\"COMMAND\":\"%s\",\"STATE\":\"%s\"},\"S29cmnd_D%i\":{\"STATE\":\"%s\"}}"),pin, cmnd, stt, pin+pinadd, stt1); - } else { - Response_P(MCP230XX_CMND_RESPONSE, pin, cmnd, stt); - } -} - -#endif - -void MCP230xx_Reset(uint8_t pinmode) { - uint8_t pullup = 0; - if ((pinmode > 1) && (pinmode < 5)) { pullup=1; } - for (uint32_t pinx=0;pinx<16;pinx++) { - Settings.mcp230xx_config[pinx].pinmode=pinmode; - Settings.mcp230xx_config[pinx].pullup=pullup; - Settings.mcp230xx_config[pinx].saved_state=0; - if ((pinmode > 1) && (pinmode < 5)) { - Settings.mcp230xx_config[pinx].int_report_mode=0; - } else { - Settings.mcp230xx_config[pinx].int_report_mode=3; - } - Settings.mcp230xx_config[pinx].int_report_defer=0; - Settings.mcp230xx_config[pinx].int_count_en=0; - Settings.mcp230xx_config[pinx].int_retain_flag=0; - Settings.mcp230xx_config[pinx].spare13=0; - Settings.mcp230xx_config[pinx].spare14=0; - Settings.mcp230xx_config[pinx].spare15=0; - } - Settings.mcp230xx_int_prio = 0; - Settings.mcp230xx_int_timer = 0; - MCP230xx_ApplySettings(); - char pulluptxt[7]; - char intmodetxt[9]; - sprintf(pulluptxt,ConvertNumTxt(pullup)); - uint8_t intmode = 3; - if ((pinmode > 1) && (pinmode < 5)) { intmode = 0; } - sprintf(intmodetxt,IntModeTxt(intmode)); - Response_P(MCP230XX_SENSOR_RESPONSE,99,pinmode,pulluptxt,intmodetxt,""); -} - -bool MCP230xx_Command(void) -{ - bool serviced = true; - bool validpin = false; - uint8_t paramcount = 0; - if (XdrvMailbox.data_len > 0) { - paramcount=1; - } else { - serviced = false; - return serviced; - } - char sub_string[XdrvMailbox.data_len]; - for (uint32_t ca=0;ca 1) { - uint8_t intpri = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if ((intpri >= 0) && (intpri <= 20)) { - Settings.mcp230xx_int_prio = intpri; - Response_P(MCP230XX_INTCFG_RESPONSE,"PRI",99,Settings.mcp230xx_int_prio); - return serviced; - } - } else { - Response_P(MCP230XX_INTCFG_RESPONSE,"PRI",99,Settings.mcp230xx_int_prio); - return serviced; - } - } - - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"INTTIMER")) { - if (paramcount > 1) { - uint8_t inttim = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if ((inttim >= 0) && (inttim <= 3600)) { - Settings.mcp230xx_int_timer = inttim; - MCP230xx_CheckForIntCounter(); - Response_P(MCP230XX_INTCFG_RESPONSE,"TIMER",99,Settings.mcp230xx_int_timer); - return serviced; - } - } else { - Response_P(MCP230XX_INTCFG_RESPONSE,"TIMER",99,Settings.mcp230xx_int_timer); - return serviced; - } - } - - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"INTDEF")) { - if (paramcount > 1) { - uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if (pin < mcp230xx_pincount) { - if (pin == 0) { - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0")) validpin=true; - } else { - validpin = true; - } - } - if (validpin) { - if (paramcount > 2) { - uint8_t intdef = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - if ((intdef >= 0) && (intdef <= 15)) { - Settings.mcp230xx_config[pin].int_report_defer=intdef; - if (Settings.mcp230xx_config[pin].int_count_en) { - Settings.mcp230xx_config[pin].int_count_en=0; - MCP230xx_CheckForIntCounter(); - AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - Disabled INTCNT for pin D%i"),pin); - } - Response_P(MCP230XX_INTCFG_RESPONSE,"DEF",pin,Settings.mcp230xx_config[pin].int_report_defer); - return serviced; - } else { - serviced=false; - return serviced; - } - } else { - Response_P(MCP230XX_INTCFG_RESPONSE,"DEF",pin,Settings.mcp230xx_config[pin].int_report_defer); - return serviced; - } - } - serviced = false; - return serviced; - } else { - serviced = false; - return serviced; - } - } - - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"INTCNT")) { - if (paramcount > 1) { - uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if (pin < mcp230xx_pincount) { - if (pin == 0) { - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0")) validpin=true; - } else { - validpin = true; - } - } - if (validpin) { - if (paramcount > 2) { - uint8_t intcnt = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - if ((intcnt >= 0) && (intcnt <= 1)) { - Settings.mcp230xx_config[pin].int_count_en=intcnt; - if (Settings.mcp230xx_config[pin].int_report_defer) { - Settings.mcp230xx_config[pin].int_report_defer=0; - AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - Disabled INTDEF for pin D%i"),pin); - } - if (Settings.mcp230xx_config[pin].int_report_mode < 3) { - Settings.mcp230xx_config[pin].int_report_mode=3; - AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - Disabled immediate interrupt/telemetry reporting for pin D%i"),pin); - } - if ((Settings.mcp230xx_config[pin].int_count_en) && (!Settings.mcp230xx_int_timer)) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("*** WARNING *** - INTCNT enabled for pin D%i but global INTTIMER is disabled!"),pin); - } - MCP230xx_CheckForIntCounter(); - Response_P(MCP230XX_INTCFG_RESPONSE,"CNT",pin,Settings.mcp230xx_config[pin].int_count_en); - return serviced; - } else { - serviced=false; - return serviced; - } - } else { - Response_P(MCP230XX_INTCFG_RESPONSE,"CNT",pin,Settings.mcp230xx_config[pin].int_count_en); - return serviced; - } - } - serviced = false; - return serviced; - } else { - serviced = false; - return serviced; - } - } - - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"INTRETAIN")) { - if (paramcount > 1) { - uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - if (pin < mcp230xx_pincount) { - if (pin == 0) { - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0")) validpin=true; - } else { - validpin = true; - } - } - if (validpin) { - if (paramcount > 2) { - uint8_t int_retain = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - if ((int_retain >= 0) && (int_retain <= 1)) { - Settings.mcp230xx_config[pin].int_retain_flag=int_retain; - Response_P(MCP230XX_INTCFG_RESPONSE,"INT_RETAIN",pin,Settings.mcp230xx_config[pin].int_retain_flag); - MCP230xx_CheckForIntRetainer(); - return serviced; - } else { - serviced=false; - return serviced; - } - } else { - Response_P(MCP230XX_INTCFG_RESPONSE,"INT_RETAIN",pin,Settings.mcp230xx_config[pin].int_retain_flag); - return serviced; - } - } - serviced = false; - return serviced; - } else { - serviced = false; - return serviced; - } - } - - uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); - - if (pin < mcp230xx_pincount) { - if (0 == pin) { - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1), "0")) validpin=true; - } else { - validpin=true; - } - } - if (validpin && (paramcount > 1)) { - if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "?")) { - uint8_t port = 0; - if (pin > 7) { port = 1; } - uint8_t portdata = MCP230xx_readGPIO(port); - char pulluptxtr[7],pinstatustxtr[7]; - char intmodetxt[9]; - sprintf(intmodetxt,IntModeTxt(Settings.mcp230xx_config[pin].int_report_mode)); - sprintf(pulluptxtr,ConvertNumTxt(Settings.mcp230xx_config[pin].pullup)); -#ifdef USE_MCP230xx_OUTPUT - uint8_t pinmod = Settings.mcp230xx_config[pin].pinmode; - sprintf(pinstatustxtr,ConvertNumTxt(portdata>>(pin-(port*8))&1,pinmod)); - Response_P(MCP230XX_SENSOR_RESPONSE,pin,pinmod,pulluptxtr,intmodetxt,pinstatustxtr); -#else - sprintf(pinstatustxtr,ConvertNumTxt(portdata>>(pin-(port*8))&1)); - Response_P(MCP230XX_SENSOR_RESPONSE,pin,Settings.mcp230xx_config[pin].pinmode,pulluptxtr,intmodetxt,pinstatustxtr); -#endif - return serviced; - } -#ifdef USE_MCP230xx_OUTPUT - if (Settings.mcp230xx_config[pin].pinmode >= 5) { - uint8_t pincmd = Settings.mcp230xx_config[pin].pinmode - 5; - if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "ON")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "1"))) { - MCP230xx_SetOutPin(pin,abs(pincmd-1)); - return serviced; - } - if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "OFF")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0"))) { - MCP230xx_SetOutPin(pin,pincmd); - return serviced; - } - if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "T")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "2"))) { - MCP230xx_SetOutPin(pin,2); - return serviced; - } - } -#endif - uint8_t pinmode = 0; - uint8_t pullup = 0; - uint8_t intmode = 0; - if (paramcount > 1) { - pinmode = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); - } - if (paramcount > 2) { - pullup = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); - } - if (paramcount > 3) { - intmode = atoi(subStr(sub_string, XdrvMailbox.data, ",", 4)); - } -#ifdef USE_MCP230xx_OUTPUT - if ((pin < mcp230xx_pincount) && (pinmode > 0) && (pinmode < 7) && (pullup < 2) && (paramcount > 2)) { -#else - if ((pin < mcp230xx_pincount) && (pinmode > 0) && (pinmode < 5) && (pullup < 2) && (paramcount > 2)) { -#endif - Settings.mcp230xx_config[pin].pinmode=pinmode; - Settings.mcp230xx_config[pin].pullup=pullup; - if ((pinmode > 1) && (pinmode < 5)) { - if ((intmode >= 0) && (intmode <= 3)) { - Settings.mcp230xx_config[pin].int_report_mode=intmode; - } - } else { - Settings.mcp230xx_config[pin].int_report_mode=3; - } - MCP230xx_ApplySettings(); - uint8_t port = 0; - if (pin > 7) { port = 1; } - uint8_t portdata = MCP230xx_readGPIO(port); - char pulluptxtc[7], pinstatustxtc[7]; - char intmodetxt[9]; - sprintf(pulluptxtc,ConvertNumTxt(pullup)); - sprintf(intmodetxt,IntModeTxt(Settings.mcp230xx_config[pin].int_report_mode)); -#ifdef USE_MCP230xx_OUTPUT - sprintf(pinstatustxtc,ConvertNumTxt(portdata>>(pin-(port*8))&1,Settings.mcp230xx_config[pin].pinmode)); -#else - sprintf(pinstatustxtc,ConvertNumTxt(portdata>>(pin-(port*8))&1)); -#endif - Response_P(MCP230XX_SENSOR_RESPONSE,pin,pinmode,pulluptxtc,intmodetxt,pinstatustxtc); - return serviced; - } - } else { - serviced=false; - return serviced; - } - return serviced; -} - -#ifdef USE_MCP230xx_DISPLAYOUTPUT - -const char HTTP_SNS_MCP230xx_OUTPUT[] PROGMEM = "{s}MCP230XX D%d{m}%s{e}"; - -void MCP230xx_UpdateWebData(void) -{ - uint8_t gpio1 = MCP230xx_readGPIO(0); - uint8_t gpio2 = 0; - if (2 == mcp230xx_type) { - gpio2 = MCP230xx_readGPIO(1); - } - uint16_t gpio = (gpio2 << 8) + gpio1; - for (uint32_t pin = 0; pin < mcp230xx_pincount; pin++) { - if (Settings.mcp230xx_config[pin].pinmode >= 5) { - char stt[7]; - sprintf(stt,ConvertNumTxt((gpio>>pin)&1,Settings.mcp230xx_config[pin].pinmode)); - WSContentSend_PD(HTTP_SNS_MCP230xx_OUTPUT, pin, stt); - } - } -} - -#endif - -#ifdef USE_MCP230xx_OUTPUT - -void MCP230xx_OutputTelemetry(void) -{ - uint8_t outputcount = 0; - uint16_t gpiototal = 0; - uint8_t gpioa = 0; - uint8_t gpiob = 0; - gpioa=MCP230xx_readGPIO(0); - if (2 == mcp230xx_type) { gpiob=MCP230xx_readGPIO(1); } - gpiototal=((uint16_t)gpiob << 8) | gpioa; - for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { - if (Settings.mcp230xx_config[pinx].pinmode >= 5) outputcount++; - } - if (outputcount) { - char stt[7]; - ResponseTime_P(PSTR(",\"MCP230_OUT\":{")); - for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { - if (Settings.mcp230xx_config[pinx].pinmode >= 5) { - sprintf(stt,ConvertNumTxt(((gpiototal>>pinx)&1),Settings.mcp230xx_config[pinx].pinmode)); - ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","),pinx,stt); - } - } - ResponseAppend_P(PSTR("\"END\":1}}")); - MqttPublishTeleSensor(); - } -} - -#endif - -void MCP230xx_Interrupt_Counter_Report(void) { - ResponseTime_P(PSTR(",\"MCP230_INTTIMER\":{")); - for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { - if (Settings.mcp230xx_config[pinx].int_count_en) { - ResponseAppend_P(PSTR("\"INTCNT_D%i\":%i,"),pinx,mcp230xx_int_counter[pinx]); - mcp230xx_int_counter[pinx]=0; - } - } - ResponseAppend_P(PSTR("\"END\":1}}")); - MqttPublishTeleSensor(); - mcp230xx_int_sec_counter = 0; -} - -void MCP230xx_Interrupt_Retain_Report(void) { - uint16_t retainresult = 0; - ResponseTime_P(PSTR(",\"MCP_INTRETAIN\":{")); - for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { - if (Settings.mcp230xx_config[pinx].int_retain_flag) { - ResponseAppend_P(PSTR("\"D%i\":%i,"),pinx,mcp230xx_int_retainer[pinx]); - retainresult |= (((mcp230xx_int_retainer[pinx])&1) << pinx); - mcp230xx_int_retainer[pinx]=0; - } - } - ResponseAppend_P(PSTR("\"Value\":%u}}"),retainresult); - MqttPublishTeleSensor(); -} - - - - - -bool Xsns29(uint8_t function) -{ - if (!I2cEnabled(XI2C_22)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - MCP230xx_Detect(); - } - else if (mcp230xx_type) { - switch (function) { - case FUNC_EVERY_50_MSECOND: - if (mcp230xx_int_en) { - mcp230xx_int_prio_counter++; - if ((mcp230xx_int_prio_counter) >= (Settings.mcp230xx_int_prio)) { - MCP230xx_CheckForInterrupt(); - mcp230xx_int_prio_counter=0; - } - } - break; - case FUNC_EVERY_SECOND: - if (mcp230xx_int_counter_en) { - mcp230xx_int_sec_counter++; - if (mcp230xx_int_sec_counter >= Settings.mcp230xx_int_timer) { - MCP230xx_Interrupt_Counter_Report(); - } - } - if (tele_period == 0) { - if (mcp230xx_int_retainer_en) { - MCP230xx_Interrupt_Retain_Report(); - } -#ifdef USE_MCP230xx_OUTPUT - MCP230xx_OutputTelemetry(); -#endif - } - break; - case FUNC_JSON_APPEND: - MCP230xx_Show(1); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_29 == XdrvMailbox.index) { - result = MCP230xx_Command(); - } - break; -#ifdef USE_WEBSERVER -#ifdef USE_MCP230xx_OUTPUT -#ifdef USE_MCP230xx_DISPLAYOUTPUT - case FUNC_WEB_SENSOR: - MCP230xx_UpdateWebData(); - break; -#endif -#endif -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_30_mpr121.ino" -# 46 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_30_mpr121.ino" -#ifdef USE_I2C -#ifdef USE_MPR121 - - - - - -#define XSNS_30 30 -#define XI2C_23 23 - - - - - - - -#define MPR121_ELEX_REG 0x00 - - -#define MPR121_MHDR_REG 0x2B - - -#define MPR121_MHDR_VAL 0x01 - - -#define MPR121_NHDR_REG 0x2C - - -#define MPR121_NHDR_VAL 0x01 - - -#define MPR121_NCLR_REG 0x2D - - -#define MPR121_NCLR_VAL 0x0E - - -#define MPR121_MHDF_REG 0x2F - - -#define MPR121_MHDF_VAL 0x01 - - -#define MPR121_NHDF_REG 0x30 - - -#define MPR121_NHDF_VAL 0x05 - - -#define MPR121_NCLF_REG 0x31 - - -#define MPR121_NCLF_VAL 0x01 - - -#define MPR121_MHDPROXR_REG 0x36 - - -#define MPR121_MHDPROXR_VAL 0x3F - - -#define MPR121_NHDPROXR_REG 0x37 - - -#define MPR121_NHDPROXR_VAL 0x5F - - -#define MPR121_NCLPROXR_REG 0x38 - - -#define MPR121_NCLPROXR_VAL 0x04 - - -#define MPR121_FDLPROXR_REG 0x39 - - -#define MPR121_FDLPROXR_VAL 0x00 - - -#define MPR121_MHDPROXF_REG 0x3A - - -#define MPR121_MHDPROXF_VAL 0x01 - - -#define MPR121_NHDPROXF_REG 0x3B - - -#define MPR121_NHDPROXF_VAL 0x01 - - -#define MPR121_NCLPROXF_REG 0x3C - - -#define MPR121_NCLPROXF_VAL 0x1F - - -#define MPR121_FDLPROXF_REG 0x3D - - -#define MPR121_FDLPROXF_VAL 0x04 - - -#define MPR121_E0TTH_REG 0x41 - - -#define MPR121_E0TTH_VAL 12 - - -#define MPR121_E0RTH_REG 0x42 - - -#define MPR121_E0RTH_VAL 6 - - -#define MPR121_CDT_REG 0x5D - - -#define MPR121_CDT_VAL 0x20 - - -#define MPR121_ECR_REG 0x5E - - -#define MPR121_ECR_VAL 0x8F - - - -#define MPR121_SRST_REG 0x80 - - -#define MPR121_SRST_VAL 0x63 - - -#define BITC(sensor,position) ((pS->current[sensor] >> position) & 1) - - -#define BITP(sensor,position) ((pS->previous[sensor] >> position) & 1) -# 195 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_30_mpr121.ino" -typedef struct mpr121 mpr121; -struct mpr121 { - const uint8_t i2c_addr[4] = { 0x5A, 0x5B, 0x5C, 0x5D }; - const char id[4] = { 'A', 'B', 'C', 'D' }; - bool connected[4] = { false, false, false, false }; - bool running[4] = { false, false, false, false }; - uint16_t current[4] = { 0x0000, 0x0000, 0x0000, 0x0000 }; - uint16_t previous[4] = { 0x0000, 0x0000, 0x0000, 0x0000 }; -}; - -bool mpr21_found = false; -# 217 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_30_mpr121.ino" -void Mpr121Init(struct mpr121 *pS, bool initial) -{ - - for (uint32_t i = 0; i < sizeof(pS->i2c_addr[i]); i++) { - - if (initial && I2cActive(pS->i2c_addr[i])) { continue; } - - - pS->connected[i] = (I2cWrite8(pS->i2c_addr[i], MPR121_SRST_REG, MPR121_SRST_VAL) - && (0x24 == I2cRead8(pS->i2c_addr[i], 0x5D))); - if (pS->connected[i]) { - - - mpr21_found = true; - char device_name[16]; - snprintf_P(device_name, sizeof(device_name), PSTR("MPR121(%c)"), pS->id[i]); - I2cSetActiveFound(pS->i2c_addr[i], device_name); - - - for (uint32_t j = 0; j < 13; j++) { - - - I2cWrite8(pS->i2c_addr[i], MPR121_E0TTH_REG + 2 * j, MPR121_E0TTH_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_E0RTH_REG + 2 * j, MPR121_E0RTH_VAL); - } - - - I2cWrite8(pS->i2c_addr[i], MPR121_MHDR_REG, MPR121_MHDR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NHDR_REG, MPR121_NHDR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NCLR_REG, MPR121_NCLR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_MHDF_REG, MPR121_MHDF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NHDF_REG, MPR121_NHDF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NCLF_REG, MPR121_NCLF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_MHDPROXR_REG, MPR121_MHDPROXR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NHDPROXR_REG, MPR121_NHDPROXR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NCLPROXR_REG, MPR121_NCLPROXR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_FDLPROXR_REG, MPR121_FDLPROXR_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_MHDPROXF_REG, MPR121_MHDPROXF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NHDPROXF_REG, MPR121_NHDPROXF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_NCLPROXF_REG, MPR121_NCLPROXF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_FDLPROXF_REG, MPR121_FDLPROXF_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_CDT_REG, MPR121_CDT_VAL); - - - I2cWrite8(pS->i2c_addr[i], MPR121_ECR_REG, MPR121_ECR_VAL); - - - pS->running[i] = (0x00 != I2cRead8(pS->i2c_addr[i], MPR121_ECR_REG)); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_I2C "MPR121%c: %sRunning"), pS->id[i], (pS->running[i]) ? "" : "NOT"); - - } else { - - - pS->running[i] = false; - } - } - - - if (!(pS->connected[0] || pS->connected[1] || pS->connected[2] - || pS->connected[3])) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C "MPR121: No sensors found")); - } -} -# 326 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_30_mpr121.ino" -void Mpr121Show(struct mpr121 *pS, uint8_t function) -{ - - - for (uint32_t i = 0; i < sizeof(pS->i2c_addr[i]); i++) { - - - if (pS->connected[i]) { - - - if (!I2cValidRead16LE(&pS->current[i], pS->i2c_addr[i], MPR121_ELEX_REG)) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_I2C "MPR121%c: ERROR: Cannot read data!"), pS->id[i]); - Mpr121Init(pS, false); - return; - } - - if (BITC(i, 15)) { - - - I2cWrite8(pS->i2c_addr[i], MPR121_ELEX_REG, 0x00); - AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_I2C "MPR121%c: ERROR: Excess current detected! Fix circuits if it happens repeatedly! Soft-resetting MPR121 ..."), pS->id[i]); - Mpr121Init(pS, false); - return; - } - } - - if (pS->running[i]) { - - - if (FUNC_JSON_APPEND == function) { - ResponseAppend_P(PSTR(",\"MPR121%c\":{"), pS->id[i]); - } - - for (uint32_t j = 0; j < 13; j++) { - - - if ((FUNC_EVERY_50_MSECOND == function) - && (BITC(i, j) != BITP(i, j))) { - Response_P(PSTR("{\"MPR121%c\":{\"Button%i\":%i}}"), pS->id[i], j, BITC(i, j)); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); - } - -#ifdef USE_WEBSERVER - if (FUNC_WEB_SENSOR == function) { - WSContentSend_PD(PSTR("{s}MPR121%c Button%d{m}%d{e}"), pS->id[i], j, BITC(i, j)); - } -#endif - - - if (FUNC_JSON_APPEND == function) { - ResponseAppend_P(PSTR("%s\"Button%i\":%i"), (j > 0 ? "," : ""), j, BITC(i, j)); - } - } - - - pS->previous[i] = pS->current[i]; - - - if (FUNC_JSON_APPEND == function) { - ResponseJsonEnd(); - } - } - } -} -# 410 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_30_mpr121.ino" -bool Xsns30(uint8_t function) -{ - if (!I2cEnabled(XI2C_23)) { return false; } - - bool result = false; - - - static struct mpr121 mpr121; - - if (FUNC_INIT == function) { - - Mpr121Init(&mpr121, true); - } - else if (mpr21_found) { - - switch (function) { - - - case FUNC_EVERY_50_MSECOND: - Mpr121Show(&mpr121, FUNC_EVERY_50_MSECOND); - break; - - - case FUNC_JSON_APPEND: - Mpr121Show(&mpr121, FUNC_JSON_APPEND); - break; - -#ifdef USE_WEBSERVER - - case FUNC_WEB_SENSOR: - Mpr121Show(&mpr121, FUNC_WEB_SENSOR); - break; -#endif - } - } - - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_31_ccs811.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_31_ccs811.ino" -#ifdef USE_I2C -#ifdef USE_CCS811 -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_31_ccs811.ino" -#define XSNS_31 31 -#define XI2C_24 24 - -#define EVERYNSECONDS 5 - -#include "Adafruit_CCS811.h" - -Adafruit_CCS811 ccs; -uint8_t CCS811_ready = 0; -uint8_t CCS811_type = 0;; -uint16_t eCO2; -uint16_t TVOC; -uint8_t tcnt = 0; -uint8_t ecnt = 0; - - - -void CCS811Detect(void) -{ - if (I2cActive(CCS811_ADDRESS)) { return; } - - if (!ccs.begin(CCS811_ADDRESS)) { - CCS811_type = 1; - I2cSetActiveFound(CCS811_ADDRESS, "CCS811"); - } -} - -void CCS811Update(void) -{ - tcnt++; - if (tcnt >= EVERYNSECONDS) { - tcnt = 0; - CCS811_ready = 0; - if (ccs.available()) { - if (!ccs.readData()){ - TVOC = ccs.getTVOC(); - eCO2 = ccs.geteCO2(); - CCS811_ready = 1; - if (global_update && global_humidity>0 && global_temperature!=9999) { ccs.setEnvironmentalData((uint8_t)global_humidity, global_temperature); } - ecnt = 0; - } - } else { - - ecnt++; - if (ecnt > 6) { - - ccs.begin(CCS811_ADDRESS); - } - } - } -} - -const char HTTP_SNS_CCS811[] PROGMEM = - "{s}CCS811 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" - "{s}CCS811 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; - -void CCS811Show(bool json) -{ - if (CCS811_ready) { - if (json) { - ResponseAppend_P(PSTR(",\"CCS811\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), eCO2,TVOC); -#ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, eCO2); -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CCS811, eCO2, TVOC); -#endif - } - } -} - - - - - -bool Xsns31(uint8_t function) -{ - if (!I2cEnabled(XI2C_24)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - CCS811Detect(); - } - else if (CCS811_type) { - switch (function) { - case FUNC_EVERY_SECOND: - CCS811Update(); - break; - case FUNC_JSON_APPEND: - CCS811Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - CCS811Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_32_mpu6050.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_32_mpu6050.ino" -#ifdef USE_I2C -#ifdef USE_MPU6050 -# 30 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_32_mpu6050.ino" -#define XSNS_32 32 -#define XI2C_25 25 - -#define D_SENSOR_MPU6050 "MPU6050" - -#define MPU_6050_ADDR_AD0_LOW 0x68 -#define MPU_6050_ADDR_AD0_HIGH 0x69 - -uint8_t MPU_6050_address; -uint8_t MPU_6050_addresses[] = { MPU_6050_ADDR_AD0_LOW, MPU_6050_ADDR_AD0_HIGH }; -uint8_t MPU_6050_found; - -int16_t MPU_6050_ax = 0, MPU_6050_ay = 0, MPU_6050_az = 0; -int16_t MPU_6050_gx = 0, MPU_6050_gy = 0, MPU_6050_gz = 0; -int16_t MPU_6050_temperature = 0; - -#ifdef USE_MPU6050_DMP - #include "MPU6050_6Axis_MotionApps20.h" - #include "I2Cdev.h" - #include - typedef struct MPU6050_DMP{ - uint8_t devStatus; - uint16_t packetSize; - uint16_t fifoCount; - uint8_t fifoBuffer[64]; - Quaternion q; - VectorInt16 aa; - VectorInt16 aaReal; - VectorFloat gravity; - float euler[3]; - float yawPitchRoll[3]; - } MPU6050_DMP; - - MPU6050_DMP MPU6050_dmp; -#else - #include -#endif -MPU6050 mpu6050; - -void MPU_6050PerformReading(void) -{ -#ifdef USE_MPU6050_DMP - mpu6050.resetFIFO(); - MPU6050_dmp.fifoCount = mpu6050.getFIFOCount(); - while (MPU6050_dmp.fifoCount < MPU6050_dmp.packetSize) MPU6050_dmp.fifoCount = mpu6050.getFIFOCount(); - mpu6050.getFIFOBytes(MPU6050_dmp.fifoBuffer, MPU6050_dmp.packetSize); - MPU6050_dmp.fifoCount -= MPU6050_dmp.packetSize; - - mpu6050.dmpGetQuaternion(&MPU6050_dmp.q, MPU6050_dmp.fifoBuffer); - mpu6050.dmpGetEuler(MPU6050_dmp.euler, &MPU6050_dmp.q); - mpu6050.dmpGetAccel(&MPU6050_dmp.aa, MPU6050_dmp.fifoBuffer); - mpu6050.dmpGetGravity(&MPU6050_dmp.gravity, &MPU6050_dmp.q); - mpu6050.dmpGetLinearAccel(&MPU6050_dmp.aaReal, &MPU6050_dmp.aa, &MPU6050_dmp.gravity); - mpu6050.dmpGetYawPitchRoll(MPU6050_dmp.yawPitchRoll, &MPU6050_dmp.q, &MPU6050_dmp.gravity); - MPU_6050_gx = MPU6050_dmp.euler[0] * 180/M_PI; - MPU_6050_gy = MPU6050_dmp.euler[1] * 180/M_PI; - MPU_6050_gz = MPU6050_dmp.euler[2] * 180/M_PI; - MPU_6050_ax = MPU6050_dmp.aaReal.x; - MPU_6050_ay = MPU6050_dmp.aaReal.y; - MPU_6050_az = MPU6050_dmp.aaReal.z; -#else - mpu6050.getMotion6( - &MPU_6050_ax, - &MPU_6050_ay, - &MPU_6050_az, - &MPU_6050_gx, - &MPU_6050_gy, - &MPU_6050_gz - ); -#endif - MPU_6050_temperature = mpu6050.getTemperature(); -} -# 119 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_32_mpu6050.ino" -void MPU_6050Detect(void) -{ - for (uint32_t i = 0; i < sizeof(MPU_6050_addresses); i++) - { - MPU_6050_address = MPU_6050_addresses[i]; - if (!I2cSetDevice(MPU_6050_address)) { break; } - mpu6050.setAddr(MPU_6050_addresses[i]); - -#ifdef USE_MPU6050_DMP - MPU6050_dmp.devStatus = mpu6050.dmpInitialize(); - mpu6050.setXGyroOffset(220); - mpu6050.setYGyroOffset(76); - mpu6050.setZGyroOffset(-85); - mpu6050.setZAccelOffset(1788); - if (MPU6050_dmp.devStatus == 0) { - mpu6050.setDMPEnabled(true); - MPU6050_dmp.packetSize = mpu6050.dmpGetFIFOPacketSize(); - MPU_6050_found = true; - } -#else - mpu6050.initialize(); - MPU_6050_found = mpu6050.testConnection(); -#endif - Settings.flag2.axis_resolution = 2; - } - - if (MPU_6050_found) { - I2cSetActiveFound(MPU_6050_address, D_SENSOR_MPU6050); - } -} - -#define D_YAW "Yaw" -#define D_PITCH "Pitch" -#define D_ROLL "Roll" - -#ifdef USE_WEBSERVER -const char HTTP_SNS_AXIS[] PROGMEM = - "{s}" D_SENSOR_MPU6050 " " D_AX_AXIS "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_AY_AXIS "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_AZ_AXIS "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_GX_AXIS "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_GY_AXIS "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_GZ_AXIS "{m}%s{e}"; -#ifdef USE_MPU6050_DMP -const char HTTP_SNS_YPR[] PROGMEM = - "{s}" D_SENSOR_MPU6050 " " D_YAW "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_PITCH "{m}%s{e}" - "{s}" D_SENSOR_MPU6050 " " D_ROLL "{m}%s{e}"; -#endif -#endif - -#define D_JSON_AXIS_AX "AccelXAxis" -#define D_JSON_AXIS_AY "AccelYAxis" -#define D_JSON_AXIS_AZ "AccelZAxis" -#define D_JSON_AXIS_GX "GyroXAxis" -#define D_JSON_AXIS_GY "GyroYAxis" -#define D_JSON_AXIS_GZ "GyroZAxis" -#define D_JSON_YAW "Yaw" -#define D_JSON_PITCH "Pitch" -#define D_JSON_ROLL "Roll" - -void MPU_6050Show(bool json) -{ - MPU_6050PerformReading(); - - double tempConv = (MPU_6050_temperature / 340.0 + 35.53); - char temperature[33]; - dtostrfd(tempConv, Settings.flag2.temperature_resolution, temperature); - char axis_ax[33]; - dtostrfd(MPU_6050_ax, Settings.flag2.axis_resolution, axis_ax); - char axis_ay[33]; - dtostrfd(MPU_6050_ay, Settings.flag2.axis_resolution, axis_ay); - char axis_az[33]; - dtostrfd(MPU_6050_az, Settings.flag2.axis_resolution, axis_az); - char axis_gx[33]; - dtostrfd(MPU_6050_gx, Settings.flag2.axis_resolution, axis_gx); - char axis_gy[33]; - dtostrfd(MPU_6050_gy, Settings.flag2.axis_resolution, axis_gy); - char axis_gz[33]; - dtostrfd(MPU_6050_gz, Settings.flag2.axis_resolution, axis_gz); -#ifdef USE_MPU6050_DMP - char axis_yaw[33]; - dtostrfd(MPU6050_dmp.yawPitchRoll[0] / PI * 180.0, Settings.flag2.axis_resolution, axis_yaw); - char axis_pitch[33]; - dtostrfd(MPU6050_dmp.yawPitchRoll[1] / PI * 180.0, Settings.flag2.axis_resolution, axis_pitch); - char axis_roll[33]; - dtostrfd(MPU6050_dmp.yawPitchRoll[2] / PI * 180.0, Settings.flag2.axis_resolution, axis_roll); -#endif - - if (json) { - char json_axis_ax[25]; - snprintf_P(json_axis_ax, sizeof(json_axis_ax), PSTR(",\"" D_JSON_AXIS_AX "\":%s"), axis_ax); - char json_axis_ay[25]; - snprintf_P(json_axis_ay, sizeof(json_axis_ay), PSTR(",\"" D_JSON_AXIS_AY "\":%s"), axis_ay); - char json_axis_az[25]; - snprintf_P(json_axis_az, sizeof(json_axis_az), PSTR(",\"" D_JSON_AXIS_AZ "\":%s"), axis_az); - char json_axis_gx[25]; - snprintf_P(json_axis_gx, sizeof(json_axis_gx), PSTR(",\"" D_JSON_AXIS_GX "\":%s"), axis_gx); - char json_axis_gy[25]; - snprintf_P(json_axis_gy, sizeof(json_axis_gy), PSTR(",\"" D_JSON_AXIS_GY "\":%s"), axis_gy); - char json_axis_gz[25]; - snprintf_P(json_axis_gz, sizeof(json_axis_gz), PSTR(",\"" D_JSON_AXIS_GZ "\":%s"), axis_gz); -#ifdef USE_MPU6050_DMP - char json_ypr_y[25]; - snprintf_P(json_ypr_y, sizeof(json_ypr_y), PSTR(",\"" D_JSON_YAW "\":%s"), axis_yaw); - char json_ypr_p[25]; - snprintf_P(json_ypr_p, sizeof(json_ypr_p), PSTR(",\"" D_JSON_PITCH "\":%s"), axis_pitch); - char json_ypr_r[25]; - snprintf_P(json_ypr_r, sizeof(json_ypr_r), PSTR(",\"" D_JSON_ROLL "\":%s"), axis_roll); - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s%s%s%s%s%s%s%s%s}"), - D_SENSOR_MPU6050, temperature, json_axis_ax, json_axis_ay, json_axis_az, json_axis_gx, json_axis_gy, json_axis_gz, - json_ypr_y, json_ypr_p, json_ypr_r); -#else - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s%s%s%s%s%s%s}"), - D_SENSOR_MPU6050, temperature, json_axis_ax, json_axis_ay, json_axis_az, json_axis_gx, json_axis_gy, json_axis_gz); -#endif -#ifdef USE_DOMOTICZ - DomoticzSensor(DZ_TEMP, temperature); -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, D_SENSOR_MPU6050, temperature, TempUnit()); - WSContentSend_PD(HTTP_SNS_AXIS, axis_ax, axis_ay, axis_az, axis_gx, axis_gy, axis_gz); -#ifdef USE_MPU6050_DMP - WSContentSend_PD(HTTP_SNS_YPR, axis_yaw, axis_pitch, axis_roll); -#endif -#endif - } -} - - - - - -bool Xsns32(uint8_t function) -{ - if (!I2cEnabled(XI2C_25)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - MPU_6050Detect(); - } - else if (MPU_6050_found) { - switch (function) { - case FUNC_EVERY_SECOND: - if (tele_period == Settings.tele_period -3) { - MPU_6050PerformReading(); - } - break; - case FUNC_JSON_APPEND: - MPU_6050Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MPU_6050Show(0); - MPU_6050PerformReading(); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_33_ds3231.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_33_ds3231.ino" -#ifdef USE_I2C -#ifdef USE_DS3231 -# 35 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_33_ds3231.ino" -#define XSNS_33 33 -#define XI2C_26 26 - - -#ifndef USE_RTC_ADDR -#define USE_RTC_ADDR 0x68 -#endif - - -#define RTC_SECONDS 0x00 -#define RTC_MINUTES 0x01 -#define RTC_HOURS 0x02 -#define RTC_DAY 0x03 -#define RTC_DATE 0x04 -#define RTC_MONTH 0x05 -#define RTC_YEAR 0x06 -#define RTC_CONTROL 0x0E -#define RTC_STATUS 0x0F - -#define OSF 7 -#define EOSC 7 -#define BBSQW 6 -#define CONV 5 -#define RS2 4 -#define RS1 3 -#define INTCN 2 - - -#define HR1224 6 -#define CENTURY 7 -#define DYDT 6 -bool ds3231ReadStatus = false; -bool ds3231WriteStatus = false; -bool DS3231chipDetected = false; - - - - -void DS3231Detect(void) -{ - if (I2cActive(USE_RTC_ADDR)) { return; } - - if (I2cValidRead(USE_RTC_ADDR, RTC_STATUS, 1)) { - I2cSetActiveFound(USE_RTC_ADDR, "DS3231"); - DS3231chipDetected = true; - } -} - - - - -uint8_t bcd2dec(uint8_t n) -{ - return n - 6 * (n >> 4); -} - - - - -uint8_t dec2bcd(uint8_t n) -{ - return n + 6 * (n / 10); -} - - - - -uint32_t ReadFromDS3231(void) -{ - TIME_T tm; - tm.second = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_SECONDS)); - tm.minute = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_MINUTES)); - tm.hour = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_HOURS) & ~_BV(HR1224)); - tm.day_of_week = I2cRead8(USE_RTC_ADDR, RTC_DAY); - tm.day_of_month = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_DATE)); - tm.month = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_MONTH) & ~_BV(CENTURY)); - tm.year = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_YEAR)); - return MakeTime(tm); -} - - - -void SetDS3231Time (uint32_t epoch_time) { - TIME_T tm; - BreakTime(epoch_time, tm); - I2cWrite8(USE_RTC_ADDR, RTC_SECONDS, dec2bcd(tm.second)); - I2cWrite8(USE_RTC_ADDR, RTC_MINUTES, dec2bcd(tm.minute)); - I2cWrite8(USE_RTC_ADDR, RTC_HOURS, dec2bcd(tm.hour)); - I2cWrite8(USE_RTC_ADDR, RTC_DAY, tm.day_of_week); - I2cWrite8(USE_RTC_ADDR, RTC_DATE, dec2bcd(tm.day_of_month)); - I2cWrite8(USE_RTC_ADDR, RTC_MONTH, dec2bcd(tm.month)); - I2cWrite8(USE_RTC_ADDR, RTC_YEAR, dec2bcd(tm.year)); - I2cWrite8(USE_RTC_ADDR, RTC_STATUS, I2cRead8(USE_RTC_ADDR, RTC_STATUS) & ~_BV(OSF)); -} - -void DS3231EverySecond(void) -{ - TIME_T tmpTime; - if (!ds3231ReadStatus && Rtc.utc_time < START_VALID_TIME ) { - ntp_force_sync = true; - Rtc.utc_time = ReadFromDS3231(); - - - BreakTime(Rtc.utc_time, tmpTime); - if (Rtc.utc_time < START_VALID_TIME ) { - ds3231ReadStatus = true; - } - RtcTime.year = tmpTime.year + 1970; - Rtc.daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); - Rtc.standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); - AddLog_P2(LOG_LEVEL_INFO, PSTR("Set time from DS3231 to RTC (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), - GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str()); - if (Rtc.local_time < START_VALID_TIME) { - rules_flag.time_init = 1; - } else { - rules_flag.time_set = 1; - } - } - else if (!ds3231WriteStatus && Rtc.utc_time > START_VALID_TIME && abs(Rtc.utc_time - ReadFromDS3231()) > 60) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("Write Time TO DS3231 from NTP (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), - GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str()); - SetDS3231Time (Rtc.utc_time); - ds3231WriteStatus = true; - } -} - - - - - -bool Xsns33(uint8_t function) -{ - if (!I2cEnabled(XI2C_26)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - DS3231Detect(); - } - else if (DS3231chipDetected) { - switch (function) { - case FUNC_EVERY_SECOND: - DS3231EverySecond(); - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_34_hx711.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_34_hx711.ino" -#ifdef USE_HX711 -# 35 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_34_hx711.ino" -#define XSNS_34 34 - -#ifndef HX_MAX_WEIGHT -#define HX_MAX_WEIGHT 20000 -#endif -#ifndef HX_REFERENCE -#define HX_REFERENCE 250 -#endif -#ifndef HX_SCALE -#define HX_SCALE 120 -#endif - -#define HX_TIMEOUT 120 -#define HX_SAMPLES 10 -#define HX_CAL_TIMEOUT 15 - -#define HX_GAIN_128 1 -#define HX_GAIN_32 2 -#define HX_GAIN_64 3 - -#define D_JSON_WEIGHT_REF "WeightRef" -#define D_JSON_WEIGHT_CAL "WeightCal" -#define D_JSON_WEIGHT_MAX "WeightMax" -#define D_JSON_WEIGHT_ITEM "WeightItem" -#define D_JSON_WEIGHT_CHANGE "WeightChange" -#define D_JSON_WEIGHT_RAW "WeightRaw" -#define D_JSON_WEIGHT_DELTA "WeightDelta" - -enum HxCalibrationSteps { HX_CAL_END, HX_CAL_LIMBO, HX_CAL_FINISH, HX_CAL_FAIL, HX_CAL_DONE, HX_CAL_FIRST, HX_CAL_RESET, HX_CAL_START }; - -const char kHxCalibrationStates[] PROGMEM = D_HX_CAL_FAIL "|" D_HX_CAL_DONE "|" D_HX_CAL_REFERENCE "|" D_HX_CAL_REMOVE; - -struct HX { - long weight = 0; - long raw = 0; - long last_weight = 0; - long sum_weight = 0; - long sum_raw = 0; - long offset = 0; - long scale = 1; - long weight_diff = 0; - uint8_t type = 1; - uint8_t sample_count = 0; - uint8_t calibrate_step = HX_CAL_END; - uint8_t calibrate_timer = 0; - uint8_t calibrate_msg = 0; - uint8_t pin_sck; - uint8_t pin_dout; - bool tare_flg = false; - bool weight_changed = false; - uint16_t weight_delta = 4; -} Hx; - - - -bool HxIsReady(uint16_t timeout) -{ - - uint32_t start = millis(); - while ((digitalRead(Hx.pin_dout) == HIGH) && (millis() - start < timeout)) { yield(); } - return (digitalRead(Hx.pin_dout) == LOW); -} - -long HxRead(void) -{ - if (!HxIsReady(HX_TIMEOUT)) { return -1; } - - uint8_t data[3] = { 0 }; - uint8_t filler = 0x00; - - - data[2] = shiftIn(Hx.pin_dout, Hx.pin_sck, MSBFIRST); - data[1] = shiftIn(Hx.pin_dout, Hx.pin_sck, MSBFIRST); - data[0] = shiftIn(Hx.pin_dout, Hx.pin_sck, MSBFIRST); - - - for (unsigned int i = 0; i < HX_GAIN_128; i++) { - digitalWrite(Hx.pin_sck, HIGH); - digitalWrite(Hx.pin_sck, LOW); - } - - - if (data[2] & 0x80) { filler = 0xFF; } - - - unsigned long value = ( static_cast(filler) << 24 - | static_cast(data[2]) << 16 - | static_cast(data[1]) << 8 - | static_cast(data[0]) ); - - return static_cast(value); -} - - - -void HxResetPart(void) -{ - Hx.tare_flg = true; - Hx.sum_weight = 0; - Hx.sample_count = 0; - Hx.last_weight = 0; -} - -void HxReset(void) -{ - HxResetPart(); - Settings.energy_frequency_calibration = 0; -} - -void HxCalibrationStateTextJson(uint8_t msg_id) -{ - char cal_text[30]; - - Hx.calibrate_msg = msg_id; - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, GetTextIndexed(cal_text, sizeof(cal_text), Hx.calibrate_msg, kHxCalibrationStates)); - - if (msg_id < 3) { MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("Sensor34")); } -} - -void SetWeightDelta() -{ - - if (Settings.weight_change == 0) { - Hx.weight_delta = 4; - return; - } - - - if (Settings.weight_change > 100) { - Hx.weight_delta = (Settings.weight_change - 100) * 10 + 100; - return; - } - - - Hx.weight_delta = Settings.weight_change - 1; -} -# 192 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_34_hx711.ino" -bool HxCommand(void) -{ - bool serviced = true; - bool show_parms = false; - char sub_string[XdrvMailbox.data_len +1]; - - for (uint32_t ca = 0; ca < XdrvMailbox.data_len; ca++) { - if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; } - } - - switch (XdrvMailbox.payload) { - case 1: - HxReset(); - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, "Reset"); - break; - case 2: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); - } - Hx.scale = 1; - HxReset(); - Hx.calibrate_step = HX_CAL_START; - Hx.calibrate_timer = 1; - HxCalibrationStateTextJson(3); - break; - case 3: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); - } - show_parms = true; - break; - case 4: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.weight_calibration = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); - Hx.scale = Settings.weight_calibration; - } - show_parms = true; - break; - case 5: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.weight_max = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) / 1000; - } - show_parms = true; - break; - case 6: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.weight_item = (unsigned long)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 10); - } - show_parms = true; - break; - case 7: - Settings.energy_frequency_calibration = Hx.weight; - Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE); - break; - case 8: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.SensorBits1.hx711_json_weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) & 1; - } - show_parms = true; - break; - case 9: - if (strstr(XdrvMailbox.data, ",") != nullptr) { - Settings.weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); - SetWeightDelta(); - } - show_parms = true; - break; - default: - show_parms = true; - } - - if (show_parms) { - char item[33]; - dtostrfd((float)Settings.weight_item / 10, 1, item); - Response_P(PSTR("{\"Sensor34\":{\"" D_JSON_WEIGHT_REF "\":%d,\"" D_JSON_WEIGHT_CAL "\":%d,\"" D_JSON_WEIGHT_MAX "\":%d,\"" - D_JSON_WEIGHT_ITEM "\":%s,\"" D_JSON_WEIGHT_CHANGE "\":%s,\"" D_JSON_WEIGHT_DELTA "\":%d}}"), - Settings.weight_reference, Settings.weight_calibration, Settings.weight_max * 1000, - item, GetStateText(Settings.SensorBits1.hx711_json_weight_change), Settings.weight_change); - } - - return serviced; -} - - - -long HxWeight(void) -{ - return (Hx.calibrate_step < HX_CAL_FAIL) ? Hx.weight : 0; -} - -void HxInit(void) -{ - Hx.type = 0; - if ((pin[GPIO_HX711_DAT] < 99) && (pin[GPIO_HX711_SCK] < 99)) { - Hx.pin_sck = pin[GPIO_HX711_SCK]; - Hx.pin_dout = pin[GPIO_HX711_DAT]; - - pinMode(Hx.pin_sck, OUTPUT); - pinMode(Hx.pin_dout, INPUT); - - digitalWrite(Hx.pin_sck, LOW); - - SetWeightDelta(); - - if (HxIsReady(8 * HX_TIMEOUT)) { - if (!Settings.weight_max) { Settings.weight_max = HX_MAX_WEIGHT / 1000; } - if (!Settings.weight_calibration) { Settings.weight_calibration = HX_SCALE; } - if (!Settings.weight_reference) { Settings.weight_reference = HX_REFERENCE; } - Hx.scale = Settings.weight_calibration; - HxRead(); - HxResetPart(); - Hx.type = 1; - } - } -} - -void HxEvery100mSecond(void) -{ - long raw = HxRead(); - Hx.sum_raw += raw; - Hx.sum_weight += raw; - - Hx.sample_count++; - if (HX_SAMPLES == Hx.sample_count) { - long average = Hx.sum_weight / Hx.sample_count; - long raw_average = Hx.sum_raw / Hx.sample_count; - long value = average - Hx.offset; - Hx.weight = value / Hx.scale; - Hx.raw = raw_average / Hx.scale; - if (Hx.weight < 0) { - if (Settings.energy_frequency_calibration) { - long difference = Settings.energy_frequency_calibration + Hx.weight; - Hx.last_weight = difference; - if (difference < 0) { HxReset(); } - } - Hx.weight = 0; - } else { - Hx.last_weight = Settings.energy_frequency_calibration; - } - - if (Hx.tare_flg) { - Hx.tare_flg = false; - Hx.offset = average; - } - - if (Hx.calibrate_step) { - Hx.calibrate_timer--; - - if (HX_CAL_START == Hx.calibrate_step) { - Hx.calibrate_step--; - Hx.calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES); - } - else if (HX_CAL_RESET == Hx.calibrate_step) { - if (Hx.calibrate_timer) { - if (Hx.weight < (long)Settings.weight_reference) { - Hx.calibrate_step--; - Hx.calibrate_timer = HX_CAL_TIMEOUT * (10 / HX_SAMPLES); - HxCalibrationStateTextJson(2); - } - } else { - Hx.calibrate_step = HX_CAL_FAIL; - } - } - else if (HX_CAL_FIRST == Hx.calibrate_step) { - if (Hx.calibrate_timer) { - if (Hx.weight > (long)Settings.weight_reference) { - Hx.calibrate_step--; - } - } else { - Hx.calibrate_step = HX_CAL_FAIL; - } - } - else if (HX_CAL_DONE == Hx.calibrate_step) { - if (Hx.weight > (long)Settings.weight_reference) { - Hx.calibrate_step = HX_CAL_FINISH; - Settings.weight_calibration = Hx.weight / Settings.weight_reference; - Hx.weight = 0; - HxCalibrationStateTextJson(1); - } else { - Hx.calibrate_step = HX_CAL_FAIL; - } - } - - if (HX_CAL_FAIL == Hx.calibrate_step) { - Hx.calibrate_step--; - Hx.tare_flg = true; - HxCalibrationStateTextJson(0); - } - if (HX_CAL_FINISH == Hx.calibrate_step) { - Hx.calibrate_step--; - Hx.calibrate_timer = 3 * (10 / HX_SAMPLES); - Hx.scale = Settings.weight_calibration; - } - - if (!Hx.calibrate_timer) { - Hx.calibrate_step = HX_CAL_END; - } - } else { - Hx.weight += Hx.last_weight; - - if (Settings.SensorBits1.hx711_json_weight_change) { - if (abs(Hx.weight - Hx.weight_diff) > Hx.weight_delta) { - Hx.weight_diff = Hx.weight; - Hx.weight_changed = true; - } - else if (Hx.weight_changed && (Hx.weight == Hx.weight_diff)) { - mqtt_data[0] = '\0'; - ResponseAppendTime(); - HxShow(true); - ResponseJsonEnd(); - MqttPublishTeleSensor(); - Hx.weight_changed = false; - } - } - } - - Hx.sum_weight = 0; - Hx.sum_raw = 0; - Hx.sample_count = 0; - } -} - -void HxSaveBeforeRestart(void) -{ - Settings.energy_frequency_calibration = Hx.weight; - Hx.sample_count = HX_SAMPLES +1; -} - -#ifdef USE_WEBSERVER -const char HTTP_HX711_WEIGHT[] PROGMEM = - "{s}HX711 " D_WEIGHT "{m}%s " D_UNIT_KILOGRAM "{e}"; -const char HTTP_HX711_COUNT[] PROGMEM = - "{s}HX711 " D_COUNT "{m}%d{e}"; -const char HTTP_HX711_CAL[] PROGMEM = - "{s}HX711 %s{m}{e}"; -#endif - -void HxShow(bool json) -{ - char scount[30] = { 0 }; - - uint16_t count = 0; - float weight = 0; - if (Hx.calibrate_step < HX_CAL_FAIL) { - if (Hx.weight && Settings.weight_item) { - count = (Hx.weight * 10) / Settings.weight_item; - if (count > 1) { - snprintf_P(scount, sizeof(scount), PSTR(",\"" D_JSON_COUNT "\":%d"), count); - } - } - weight = (float)Hx.weight / 1000; - } - char weight_chr[33]; - dtostrfd(weight, Settings.flag2.weight_resolution, weight_chr); - - if (json) { - ResponseAppend_P(PSTR(",\"HX711\":{\"" D_JSON_WEIGHT "\":%s%s, \"" D_JSON_WEIGHT_RAW "\":%d}"), weight_chr, scount, Hx.raw); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_HX711_WEIGHT, weight_chr); - if (count > 1) { - WSContentSend_PD(HTTP_HX711_COUNT, count); - } - if (Hx.calibrate_step) { - char cal_text[30]; - WSContentSend_PD(HTTP_HX711_CAL, GetTextIndexed(cal_text, sizeof(cal_text), Hx.calibrate_msg, kHxCalibrationStates)); - } -#endif - } -} - -#ifdef USE_WEBSERVER -#ifdef USE_HX711_GUI - - - - -#define WEB_HANDLE_HX711 "s34" - -const char S_CONFIGURE_HX711[] PROGMEM = D_CONFIGURE_HX711; - -const char HTTP_BTN_MENU_MAIN_HX711[] PROGMEM = - "

"; - -const char HTTP_BTN_MENU_HX711[] PROGMEM = - "

"; - -const char HTTP_FORM_HX711[] PROGMEM = - "
 " D_CALIBRATION " " - "
" - "

" D_REFERENCE_WEIGHT " (" D_UNIT_KILOGRAM ")

" - "
" - "
" - "


" - - "
 " D_HX711_PARAMETERS " " - "
" - "

" D_ITEM_WEIGHT " (" D_UNIT_KILOGRAM ")

"; - -void HandleHxAction(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_HX711); - - if (Webserver->hasArg("save")) { - HxSaveSettings(); - HandleConfiguration(); - return; - } - - char stemp1[20]; - - if (Webserver->hasArg("reset")) { - snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 1")); - ExecuteWebCommand(stemp1, SRC_WEBGUI); - - HandleRoot(); - return; - } - - if (Webserver->hasArg("calibrate")) { - WebGetArg("p1", stemp1, sizeof(stemp1)); - Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToFloat(stemp1) * 1000); - - HxLogUpdates(); - - snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 2")); - ExecuteWebCommand(stemp1, SRC_WEBGUI); - - HandleRoot(); - return; - } - - WSContentStart_P(S_CONFIGURE_HX711); - WSContentSendStyle(); - dtostrfd((float)Settings.weight_reference / 1000, 3, stemp1); - char stemp2[20]; - dtostrfd((float)Settings.weight_item / 10000, 4, stemp2); - WSContentSend_P(HTTP_FORM_HX711, stemp1, stemp2); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -void HxSaveSettings(void) -{ - char tmp[100]; - - WebGetArg("p2", tmp, sizeof(tmp)); - Settings.weight_item = (!strlen(tmp)) ? 0 : (unsigned long)(CharToFloat(tmp) * 10000); - - HxLogUpdates(); -} - -void HxLogUpdates(void) -{ - char weigth_ref_chr[33]; - dtostrfd((float)Settings.weight_reference / 1000, Settings.flag2.weight_resolution, weigth_ref_chr); - char weigth_item_chr[33]; - dtostrfd((float)Settings.weight_item / 10000, 4, weigth_item_chr); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_JSON_WEIGHT_REF " %s, " D_JSON_WEIGHT_ITEM " %s"), weigth_ref_chr, weigth_item_chr); -} - -#endif -#endif - - - - - -bool Xsns34(uint8_t function) -{ - bool result = false; - - if (Hx.type) { - switch (function) { - case FUNC_EVERY_100_MSECOND: - HxEvery100mSecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_34 == XdrvMailbox.index) { - result = HxCommand(); - } - break; - case FUNC_JSON_APPEND: - HxShow(1); - break; - case FUNC_SAVE_BEFORE_RESTART: - HxSaveBeforeRestart(); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HxShow(0); - break; -#ifdef USE_HX711_GUI - case FUNC_WEB_ADD_MAIN_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_MAIN_HX711); - break; - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_HX711); - break; - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/" WEB_HANDLE_HX711, HandleHxAction); - break; -#endif -#endif - case FUNC_INIT: - HxInit(); - break; - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_35_tx20.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_35_tx20.ino" -#if defined(USE_TX20_WIND_SENSOR) || defined(USE_TX23_WIND_SENSOR) -# 51 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_35_tx20.ino" -#define XSNS_35 35 - -#if defined(USE_TX20_WIND_SENSOR) && defined(USE_TX23_WIND_SENSOR) -#undef USE_TX20_WIND_SENSOR -#warning **** use USE_TX20_WIND_SENSOR or USE_TX23_WIND_SENSOR but not both together, TX20 disabled **** -#endif - - -#define TX2X_BIT_TIME 1220 -#define TX2X_WEIGHT_AVG_SAMPLE 150 -#define TX2X_TIMEOUT 10 -#define TX23_READ_INTERVAL 4 - - - -extern "C" { -#include "gpio.h" -} - -#ifdef USE_TX20_WIND_SENSOR -#undef D_TX2x_NAME -#define D_TX2x_NAME "TX20" -#else -#undef D_TX2x_NAME -#define D_TX2x_NAME "TX23" -#endif - -#ifdef USE_WEBSERVER -#define D_TX20_WIND_AVG "∅" -#define D_TX20_WIND_ANGLE "∠" -#define D_TX20_WIND_DEGREE "°" -const char HTTP_SNS_TX2X[] PROGMEM = - "{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED "{m}%s %s{e}" -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - "{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED " " D_TX20_WIND_AVG "{m}%s %s{e}" - "{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED_MIN "{m}%s %s{e}" - "{s}" D_TX2x_NAME " " D_TX20_WIND_SPEED_MAX "{m}%s %s{e}" -#endif - "{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION "{m}%s %s" D_TX20_WIND_DEGREE "{e}" -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - "{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION " " D_TX20_WIND_AVG "{m}%s %s" D_TX20_WIND_DEGREE "{e}" - "{s}" D_TX2x_NAME " " D_TX20_WIND_DIRECTION " " D_TX20_WIND_ANGLE "{m}%s" D_TX20_WIND_DEGREE " (%s,%s)" D_TX20_WIND_DEGREE; -#endif - ; -#endif - - -float const tx2x_f_pi = 3.1415926535897932384626433; -float const tx2x_f_halfpi = tx2x_f_pi / 2.0; -float const tx2x_f_pi180 = tx2x_f_pi / 180.0; - -#define TX2X_DIRECTIONS_MAXSIZE 3 -const char kTx2xDirections[] PROGMEM = D_TX20_NORTH "|" - D_TX20_NORTH D_TX20_NORTH D_TX20_EAST "|" - D_TX20_NORTH D_TX20_EAST "|" - D_TX20_EAST D_TX20_NORTH D_TX20_EAST "|" - D_TX20_EAST "|" - D_TX20_EAST D_TX20_SOUTH D_TX20_EAST "|" - D_TX20_SOUTH D_TX20_EAST "|" - D_TX20_SOUTH D_TX20_SOUTH D_TX20_EAST "|" - D_TX20_SOUTH "|" - D_TX20_SOUTH D_TX20_SOUTH D_TX20_WEST "|" - D_TX20_SOUTH D_TX20_WEST "|" - D_TX20_WEST D_TX20_SOUTH D_TX20_WEST "|" - D_TX20_WEST "|" - D_TX20_WEST D_TX20_NORTH D_TX20_WEST "|" - D_TX20_NORTH D_TX20_WEST "|" - D_TX20_NORTH D_TX20_NORTH D_TX20_WEST; - -int32_t tx2x_wind_speed = 0; -int32_t tx2x_wind_direction = 0; - -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS -int32_t tx2x_wind_speed_min = 0xfff; -int32_t tx2x_wind_speed_max = 0; -float tx2x_wind_speed_avg = 0; -float tx2x_wind_direction_avg_x = 0; -float tx2x_wind_direction_avg_y = 0; -float tx2x_wind_direction_avg = 0; -int32_t tx2x_wind_direction_min = 0; -int32_t tx2x_wind_direction_max = 0; - -uint32_t tx2x_count = 0; -uint32_t tx2x_avg_samples; -uint32_t tx2x_last_uptime = 0; -bool tx2x_valuesread = false; -#endif - -#ifdef DEBUG_TASMOTA_SENSOR -uint32_t tx2x_sa = 0; -uint32_t tx2x_sb = 0; -uint32_t tx2x_sc = 0; -uint32_t tx2x_sd = 0; -uint32_t tx2x_se = 0; -uint32_t tx2x_sf = 0; -#endif -uint32_t tx2x_last_available = 0; - -#ifdef USE_TX23_WIND_SENSOR -uint32_t tx23_stage = 0; -#endif - -#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 -void TX2xStartRead(void) ICACHE_RAM_ATTR; -#endif - -void TX2xStartRead(void) -{ -# 184 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_35_tx20.ino" -#ifdef USE_TX23_WIND_SENSOR - if (0!=tx23_stage) - { - if ((2==tx23_stage) || (3==tx23_stage)) - { -#endif -#ifdef DEBUG_TASMOTA_SENSOR - tx2x_sa = 0; - tx2x_sb = 0; - tx2x_sc = 0; - tx2x_sd = 0; - tx2x_se = 0; - tx2x_sf = 0; -#else - uint32_t tx2x_sa = 0; - uint32_t tx2x_sb = 0; - uint32_t tx2x_sc = 0; - uint32_t tx2x_sd = 0; - uint32_t tx2x_se = 0; - uint32_t tx2x_sf = 0; -#endif - - delayMicroseconds(TX2X_BIT_TIME / 2); - - for (int32_t bitcount = 41; bitcount > 0; bitcount--) { - uint32_t dpin = (digitalRead(pin[GPIO_TX2X_TXD_BLACK])); -#ifdef USE_TX23_WIND_SENSOR - dpin ^= 1; -#endif - if (bitcount > 41 - 5) { - - tx2x_sa = (tx2x_sa << 1) | (dpin ^ 1); - } else if (bitcount > 41 - 5 - 4) { - - tx2x_sb = tx2x_sb >> 1 | ((dpin ^ 1) << 3); - } else if (bitcount > 41 - 5 - 4 - 12) { - - tx2x_sc = tx2x_sc >> 1 | ((dpin ^ 1) << 11); - } else if (bitcount > 41 - 5 - 4 - 12 - 4) { - - tx2x_sd = tx2x_sd >> 1 | ((dpin ^ 1) << 3); - } else if (bitcount > 41 - 5 - 4 - 12 - 4 - 4) { - - tx2x_se = tx2x_se >> 1 | (dpin << 3); - } else { - - tx2x_sf = tx2x_sf >> 1 | (dpin << 11); - } - delayMicroseconds(TX2X_BIT_TIME); - } - - uint32_t chk = (tx2x_sb + (tx2x_sc & 0xf) + ((tx2x_sc >> 4) & 0xf) + ((tx2x_sc >> 8) & 0xf)); - chk &= 0xf; - - - ; -#ifdef USE_TX23_WIND_SENSOR - if ((chk == tx2x_sd) && (0x1b==tx2x_sa) && (tx2x_sb==tx2x_se) && (tx2x_sc==tx2x_sf) && (tx2x_sc < 511)) { -#else - if ((chk == tx2x_sd) && (tx2x_sb==tx2x_se) && (tx2x_sc==tx2x_sf) && (tx2x_sc < 511)) { -#endif - tx2x_last_available = uptime; - - tx2x_wind_speed = tx2x_sc; - tx2x_wind_direction = tx2x_sb; -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - if (!tx2x_valuesread) { - tx2x_wind_direction_min = tx2x_wind_direction; - tx2x_wind_direction_max = tx2x_wind_direction; - tx2x_valuesread = true; - } -#endif - } - -#ifdef USE_TX23_WIND_SENSOR - } - tx23_stage++; - } -#endif - - - - GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << pin[GPIO_TX2X_TXD_BLACK]); -} - -bool Tx2xAvailable(void) -{ - return ((uptime - tx2x_last_available) < TX2X_TIMEOUT); -} - -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS -float atan2f(float a, float b) -{ - float atan2val; - if (b > 0) { - atan2val = atanf(a/b); - } else if ((b < 0) && (a >= 0)) { - atan2val = atanf(a/b) + tx2x_f_pi; - } else if ((b < 0) && (a < 0)) { - atan2val = atanf(a/b) - tx2x_f_pi; - } else if ((b == 0) && (a > 0)) { - atan2val = tx2x_f_halfpi; - } else if ((b == 0) && (a < 0)) { - atan2val = 0 - (tx2x_f_halfpi); - } else if ((b == 0) && (a == 0)) { - atan2val = 1000; - } - return atan2val; -} - -void Tx2xCheckSampleCount(void) -{ - uint32_t tx2x_prev_avg_samples = tx2x_avg_samples; - if (Settings.tele_period) { - - tx2x_avg_samples = Settings.tele_period; - } else { - - tx2x_avg_samples = TX2X_WEIGHT_AVG_SAMPLE; - } - if (tx2x_prev_avg_samples != tx2x_avg_samples) { - tx2x_wind_speed_avg = tx2x_wind_speed; - tx2x_count = 0; - } -} - -void Tx2xResetStat(void) -{ - DEBUG_SENSOR_LOG(PSTR(D_TX2x_NAME ": reset statistics")); - tx2x_last_uptime = uptime; - Tx2xResetStatData(); -} - -void Tx2xResetStatData(void) -{ - tx2x_wind_speed_min = tx2x_wind_speed; - tx2x_wind_speed_max = tx2x_wind_speed; - - tx2x_wind_direction_min = tx2x_wind_direction; - tx2x_wind_direction_max = tx2x_wind_direction; -} -#endif - -void Tx2xRead(void) -{ -#ifdef USE_TX23_WIND_SENSOR - - - - - - - - if ((uptime % TX23_READ_INTERVAL)==0) { - - - tx23_stage = 0; - pinMode(pin[GPIO_TX2X_TXD_BLACK], OUTPUT); - digitalWrite(pin[GPIO_TX2X_TXD_BLACK], LOW); - } else if ((uptime % TX23_READ_INTERVAL)==1) { - - - tx23_stage = 1; - pinMode(pin[GPIO_TX2X_TXD_BLACK], INPUT_PULLUP); - } -#endif - if (Tx2xAvailable()) { -#ifdef DEBUG_TASMOTA_SENSOR - DEBUG_SENSOR_LOG(PSTR(D_TX2x_NAME ": sa=0x%02lx sb=%ld (0x%02lx), sc=%ld (0x%03lx), sd=0x%02lx, se=%ld, sf=%ld"), tx2x_sa,tx2x_sb,tx2x_sb,tx2x_sc,tx2x_sc,tx2x_sd,tx2x_se,tx2x_sf); -#endif -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - if (tx2x_wind_speed < tx2x_wind_speed_min) { - tx2x_wind_speed_min = tx2x_wind_speed; - } - if (tx2x_wind_speed > tx2x_wind_speed_max) { - tx2x_wind_speed_max = tx2x_wind_speed; - } - - - - - if (tx2x_count <= tx2x_avg_samples) { - tx2x_count++; - } - tx2x_wind_speed_avg -= tx2x_wind_speed_avg / tx2x_count; - tx2x_wind_speed_avg += float(tx2x_wind_speed) / tx2x_count; - - tx2x_wind_direction_avg_x -= tx2x_wind_direction_avg_x / tx2x_count; - tx2x_wind_direction_avg_x += cosf((tx2x_wind_direction*22.5) * tx2x_f_pi180) / tx2x_count; - tx2x_wind_direction_avg_y -= tx2x_wind_direction_avg_y / tx2x_count; - tx2x_wind_direction_avg_y += sinf((tx2x_wind_direction*22.5) * tx2x_f_pi180) / tx2x_count; - tx2x_wind_direction_avg = atan2f(tx2x_wind_direction_avg_y, tx2x_wind_direction_avg_x) * 180.0f / tx2x_f_pi; - if (tx2x_wind_direction_avg<0.0) { - tx2x_wind_direction_avg += 360.0; - } - if (tx2x_wind_direction_avg>360.0) { - tx2x_wind_direction_avg -= 360.0; - } - - int32_t tx2x_wind_direction_avg_int = int((tx2x_wind_direction_avg/22.5)+0.5) % 16; - - - if (tx2x_wind_direction > tx2x_wind_direction_avg_int) { - - if ((tx2x_wind_direction-tx2x_wind_direction_avg_int)>8) { - - if ((tx2x_wind_direction - 16) < tx2x_wind_direction_min) { - - tx2x_wind_direction_min = tx2x_wind_direction - 16; - } - } else { - - if (tx2x_wind_direction > tx2x_wind_direction_max) { - - tx2x_wind_direction_max = tx2x_wind_direction; - } - } - } else { - - if ((tx2x_wind_direction_avg_int-tx2x_wind_direction)>8) { - - if ((tx2x_wind_direction + 16) > tx2x_wind_direction_max) { - - tx2x_wind_direction_max = tx2x_wind_direction + 16; - } - } else { - - if (tx2x_wind_direction < tx2x_wind_direction_min) { - - tx2x_wind_direction_min = tx2x_wind_direction; - } - } - } - -#ifdef DEBUG_TASMOTA_SENSOR - char diravg[FLOATSZ]; - dtostrfd(tx2x_wind_direction_avg, 1, diravg); - char cosx[FLOATSZ]; - dtostrfd(tx2x_wind_direction_avg_x, 1, cosx); - char siny[FLOATSZ]; - dtostrfd(tx2x_wind_direction_avg_y, 1, siny); - DEBUG_SENSOR_LOG(PSTR(D_TX2x_NAME ": dir stat - counter=%ld, actint=%ld, avgint=%ld, avg=%s (cosx=%s, siny=%s), min %d, max %d"), - (uptime-tx2x_last_uptime), - tx2x_wind_direction, - tx2x_wind_direction_avg_int, - diravg, - cosx, - siny, - tx2x_wind_direction_min, - tx2x_wind_direction_max - ); -#endif -#endif - } else { - DEBUG_SENSOR_LOG(PSTR(D_TX2x_NAME ": not available")); - tx2x_wind_speed = 0; - tx2x_wind_direction = 0; -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - tx2x_wind_speed_avg = 0; - tx2x_wind_direction_avg = 0; - Tx2xResetStatData(); -#endif - } - -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - Tx2xCheckSampleCount(); - if (0==Settings.tele_period && (uptime-tx2x_last_uptime)>=tx2x_avg_samples) { - Tx2xResetStat(); - } -#endif -} - -void Tx2xInit(void) -{ - if (!Settings.flag2.speed_conversion) { - Settings.flag2.speed_conversion = 2; - } -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - tx2x_valuesread = false; - Tx2xResetStat(); - Tx2xCheckSampleCount(); -#endif -#ifdef USE_TX23_WIND_SENSOR - tx23_stage = 0; - pinMode(pin[GPIO_TX2X_TXD_BLACK], OUTPUT); - digitalWrite(pin[GPIO_TX2X_TXD_BLACK], LOW); -#else - pinMode(pin[GPIO_TX2X_TXD_BLACK], INPUT); -#endif - attachInterrupt(pin[GPIO_TX2X_TXD_BLACK], TX2xStartRead, RISING); -} - -int32_t Tx2xNormalize(int32_t value) -{ - while (value>15) { - value -= 16; - } - while (value<0) { - value += 16; - } - return value; -} - -void Tx2xShow(bool json) -{ - if (!Tx2xAvailable()) { return; } - - char wind_speed_string[FLOATSZ]; - dtostrfd(ConvertSpeed(tx2x_wind_speed)/10, 1, wind_speed_string); - char wind_direction_string[FLOATSZ]; - dtostrfd(tx2x_wind_direction*22.5, 1, wind_direction_string); - char wind_direction_cardinal_string[TX2X_DIRECTIONS_MAXSIZE+1]; - GetTextIndexed(wind_direction_cardinal_string, sizeof(wind_direction_cardinal_string), tx2x_wind_direction, kTx2xDirections); -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - char wind_speed_min_string[FLOATSZ]; - dtostrfd(ConvertSpeed(tx2x_wind_speed_min)/10, 1, wind_speed_min_string); - char wind_speed_max_string[FLOATSZ]; - dtostrfd(ConvertSpeed(tx2x_wind_speed_max)/10, 1, wind_speed_max_string); - char wind_speed_avg_string[FLOATSZ]; - dtostrfd(ConvertSpeed(tx2x_wind_speed_avg)/10, 1, wind_speed_avg_string); - char wind_direction_avg_string[FLOATSZ]; - dtostrfd(tx2x_wind_direction_avg, 1, wind_direction_avg_string); - char wind_direction_avg_cardinal_string[4]; - GetTextIndexed(wind_direction_avg_cardinal_string, sizeof(wind_direction_avg_cardinal_string), int((tx2x_wind_direction_avg/22.5f)+0.5f) % 16, kTx2xDirections); - char wind_direction_range_string[FLOATSZ]; - dtostrfd(Tx2xNormalize(tx2x_wind_direction_max-tx2x_wind_direction_min)*22.5, 1, wind_direction_range_string); - char wind_direction_min_string[FLOATSZ]; - dtostrfd(Tx2xNormalize(tx2x_wind_direction_min)*22.5, 1, wind_direction_min_string); - char wind_direction_max_string[FLOATSZ]; - dtostrfd(Tx2xNormalize(tx2x_wind_direction_max)*22.5, 1, wind_direction_max_string); -#endif - - if (json) { -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS -#ifdef USE_TX2x_LEGACY_JSON - ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":%s,\"SpeedAvg\":%s,\"SpeedMax\":%s,\"Direction\":\"%s\",\"Degree\":%s}"), - wind_speed_string, - wind_speed_avg_string, - wind_speed_max_string, - wind_direction_cardinal_string, - wind_direction_string - ); -#else - ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":{\"Act\":%s,\"Avg\":%s,\"Min\":%s,\"Max\":%s},\"Dir\":{\"Card\":\"%s\",\"Deg\":%s,\"Avg\":%s,\"AvgCard\":\"%s\",\"Min\":%s,\"Max\":%s,\"Range\":%s}}"), - wind_speed_string, - wind_speed_avg_string, - wind_speed_min_string, - wind_speed_max_string, - wind_direction_cardinal_string, - wind_direction_string, - wind_direction_avg_string, - wind_direction_avg_cardinal_string, - wind_direction_min_string, - wind_direction_max_string, - wind_direction_range_string - ); -#endif -#else -#ifdef USE_TX2x_LEGACY_JSON - ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":%s,\"Direction\":\"%s\",\"Degree\":%s}"), - wind_speed_string, wind_direction_cardinal_string, wind_direction_string); -#else - ResponseAppend_P(PSTR(",\"" D_TX2x_NAME "\":{\"" D_JSON_SPEED "\":{\"Act\":%s},\"Dir\":{\"Card\":\"%s\",\"Deg\":%s}}"), - wind_speed_string, wind_direction_cardinal_string, wind_direction_string); -#endif -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TX2X, - wind_speed_string, - SpeedUnit().c_str(), -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - wind_speed_avg_string, - SpeedUnit().c_str(), - wind_speed_min_string, - SpeedUnit().c_str(), - wind_speed_max_string, - SpeedUnit().c_str(), -#endif - wind_direction_cardinal_string, - wind_direction_string -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - ,wind_direction_avg_cardinal_string, - wind_direction_avg_string, - wind_direction_range_string, - wind_direction_min_string, - wind_direction_max_string -#endif - ); -#endif - } -} - - - - - -bool Xsns35(uint8_t function) -{ - bool result = false; - - if (pin[GPIO_TX2X_TXD_BLACK] < 99) { - switch (function) { - case FUNC_INIT: - Tx2xInit(); - break; - case FUNC_EVERY_SECOND: - Tx2xRead(); - break; -#ifndef USE_TX2X_WIND_SENSOR_NOSTATISTICS - case FUNC_AFTER_TELEPERIOD: - Tx2xResetStat(); - break; -#endif - case FUNC_JSON_APPEND: - Tx2xShow(true); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Tx2xShow(false); - break; -#endif - - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_36_mgc3130.ino" -# 22 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_36_mgc3130.ino" -#ifdef USE_I2C -#ifdef USE_MGC3130 -# 35 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_36_mgc3130.ino" -#define XSNS_36 36 -#define XI2C_27 27 - -#warning **** MGC3130: It is recommended to disable all unneeded I2C-drivers **** - -#define MGC3130_I2C_ADDR 0x42 - -#define MGC3130_xfer pin[GPIO_MGC3130_XFER] -#define MGC3130_reset pin[GPIO_MGC3130_RESET] - - -bool MGC3130_type = false; -char MGC3130stype[] = "MGC3130"; - - -#define MGC3130_SYSTEM_STATUS 0x15 -#define MGC3130_REQUEST_MSG 0x06 -#define MGC3130_FW_VERSION 0x83 -#define MGC3130_SET_RUNTIME 0xA2 -#define MGC3130_SENSOR_DATA 0x91 - - -#define MGC3130_GESTURE_GARBAGE 1 -#define MGC3130_FLICK_WEST_EAST 2 -#define MGC3130_FLICK_EAST_WEST 3 -#define MGC3130_FLICK_SOUTH_NORTH 4 -#define MGC3130_FLICK_NORTH_SOUTH 5 -#define MGC3130_CIRCLE_CLOCKWISE 6 -#define MGC3130_CIRCLE_CCLOCKWISE 7 - -#define MGC3130_MIN_ROTVALUE 0 -#define MGC3130_MAX_ROTVALUE 1023 -#define MGC3130_MIN_ZVALUE 32768 - - -#ifdef USE_WEBSERVER -const char HTTP_MGC_3130_SNS[] PROGMEM = - "{s}" "%s" "{m}%s{e}" - "{s}" "HwRev" "{m}%u.%u{e}" - "{s}" "loaderVer" "{m}%u.%u{e}" - "{s}" "platVer" "{m}%u{e}"; -#endif - - - - - - - -#pragma pack(1) -union MGC3130_Union{ - uint8_t buffer[132]; - struct - { - - uint8_t msgSize; - uint8_t flag; - uint8_t counter; - uint8_t id; - - struct { - uint8_t DSPStatus:1; - uint8_t gestureInfo:1; - uint8_t touchInfo:1; - uint8_t airWheelInfo:1; - uint8_t xyzPosition:1; - uint8_t noisePower:1; - uint8_t reserved:2; - uint8_t electrodeConfiguration:3; - uint8_t CICData:1; - uint8_t SDData:1; - uint16_t reserved2:3; - } outputConfigMask; - uint8_t timestamp; - struct { - uint8_t positionValid:1; - uint8_t airWheelValid:1; - uint8_t rawDataValid:1; - uint8_t noisePowerValid:1; - uint8_t environmentalNoise:1; - uint8_t clipping:1; - uint8_t reserved:1; - uint8_t DSPRunning:1; - } systemInfo; - uint16_t dspInfo; - struct { - uint8_t gestureCode:8; - uint8_t reserved:4; - uint8_t gestureType:4; - uint8_t edgeFlick:1; - uint16_t reserved2:14; - uint8_t gestureInProgress:1; - } gestureInfo; - struct { - uint8_t touchSouth:1; - uint8_t touchWest:1; - uint8_t touchNorth:1; - uint8_t touchEast:1; - uint8_t touchCentre:1; - uint8_t tapSouth:1; - uint8_t tapWest:1; - uint8_t tapNorth:1; - uint8_t tapEast :1; - uint8_t tapCentre:1; - uint8_t doubleTapSouth:1; - uint8_t doubleTapWest:1; - uint8_t doubleTapNorth:1; - uint8_t doubleTapEast:1; - uint8_t doubleTapCentre:1; - uint8_t reserved:1; - uint8_t touchCounter; - uint8_t reserved2; - } touchInfo; - int8_t airWheel; - uint8_t reserved; - uint16_t x; - uint16_t y; - uint16_t z; - float noisePower; - float CICData[4]; - float SDData[4]; - } out; - struct { - uint8_t header[3]; - - uint8_t valid; - uint8_t hwRev[2]; - uint8_t parameterStartAddr; - uint8_t loaderVersion[2]; - uint8_t loaderPlatform; - uint8_t fwStartAddr; - char fwVersion[120]; - } fw; - struct{ - uint8_t id; - uint8_t size; - uint16_t error; - uint32_t reserved; - uint32_t reserved1; - } status; -} MGC_data; -#pragma pack() - -char MGC3130_currentGesture[12]; - -int8_t MGC3130_delta, MGC3130_lastrotation = 0; -int16_t MGC3130_rotValue, MGC3130_lastSentRotValue = 0; - -uint16_t MGC3130_lastSentX, MGC3130_lastSentY, MGC3130_lastSentZ = 0; - -uint8_t hwRev[2], loaderVersion[2], loaderPlatform = 0; -char MGC3130_firmwareInfo[20]; - -uint8_t MGC3130_touchTimeout = 0; -uint16_t MGC3130_touchCounter = 1; -uint32_t MGC3130_touchTimeStamp = millis(); -bool MGC3130_triggeredByTouch = false; - -uint8_t MGC3130_mode = 1; - - - -uint8_t MGC3130autoCal[] = {0x10, 0x00, 0x00, 0xA2, 0x80, 0x00 , 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; -uint8_t MGC3130disableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}; -uint8_t MGC3130enableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}; - -void MGC3130_handleSensorData(){ - if ( MGC_data.out.outputConfigMask.touchInfo && MGC3130_touchTimeout == 0){ - if (MGC3130_handleTouch()){ - MGC3130_triggeredByTouch = true; - MqttPublishSensor(); - } - } - - if(MGC3130_mode == 1){ - if( MGC_data.out.outputConfigMask.gestureInfo && MGC_data.out.gestureInfo.gestureCode > 0){ - MGC3130_handleGesture(); - MqttPublishSensor(); - } - } - if(MGC3130_mode == 2){ - if(MGC_data.out.outputConfigMask.airWheelInfo && MGC_data.out.systemInfo.airWheelValid){ - MGC3130_handleAirWheel(); - MqttPublishSensor(); - } - } - if(MGC3130_mode == 3){ - if(MGC_data.out.systemInfo.positionValid && (MGC_data.out.z > MGC3130_MIN_ZVALUE)){ - MqttPublishSensor(); - } - } -} - -void MGC3130_sendMessage(uint8_t data[], uint8_t length){ - Wire.beginTransmission(MGC3130_I2C_ADDR); - Wire.write(data,length); - Wire.endTransmission(); - delay(2); - MGC3130_receiveMessage(); -} - - -void MGC3130_handleGesture(){ - - char edge[5]; - if (MGC_data.out.gestureInfo.edgeFlick){ - snprintf_P(edge, sizeof(edge), PSTR("ED_")); - } - else{ - snprintf_P(edge, sizeof(edge), PSTR("")); - } - switch(MGC_data.out.gestureInfo.gestureCode){ - case MGC3130_GESTURE_GARBAGE: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("NONE")); - break; - case MGC3130_FLICK_WEST_EAST: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_WE"), edge); - break; - case MGC3130_FLICK_EAST_WEST: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_EW"), edge); - break; - case MGC3130_FLICK_SOUTH_NORTH: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_SN"), edge); - break; - case MGC3130_FLICK_NORTH_SOUTH: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("%sFL_NS"), edge); - break; - case MGC3130_CIRCLE_CLOCKWISE: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("CW")); - break; - case MGC3130_CIRCLE_CCLOCKWISE: - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("CCW")); - break; - } - -} - -bool MGC3130_handleTouch(){ - - bool success = false; - if (MGC_data.out.touchInfo.doubleTapCentre && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_C")); - MGC3130_touchTimeout = 5; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.doubleTapEast && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_E")); - MGC3130_touchTimeout = 5; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.doubleTapNorth && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_N")); - MGC3130_touchTimeout = 5; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.doubleTapWest && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_W")); - MGC3130_touchTimeout = 5; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.doubleTapSouth && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("DT_S")); - MGC3130_touchTimeout = 5; - success = true; - MGC3130_touchCounter = 1; - } - if (MGC_data.out.touchInfo.tapCentre && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_C")); - MGC3130_touchTimeout = 2; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.tapEast && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_E")); - MGC3130_touchTimeout = 2; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.tapNorth && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_N")); - MGC3130_touchTimeout = 2; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.tapWest && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_W")); - MGC3130_touchTimeout = 2; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.tapSouth && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TP_S")); - MGC3130_touchTimeout = 2; - success = true; - MGC3130_touchCounter = 1; - } - else if (MGC_data.out.touchInfo.touchCentre && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_C")); - success = true; - MGC3130_touchCounter++; - } - else if (MGC_data.out.touchInfo.touchEast && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_E")); - success = true; - MGC3130_touchCounter++; - } - else if (MGC_data.out.touchInfo.touchNorth && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_N")); - success = true; - MGC3130_touchCounter++; - } - else if (MGC_data.out.touchInfo.touchWest && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_W")); - success = true; - MGC3130_touchCounter++; - } - else if (MGC_data.out.touchInfo.touchSouth && !success){ - - snprintf_P(MGC3130_currentGesture, sizeof(MGC3130_currentGesture), PSTR("TH_S")); - success = true; - MGC3130_touchCounter++; - } - - return success; -} - -void MGC3130_handleAirWheel(){ - MGC3130_delta = MGC_data.out.airWheel - MGC3130_lastrotation; - MGC3130_lastrotation = MGC_data.out.airWheel; - - MGC3130_rotValue = MGC3130_rotValue + MGC3130_delta; - if(MGC3130_rotValue < MGC3130_MIN_ROTVALUE){ - MGC3130_rotValue = MGC3130_MIN_ROTVALUE; - } - if(MGC3130_rotValue > MGC3130_MAX_ROTVALUE){ - MGC3130_rotValue = MGC3130_MAX_ROTVALUE; - } -} - -void MGC3130_handleSystemStatus(){ - -} - -bool MGC3130_receiveMessage(){ - if(MGC3130_readData()){ - switch(MGC_data.out.id){ - case MGC3130_SENSOR_DATA: - MGC3130_handleSensorData(); - break; - case MGC3130_SYSTEM_STATUS: - MGC3130_handleSystemStatus(); - break; - case MGC3130_FW_VERSION: - hwRev[0] = MGC_data.fw.hwRev[1]; - hwRev[1] = MGC_data.fw.hwRev[0]; - loaderVersion[0] = MGC_data.fw.loaderVersion[0]; - loaderVersion[1] = MGC_data.fw.loaderVersion[1]; - loaderPlatform = MGC_data.fw.loaderPlatform; - snprintf_P(MGC3130_firmwareInfo, sizeof(MGC3130_firmwareInfo), PSTR("FW: %s"), MGC_data.fw.fwVersion); - MGC3130_firmwareInfo[20] = '\0'; - - break; - } - return true; - } - return false; -} - -bool MGC3130_readData() -{ - bool success = false; - if (!digitalRead(MGC3130_xfer)){ - pinMode(MGC3130_xfer, OUTPUT); - digitalWrite(MGC3130_xfer, LOW); - Wire.requestFrom(MGC3130_I2C_ADDR, (uint16_t)32); - - MGC_data.buffer[0] = 4; - unsigned char i = 0; - while(Wire.available() && (i < MGC_data.buffer[0])){ - MGC_data.buffer[i] = Wire.read(); - i++; - } - digitalWrite(MGC3130_xfer, HIGH); - pinMode(MGC3130_xfer, INPUT); - success = true; - } - return success; -} - -void MGC3130_nextMode(){ - if (MGC3130_mode < 3){ - MGC3130_mode++; - } - else{ - MGC3130_mode = 1; - } - switch(MGC3130_mode){ - case 1: - MGC3130_sendMessage(MGC3130disableAirwheel,16); - break; - case 2: - MGC3130_sendMessage(MGC3130enableAirwheel,16); - break; - case 3: - MGC3130_sendMessage(MGC3130disableAirwheel,16); - break; - } -} - -void MGC3130_loop() -{ - if(MGC3130_touchTimeout > 0){ - MGC3130_touchTimeout--; - } - MGC3130_receiveMessage(); -} - -void MGC3130_detect(void) -{ - if (MGC3130_type || I2cActive(MGC3130_I2C_ADDR)) { return; } - - pinMode(MGC3130_xfer, INPUT_PULLUP); - pinMode(MGC3130_reset, OUTPUT); - digitalWrite(MGC3130_reset, LOW); - delay(10); - digitalWrite(MGC3130_reset, HIGH); - delay(50); - - if (MGC3130_receiveMessage()) { - I2cSetActiveFound(MGC3130_I2C_ADDR, MGC3130stype); - MGC3130_currentGesture[0] = '\0'; - MGC3130_type = true; - } -} - - - - - -void MGC3130_show(bool json) -{ - if (!MGC3130_type) { return; } - - char status_chr[2]; - if (MGC_data.out.systemInfo.DSPRunning) { - sprintf (status_chr, "1"); - } - else{ - sprintf (status_chr, "0"); - } - - if (json) { - if (MGC3130_mode == 3 && !MGC3130_triggeredByTouch) { - if (MGC_data.out.systemInfo.positionValid && !(MGC_data.out.x == MGC3130_lastSentX && MGC_data.out.y == MGC3130_lastSentY && MGC_data.out.z == MGC3130_lastSentZ)) { - ResponseAppend_P(PSTR(",\"%s\":{\"X\":%u,\"Y\":%u,\"Z\":%u}"), - MGC3130stype, MGC_data.out.x/64, MGC_data.out.y/64, (MGC_data.out.z-(uint16_t)MGC3130_MIN_ZVALUE)/64); - MGC3130_lastSentX = MGC_data.out.x; - MGC3130_lastSentY = MGC_data.out.y; - MGC3130_lastSentZ = MGC_data.out.z; - } - } - MGC3130_triggeredByTouch = false; - - if (MGC3130_mode == 2) { - if (MGC_data.out.systemInfo.airWheelValid && (MGC3130_rotValue != MGC3130_lastSentRotValue)) { - ResponseAppend_P(PSTR(",\"%s\":{\"AW\":%i}"), MGC3130stype, MGC3130_rotValue); - MGC3130_lastSentRotValue = MGC3130_rotValue; - } - } - - if (MGC3130_currentGesture[0] != '\0') { - if (millis() - MGC3130_touchTimeStamp > 220 ) { - MGC3130_touchCounter = 1; - } - ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%u}"), MGC3130stype, MGC3130_currentGesture, MGC3130_touchCounter); - MGC3130_currentGesture[0] = '\0'; - MGC3130_touchTimeStamp = millis(); - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_MGC_3130_SNS, MGC3130stype, status_chr, hwRev[0], hwRev[1], loaderVersion[0], loaderVersion[1], loaderPlatform ); -#endif - } -} -# 557 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_36_mgc3130.ino" -bool MGC3130CommandSensor() -{ - bool serviced = true; - - switch (XdrvMailbox.payload) { - case 0: - MGC3130_nextMode(); - break; - case 1: - MGC3130_mode = 1; - MGC3130_sendMessage(MGC3130disableAirwheel,16); - break; - case 2: - MGC3130_mode = 2; - MGC3130_sendMessage(MGC3130enableAirwheel,16); - break; - case 3: - MGC3130_mode = 3; - MGC3130_sendMessage(MGC3130disableAirwheel,16); - break; - } - return serviced; -} - - - - - -bool Xsns36(uint8_t function) -{ - if (!I2cEnabled(XI2C_27)) { return false; } - - bool result = false; - - if ((FUNC_INIT == function) && (pin[GPIO_MGC3130_XFER] < 99) && (pin[GPIO_MGC3130_RESET] < 99)) { - MGC3130_detect(); - } - else if (MGC3130_type) { - switch (function) { - case FUNC_EVERY_50_MSECOND: - MGC3130_loop(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_36 == XdrvMailbox.index) { - result = MGC3130CommandSensor(); - } - break; - case FUNC_JSON_APPEND: - MGC3130_show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MGC3130_show(0); - break; -#endif - } - } - return result; -} -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_37_rfsensor.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_37_rfsensor.ino" -#ifdef USE_RF_SENSOR -# 33 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_37_rfsensor.ino" -#define XSNS_37 37 - - - - -#define RFSNS_VALID_WINDOW 1800 - -#define RFSNS_LOOPS_PER_MILLI 1900 -#define RFSNS_RAW_BUFFER_SIZE 180 -#define RFSNS_MIN_RAW_PULSES 112 - -#define RFSNS_MIN_PULSE_LENGTH 300 -#define RFSNS_RAWSIGNAL_SAMPLE 50 -#define RFSNS_SIGNAL_TIMEOUT 10 -#define RFSNS_SIGNAL_REPEAT_TIME 500 - -typedef struct RawSignalStruct -{ - int Number; - uint8_t Repeats; - uint8_t Multiply; - unsigned long Time; - uint8_t Pulses[RFSNS_RAW_BUFFER_SIZE+2]; - -} raw_signal_t; - -raw_signal_t *rfsns_raw_signal = nullptr; -uint8_t rfsns_rf_bit; -uint8_t rfsns_rf_port; -uint8_t rfsns_any_sensor = 0; - - - - - -bool RfSnsFetchSignal(uint8_t DataPin, bool StateSignal) -{ - uint8_t Fbit = digitalPinToBitMask(DataPin); - uint8_t Fport = digitalPinToPort(DataPin); - uint8_t FstateMask = (StateSignal ? Fbit : 0); - - if ((*portInputRegister(Fport) & Fbit) == FstateMask) { - const unsigned long LoopsPerMilli = RFSNS_LOOPS_PER_MILLI; - - - - - - - unsigned long PulseLength = 0; - if (rfsns_raw_signal->Time) { - if (rfsns_raw_signal->Repeats && (rfsns_raw_signal->Time + RFSNS_SIGNAL_REPEAT_TIME) > millis()) { - PulseLength = micros() + RFSNS_SIGNAL_TIMEOUT *1000; - while (((rfsns_raw_signal->Time + RFSNS_SIGNAL_REPEAT_TIME) > millis()) && (PulseLength > micros())) { - if ((*portInputRegister(Fport) & Fbit) == FstateMask) { - PulseLength = micros() + RFSNS_SIGNAL_TIMEOUT *1000; - } - } - while (((rfsns_raw_signal->Time + RFSNS_SIGNAL_REPEAT_TIME) > millis()) && ((*portInputRegister(Fport) & Fbit) != FstateMask)); - } - } - - int RawCodeLength = 1; - bool Ftoggle = false; - unsigned long numloops = 0; - unsigned long maxloops = RFSNS_SIGNAL_TIMEOUT * LoopsPerMilli; - rfsns_raw_signal->Multiply = RFSNS_RAWSIGNAL_SAMPLE; - do { - numloops = 0; - while(((*portInputRegister(Fport) & Fbit) == FstateMask) ^ Ftoggle) { - if (numloops++ == maxloops) { break; } - } - PulseLength = (numloops *1000) / LoopsPerMilli; - if (PulseLength < RFSNS_MIN_PULSE_LENGTH) { break; } - Ftoggle = !Ftoggle; - rfsns_raw_signal->Pulses[RawCodeLength++] = PulseLength / (unsigned long)rfsns_raw_signal->Multiply; - } - while(RawCodeLength < RFSNS_RAW_BUFFER_SIZE && numloops <= maxloops); - - if ((RawCodeLength >= RFSNS_MIN_RAW_PULSES) && (RawCodeLength < RFSNS_RAW_BUFFER_SIZE -1)) { - rfsns_raw_signal->Repeats = 0; - rfsns_raw_signal->Number = RawCodeLength -1; - rfsns_raw_signal->Pulses[rfsns_raw_signal->Number] = 0; - rfsns_raw_signal->Time = millis(); - return true; - } - else - rfsns_raw_signal->Number = 0; - } - - return false; -} - -#ifdef USE_THEO_V2 -# 149 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_37_rfsensor.ino" -#define RFSNS_THEOV2_MAX_CHANNEL 2 - -#define RFSNS_THEOV2_PULSECOUNT 114 -#define RFSNS_THEOV2_RF_PULSE_MID 1000 - -typedef struct { - uint32_t time; - int16_t temp; - uint16_t lux; - uint8_t volt; -} theo_v2_t1_t; - -typedef struct { - uint32_t time; - int16_t temp; - uint16_t hum; - uint8_t volt; -} theo_v2_t2_t; - -theo_v2_t1_t *rfsns_theo_v2_t1 = nullptr; -theo_v2_t2_t *rfsns_theo_v2_t2 = nullptr; - -void RfSnsInitTheoV2(void) -{ - rfsns_theo_v2_t1 = (theo_v2_t1_t*)malloc(RFSNS_THEOV2_MAX_CHANNEL * sizeof(theo_v2_t1_t)); - rfsns_theo_v2_t2 = (theo_v2_t2_t*)malloc(RFSNS_THEOV2_MAX_CHANNEL * sizeof(theo_v2_t2_t)); - rfsns_any_sensor++; -} - -void RfSnsAnalyzeTheov2(void) -{ - if (rfsns_raw_signal->Number != RFSNS_THEOV2_PULSECOUNT) { return; } - - uint8_t Checksum; - uint8_t Channel; - uint8_t Type; - uint8_t Voltage; - int Payload1; - int Payload2; - - uint8_t b, bytes, bits, id; - - uint8_t idx = 3; - uint8_t chksum = 0; - for (bytes = 0; bytes < 7; bytes++) { - b = 0; - for (bits = 0; bits <= 7; bits++) - { - if ((rfsns_raw_signal->Pulses[idx] * rfsns_raw_signal->Multiply) > RFSNS_THEOV2_RF_PULSE_MID) { - b |= 1 << bits; - } - idx += 2; - } - if (bytes > 0) { chksum += b; } - - switch (bytes) { - case 0: - Checksum = b; - break; - case 1: - id = b; - Channel = b & 0x7; - Type = (b >> 3) & 0x1f; - break; - case 2: - Voltage = b; - break; - case 3: - Payload1 = b; - break; - case 4: - Payload1 = (b << 8) | Payload1; - break; - case 5: - Payload2 = b; - break; - case 6: - Payload2 = (b << 8) | Payload2; - break; - } - } - - if (Checksum != chksum) { return; } - if ((Channel == 0) || (Channel > RFSNS_THEOV2_MAX_CHANNEL)) { return; } - Channel--; - - rfsns_raw_signal->Repeats = 1; - - int Payload3 = Voltage & 0x3f; - - switch (Type) { - case 1: - rfsns_theo_v2_t1[Channel].time = LocalTime(); - rfsns_theo_v2_t1[Channel].volt = Payload3; - rfsns_theo_v2_t1[Channel].temp = Payload1; - rfsns_theo_v2_t1[Channel].lux = Payload2; - break; - case 2: - rfsns_theo_v2_t2[Channel].time = LocalTime(); - rfsns_theo_v2_t2[Channel].volt = Payload3; - rfsns_theo_v2_t2[Channel].temp = Payload1; - rfsns_theo_v2_t2[Channel].hum = Payload2; - break; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFS: TheoV2, ChkCalc %d, Chksum %d, id %d, Type %d, Ch %d, Volt %d, BattLo %d, Pld1 %d, Pld2 %d"), - chksum, Checksum, id, Type, Channel +1, Payload3, (Voltage & 0x80) >> 7, Payload1, Payload2); -} - -void RfSnsTheoV2Show(bool json) -{ - bool sensor_once = false; - - for (uint32_t i = 0; i < RFSNS_THEOV2_MAX_CHANNEL; i++) { - if (rfsns_theo_v2_t1[i].time) { - char sensor[10]; - snprintf_P(sensor, sizeof(sensor), PSTR("TV2T1C%d"), i +1); - char voltage[33]; - dtostrfd((float)rfsns_theo_v2_t1[i].volt / 10, 1, voltage); - - if (rfsns_theo_v2_t1[i].time < LocalTime() - RFSNS_VALID_WINDOW) { - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_RFRECEIVED "\":\"%s\",\"" D_JSON_VOLTAGE "\":%s}"), - sensor, GetDT(rfsns_theo_v2_t1[i].time).c_str(), voltage); - } - } else { - char temperature[33]; - dtostrfd(ConvertTemp((float)rfsns_theo_v2_t1[i].temp / 100), Settings.flag2.temperature_resolution, temperature); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_VOLTAGE "\":%s}"), - sensor, temperature, rfsns_theo_v2_t1[i].lux, voltage); -#ifdef USE_DOMOTICZ - if ((0 == tele_period) && !sensor_once) { - DomoticzSensor(DZ_TEMP, temperature); - DomoticzSensor(DZ_ILLUMINANCE, rfsns_theo_v2_t1[i].lux); - sensor_once = true; - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, sensor, temperature, TempUnit()); - WSContentSend_PD(HTTP_SNS_ILLUMINANCE, sensor, rfsns_theo_v2_t1[i].lux); -#endif - } - } - } - } - - sensor_once = false; - for (uint32_t i = 0; i < RFSNS_THEOV2_MAX_CHANNEL; i++) { - if (rfsns_theo_v2_t2[i].time) { - char sensor[10]; - snprintf_P(sensor, sizeof(sensor), PSTR("TV2T2C%d"), i +1); - char voltage[33]; - dtostrfd((float)rfsns_theo_v2_t2[i].volt / 10, 1, voltage); - - if (rfsns_theo_v2_t2[i].time < LocalTime() - RFSNS_VALID_WINDOW) { - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_RFRECEIVED" \":\"%s\",\"" D_JSON_VOLTAGE "\":%s}"), - sensor, GetDT(rfsns_theo_v2_t2[i].time).c_str(), voltage); - } - } else { - float temp = ConvertTemp((float)rfsns_theo_v2_t2[i].temp / 100); - float humi = ConvertHumidity((float)rfsns_theo_v2_t2[i].hum / 100); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{"), sensor); - ResponseAppendTHD(temp, humi); - ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s}"), voltage); - - if ((0 == tele_period) && !sensor_once) { -#ifdef USE_DOMOTICZ - DomoticzTempHumPressureSensor(temp, humi); -#endif -#ifdef USE_KNX - KnxSensor(KNX_TEMPERATURE, temp); - KnxSensor(KNX_HUMIDITY, humi); -#endif - sensor_once = true; - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_THD(sensor, temp, humi); -#endif - } - } - } - } -} - -#endif - -#ifdef USE_ALECTO_V2 -# 389 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_37_rfsensor.ino" -#define RFSNS_DKW2012_PULSECOUNT 176 -#define RFSNS_ACH2010_MIN_PULSECOUNT 160 -#define RFSNS_ACH2010_MAX_PULSECOUNT 160 - -#define D_ALECTOV2 "AlectoV2" - -const char kAlectoV2Directions[] PROGMEM = D_TX20_NORTH "|" - D_TX20_NORTH D_TX20_NORTH D_TX20_EAST "|" - D_TX20_NORTH D_TX20_EAST "|" - D_TX20_EAST D_TX20_NORTH D_TX20_EAST "|" - D_TX20_EAST "|" - D_TX20_EAST D_TX20_SOUTH D_TX20_EAST "|" - D_TX20_SOUTH D_TX20_EAST "|" - D_TX20_SOUTH D_TX20_SOUTH D_TX20_EAST "|" - D_TX20_SOUTH "|" - D_TX20_SOUTH D_TX20_SOUTH D_TX20_WEST "|" - D_TX20_SOUTH D_TX20_WEST "|" - D_TX20_WEST D_TX20_SOUTH D_TX20_WEST "|" - D_TX20_WEST "|" - D_TX20_WEST D_TX20_NORTH D_TX20_WEST "|" - D_TX20_NORTH D_TX20_WEST "|" - D_TX20_NORTH D_TX20_NORTH D_TX20_WEST; - -typedef struct { - uint32_t time; - float temp; - float rain; - float wind; - float gust; - uint8_t type; - uint8_t humi; - uint8_t wdir; -} alecto_v2_t; - -alecto_v2_t *rfsns_alecto_v2 = nullptr; -uint16_t rfsns_alecto_rain_base = 0; - -void RfSnsInitAlectoV2(void) -{ - rfsns_alecto_v2 = (alecto_v2_t*)malloc(sizeof(alecto_v2_t)); - rfsns_any_sensor++; -} - -void RfSnsAnalyzeAlectov2() -{ - if (!(((rfsns_raw_signal->Number >= RFSNS_ACH2010_MIN_PULSECOUNT) && - (rfsns_raw_signal->Number <= RFSNS_ACH2010_MAX_PULSECOUNT)) || (rfsns_raw_signal->Number == RFSNS_DKW2012_PULSECOUNT))) { return; } - - uint8_t c = 0; - uint8_t rfbit; - uint8_t data[9] = { 0 }; - uint8_t msgtype = 0; - uint8_t rc = 0; - int temp; - uint8_t checksum = 0; - uint8_t checksumcalc = 0; - uint8_t maxidx = 8; - unsigned long atime; - float factor; - char buf1[16]; - - if (rfsns_raw_signal->Number > RFSNS_ACH2010_MAX_PULSECOUNT) { maxidx = 9; } - - uint8_t idx = maxidx; - for (uint32_t x = rfsns_raw_signal->Number; x > 0; x = x-2) { - if (rfsns_raw_signal->Pulses[x-1] * rfsns_raw_signal->Multiply < 0x300) { - rfbit = 0x80; - } else { - rfbit = 0; - } - data[idx] = (data[idx] >> 1) | rfbit; - c++; - if (c == 8) { - if (idx == 0) { break; } - c = 0; - idx--; - } - } - - checksum = data[maxidx]; - checksumcalc = RfSnsAlectoCRC8(data, maxidx); - - msgtype = (data[0] >> 4) & 0xf; - rc = (data[0] << 4) | (data[1] >> 4); - - if (checksum != checksumcalc) { return; } - if ((msgtype != 10) && (msgtype != 5)) { return; } - - rfsns_raw_signal->Repeats = 1; - - - - - - factor = 1.22; - - - - - - rfsns_alecto_v2->time = LocalTime(); - rfsns_alecto_v2->type = (RFSNS_DKW2012_PULSECOUNT == rfsns_raw_signal->Number); - rfsns_alecto_v2->temp = (float)(((data[1] & 0x3) * 256 + data[2]) - 400) / 10; - rfsns_alecto_v2->humi = data[3]; - uint16_t rain = (data[6] * 256) + data[7]; - - if (rain < rfsns_alecto_rain_base) { rfsns_alecto_rain_base = rain; } - if (rfsns_alecto_rain_base > 0) { - rfsns_alecto_v2->rain += ((float)rain - rfsns_alecto_rain_base) * 0.30; - } - rfsns_alecto_rain_base = rain; - rfsns_alecto_v2->wind = (float)data[4] * factor; - rfsns_alecto_v2->gust = (float)data[5] * factor; - if (rfsns_alecto_v2->type) { - rfsns_alecto_v2->wdir = data[8] & 0xf; - } - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFS: " D_ALECTOV2 ", ChkCalc %d, Chksum %d, rc %d, Temp %d, Hum %d, Rain %d, Wind %d, Gust %d, Dir %d, Factor %s"), - checksumcalc, checksum, rc, ((data[1] & 0x3) * 256 + data[2]) - 400, data[3], (data[6] * 256) + data[7], data[4], data[5], data[8] & 0xf, dtostrfd(factor, 3, buf1)); -} - -void RfSnsAlectoResetRain(void) -{ - if ((RtcTime.hour == 0) && (RtcTime.minute == 0) && (RtcTime.second == 5)) { - rfsns_alecto_v2->rain = 0; - } -} - - - - - - - -uint8_t RfSnsAlectoCRC8(uint8_t *addr, uint8_t len) -{ - uint8_t crc = 0; - while (len--) { - uint8_t inbyte = *addr++; - for (uint32_t i = 8; i; i--) { - uint8_t mix = (crc ^ inbyte) & 0x80; - crc <<= 1; - if (mix) { crc ^= 0x31; } - inbyte <<= 1; - } - } - return crc; -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_ALECTOV2[] PROGMEM = - "{s}" D_ALECTOV2 " " D_RAIN "{m}%s " D_UNIT_MILLIMETER "{e}" - "{s}" D_ALECTOV2 " " D_TX20_WIND_SPEED "{m}%s " D_UNIT_KILOMETER_PER_HOUR "{e}" - "{s}" D_ALECTOV2 " " D_TX20_WIND_SPEED_MAX "{m}%s " D_UNIT_KILOMETER_PER_HOUR "{e}"; -const char HTTP_SNS_ALECTOV2_WDIR[] PROGMEM = - "{s}" D_ALECTOV2 " " D_TX20_WIND_DIRECTION "{m}%s{e}"; -#endif - -void RfSnsAlectoV2Show(bool json) -{ - if (rfsns_alecto_v2->time) { - if (rfsns_alecto_v2->time < LocalTime() - RFSNS_VALID_WINDOW) { - if (json) { - ResponseAppend_P(PSTR(",\"" D_ALECTOV2 "\":{\"" D_JSON_RFRECEIVED "\":\"%s\"}"), GetDT(rfsns_alecto_v2->time).c_str()); - } - } else { - float temp = ConvertTemp(rfsns_alecto_v2->temp); - float humi = ConvertHumidity((float)rfsns_alecto_v2->humi); - - char rain[33]; - dtostrfd(rfsns_alecto_v2->rain, 2, rain); - char wind[33]; - dtostrfd(rfsns_alecto_v2->wind, 2, wind); - char gust[33]; - dtostrfd(rfsns_alecto_v2->gust, 2, gust); - char wdir[4]; - char direction[20]; - if (rfsns_alecto_v2->type) { - GetTextIndexed(wdir, sizeof(wdir), rfsns_alecto_v2->wdir, kAlectoV2Directions); - snprintf_P(direction, sizeof(direction), PSTR(",\"Direction\":\"%s\""), wdir); - } - - if (json) { - ResponseAppend_P(PSTR(",\"" D_ALECTOV2 "\":{")); - ResponseAppendTHD(temp, humi); - ResponseAppend_P(PSTR(",\"Rain\":%s,\"Wind\":%s,\"Gust\":%s%s}"), rain, wind, gust, (rfsns_alecto_v2->type) ? direction : ""); - - if (0 == tele_period) { -#ifdef USE_DOMOTICZ - - - - -#endif - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_THD(D_ALECTOV2, temp, humi); - WSContentSend_PD(HTTP_SNS_ALECTOV2, rain, wind, gust); - if (rfsns_alecto_v2->type) { - WSContentSend_PD(HTTP_SNS_ALECTOV2_WDIR, wdir); - } -#endif - } - } - } -} -#endif - -void RfSnsInit(void) -{ - rfsns_raw_signal = (raw_signal_t*)(malloc(sizeof(raw_signal_t))); - if (rfsns_raw_signal) { - memset(rfsns_raw_signal, 0, sizeof(raw_signal_t)); -#ifdef USE_THEO_V2 - RfSnsInitTheoV2(); -#endif -#ifdef USE_ALECTO_V2 - RfSnsInitAlectoV2(); -#endif - if (rfsns_any_sensor) { - rfsns_rf_bit = digitalPinToBitMask(pin[GPIO_RF_SENSOR]); - rfsns_rf_port = digitalPinToPort(pin[GPIO_RF_SENSOR]); - pinMode(pin[GPIO_RF_SENSOR], INPUT); - } else { - free(rfsns_raw_signal); - rfsns_raw_signal = nullptr; - } - } -} - -void RfSnsAnalyzeRawSignal(void) -{ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFS: Pulses %d"), (int)rfsns_raw_signal->Number); - -#ifdef USE_THEO_V2 - RfSnsAnalyzeTheov2(); -#endif -#ifdef USE_ALECTO_V2 - RfSnsAnalyzeAlectov2(); -#endif -} - -void RfSnsEverySecond(void) -{ -#ifdef USE_ALECTO_V2 - RfSnsAlectoResetRain(); -#endif -} - -void RfSnsShow(bool json) -{ -#ifdef USE_THEO_V2 - RfSnsTheoV2Show(json); -#endif -#ifdef USE_ALECTO_V2 - RfSnsAlectoV2Show(json); -#endif -} - - - - - -bool Xsns37(uint8_t function) -{ - bool result = false; - - if ((pin[GPIO_RF_SENSOR] < 99) && (FUNC_INIT == function)) { - RfSnsInit(); - } - else if (rfsns_raw_signal) { - switch (function) { - case FUNC_LOOP: - if ((*portInputRegister(rfsns_rf_port) &rfsns_rf_bit) == rfsns_rf_bit) { - if (RfSnsFetchSignal(pin[GPIO_RF_SENSOR], HIGH)) { - RfSnsAnalyzeRawSignal(); - } - } - ssleep = 0; - break; - case FUNC_EVERY_SECOND: - RfSnsEverySecond(); - break; - case FUNC_JSON_APPEND: - RfSnsShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - RfSnsShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_38_az7798.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_38_az7798.ino" -#ifdef USE_AZ7798 - -#define XSNS_38 38 -# 112 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_38_az7798.ino" -#include - -#ifndef CO2_LOW -#define CO2_LOW 800 -#endif -#ifndef CO2_HIGH -#define CO2_HIGH 1200 -#endif - -#define AZ_READ_TIMEOUT 400 - -#define AZ_CLOCK_UPDATE_INTERVAL (24UL * 60 * 60) -#define AZ_EPOCH (946684800UL) - -TasmotaSerial *AzSerial; - -const char ktype[] = "AZ7798"; -uint8_t az_type = 1; -uint16_t az_co2 = 0; -double az_temperature = 0; -double az_humidity = 0; -uint8_t az_received = 0; -uint8_t az_state = 0; -unsigned long az_clock_update = 10; - - - -void AzEverySecond(void) -{ - unsigned long start = millis(); - - az_state++; - if (5 == az_state) { - az_state = 0; - - AzSerial->flush(); - AzSerial->write(":\r", 2); - az_received = 0; - - uint8_t az_response[32]; - uint8_t counter = 0; - uint8_t i, j; - uint8_t response_substr[16]; - - do { - if (AzSerial->available() > 0) { - az_response[counter] = AzSerial->read(); - if(az_response[counter] == 0x0d) { az_received = 1; } - counter++; - } else { - delay(5); - } - } while(((millis() - start) < AZ_READ_TIMEOUT) && (counter < sizeof(az_response)) && !az_received); - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, az_response, counter); - - if (!az_received) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 comms timeout")); - return; - } - - i = 0; - while((az_response[i] != 'T') && (i < counter)) {i++;} - if(az_response[i] != 'T') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 failed to find start of response")); - return; - } - i++; - j = 0; - - while((az_response[i] != 'C') && (az_response[i] != 'F') && (i < counter)) { - response_substr[j++] = az_response[i++]; - } - if((az_response[i] != 'C') && (az_response[i] != 'F')){ - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 failed to find end of temperature")); - return; - } - response_substr[j] = 0; - az_temperature = CharToFloat((char*)response_substr); - if(az_response[i] == 'C') { - az_temperature = ConvertTemp((float)az_temperature); - } else { - az_temperature = ConvertTemp((az_temperature - 32) / 1.8); - } - i++; - if(az_response[i] != ':') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 error first delimiter")); - return; - } - i++; - if(az_response[i] != 'C') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 error start of CO2")); - return; - } - i++; - j = 0; - - while((az_response[i] != 'p') && (i < counter)) { - response_substr[j++] = az_response[i++]; - } - if(az_response[i] != 'p') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 failed to find end of CO2")); - return; - } - response_substr[j] = 0; - az_co2 = atoi((char*)response_substr); -#ifdef USE_LIGHT - LightSetSignal(CO2_LOW, CO2_HIGH, az_co2); -#endif - i += 3; - if(az_response[i] != ':') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 error second delimiter")); - return; - } - i++; - if(az_response[i] != 'H') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 error start of humidity")); - return; - } - i++; - j = 0; - - while((az_response[i] != '%') && (i < counter)) { - response_substr[j++] = az_response[i++]; - } - if(az_response[i] != '%') { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 failed to find end of humidity")); - return; - } - response_substr[j] = 0; - az_humidity = ConvertHumidity(CharToFloat((char*)response_substr)); - } - - - if ((az_clock_update == 0) && (LocalTime() > AZ_EPOCH)) { - char tmpString[16]; - sprintf(tmpString, "C %d\r", (int)(LocalTime() - AZ_EPOCH)); - AzSerial->write(tmpString); - - do { - if (AzSerial->available() > 0) { - if(AzSerial->read() == 0x0d) { break; } - } else { - delay(5); - } - } while(((millis() - start) < AZ_READ_TIMEOUT)); - az_clock_update = AZ_CLOCK_UPDATE_INTERVAL; - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "AZ7798 clock updated")); - } else { - az_clock_update--; - } -} - - - -void AzInit(void) -{ - az_type = 0; - if ((pin[GPIO_AZ_RXD] < 99) && (pin[GPIO_AZ_TXD] < 99)) { - AzSerial = new TasmotaSerial(pin[GPIO_AZ_RXD], pin[GPIO_AZ_TXD], 1); - if (AzSerial->begin(9600)) { - if (AzSerial->hardwareSerial()) { ClaimSerial(); } - az_type = 1; - } - } -} - -void AzShow(bool json) -{ - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_CO2 "\":%d,"), ktype, az_co2); - ResponseAppendTHD(az_temperature, az_humidity); - ResponseJsonEnd(); -#ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, az_co2); -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CO2, ktype, az_co2); - WSContentSend_THD(ktype, az_temperature, az_humidity); -#endif - } -} - - - - - -bool Xsns38(uint8_t function) -{ - bool result = false; - - if(az_type){ - switch (function) { - case FUNC_INIT: - AzInit(); - break; - case FUNC_EVERY_SECOND: - AzEverySecond(); - break; - case FUNC_JSON_APPEND: - AzShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - AzShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_39_max31855.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_39_max31855.ino" -#ifdef USE_MAX31855 - -#define XSNS_39 39 - -bool initialized = false; - -struct MAX31855_ResultStruct{ - uint8_t ErrorCode; - float ProbeTemperature; - float ReferenceTemperature; -} MAX31855_Result; - -void MAX31855_Init(void){ - if(initialized) - return; - - - pinMode(pin[GPIO_MAX31855CS], OUTPUT); - pinMode(pin[GPIO_MAX31855CLK], OUTPUT); - pinMode(pin[GPIO_MAX31855DO], INPUT); - - - digitalWrite(pin[GPIO_MAX31855CS], HIGH); - digitalWrite(pin[GPIO_MAX31855CLK], LOW); - - initialized = true; -} - - - - - -void MAX31855_GetResult(void){ - int32_t RawData = MAX31855_ShiftIn(32); - uint8_t probeerror = RawData & 0x7; - - MAX31855_Result.ErrorCode = probeerror; - MAX31855_Result.ReferenceTemperature = MAX31855_GetReferenceTemperature(RawData); - if(probeerror) - MAX31855_Result.ProbeTemperature = NAN; - else - MAX31855_Result.ProbeTemperature = MAX31855_GetProbeTemperature(RawData); -} - - - - - - -float MAX31855_GetProbeTemperature(int32_t RawData){ - if(RawData & 0x80000000) - RawData = (RawData >> 18) | 0xFFFFC000; - else - RawData >>= 18; - - float result = (RawData * 0.25); - - return ConvertTemp(result); -} - - - - - -float MAX31855_GetReferenceTemperature(int32_t RawData){ - if(RawData & 0x8000) - RawData = (RawData >> 4) | 0xFFFFF000; - else - RawData = (RawData >> 4) & 0x00000FFF; - - float result = (RawData * 0.0625); - - return ConvertTemp(result); -} - - - - - -int32_t MAX31855_ShiftIn(uint8_t Length){ - int32_t dataIn = 0; - - digitalWrite(pin[GPIO_MAX31855CS], LOW); - delayMicroseconds(1); - - for (uint32_t i = 0; i < Length; i++) - { - digitalWrite(pin[GPIO_MAX31855CLK], LOW); - delayMicroseconds(1); - dataIn <<= 1; - if(digitalRead(pin[GPIO_MAX31855DO])) - dataIn |= 1; - digitalWrite(pin[GPIO_MAX31855CLK], HIGH); - delayMicroseconds(1); - } - - digitalWrite(pin[GPIO_MAX31855CS], HIGH); - digitalWrite(pin[GPIO_MAX31855CLK], LOW); - return dataIn; -} - -void MAX31855_Show(bool Json){ - char probetemp[33]; - char referencetemp[33]; - dtostrfd(MAX31855_Result.ProbeTemperature, Settings.flag2.temperature_resolution, probetemp); - dtostrfd(MAX31855_Result.ReferenceTemperature, Settings.flag2.temperature_resolution, referencetemp); - - if(Json){ - ResponseAppend_P(PSTR(",\"MAX31855\":{\"" D_JSON_PROBETEMPERATURE "\":%s,\"" D_JSON_REFERENCETEMPERATURE "\":%s,\"" D_JSON_ERROR "\":%d}"), \ - probetemp, referencetemp, MAX31855_Result.ErrorCode); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_TEMP, probetemp); - } -#endif -#ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, MAX31855_Result.ProbeTemperature); - } -#endif - } else { -#ifdef USE_WEBSERVER - WSContentSend_PD(HTTP_SNS_TEMP, "MAX31855", probetemp, TempUnit()); -#endif - } -} - - - - - -bool Xsns39(uint8_t function) -{ - bool result = false; - if((pin[GPIO_MAX31855CS] < 99) && (pin[GPIO_MAX31855CLK] < 99) && (pin[GPIO_MAX31855DO] < 99)){ - - switch (function) { - case FUNC_INIT: - MAX31855_Init(); - break; - case FUNC_EVERY_SECOND: - MAX31855_GetResult(); - break; - case FUNC_JSON_APPEND: - MAX31855_Show(true); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MAX31855_Show(false); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_40_pn532.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_40_pn532.ino" -#ifdef USE_PN532_HSU - -#define XSNS_40 40 - -#include - -TasmotaSerial *PN532_Serial; - -#define PN532_INVALID_ACK -1 -#define PN532_TIMEOUT -2 -#define PN532_INVALID_FRAME -3 -#define PN532_NO_SPACE -4 - -#define PN532_PREAMBLE 0x00 -#define PN532_STARTCODE1 0x00 -#define PN532_STARTCODE2 0xFF -#define PN532_POSTAMBLE 0x00 - -#define PN532_HOSTTOPN532 0xD4 -#define PN532_PN532TOHOST 0xD5 - -#define PN532_ACK_WAIT_TIME 0x0A - -#define PN532_COMMAND_GETFIRMWAREVERSION 0x02 -#define PN532_COMMAND_SAMCONFIGURATION 0x14 -#define PN532_COMMAND_RFCONFIGURATION 0x32 -#define PN532_COMMAND_INDATAEXCHANGE 0x40 -#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A - -#define PN532_MIFARE_ISO14443A 0x00 -#define MIFARE_CMD_READ 0x30 -#define MIFARE_CMD_AUTH_A 0x60 -#define MIFARE_CMD_AUTH_B 0x61 -#define MIFARE_CMD_WRITE 0xA0 - -uint8_t pn532_model = 0; -uint8_t pn532_command = 0; -uint8_t pn532_scantimer = 0; - -uint8_t pn532_packetbuffer[64]; - -#ifdef USE_PN532_DATA_FUNCTION -uint8_t pn532_function = 0; -uint8_t pn532_newdata[16]; -uint8_t pn532_newdata_len = 0; -#endif - -void PN532_Init(void) -{ - if ((pin[GPIO_PN532_RXD] < 99) && (pin[GPIO_PN532_TXD] < 99)) { - PN532_Serial = new TasmotaSerial(pin[GPIO_PN532_RXD], pin[GPIO_PN532_TXD], 1); - if (PN532_Serial->begin(115200)) { - if (PN532_Serial->hardwareSerial()) { ClaimSerial(); } - PN532_wakeup(); - uint32_t ver = PN532_getFirmwareVersion(); - if (ver) { - PN532_setPassiveActivationRetries(0xFF); - PN532_SAMConfig(); - pn532_model = 1; - AddLog_P2(LOG_LEVEL_INFO,"NFC: PN532 NFC Reader detected (V%u.%u)",(ver>>16) & 0xFF, (ver>>8) & 0xFF); - } - } - } -} - -int8_t PN532_receive(uint8_t *buf, int len, uint16_t timeout) -{ - int read_bytes = 0; - int ret; - unsigned long start_millis; - while (read_bytes < len) { - start_millis = millis(); - do { - ret = PN532_Serial->read(); - if (ret >= 0) { - break; - } - } while((timeout == 0) || ((millis()- start_millis ) < timeout)); - - if (ret < 0) { - if (read_bytes) { - return read_bytes; - } else { - return PN532_TIMEOUT; - } - } - buf[read_bytes] = (uint8_t)ret; - read_bytes++; - } - return read_bytes; -} - -int8_t PN532_readAckFrame(void) -{ - const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; - uint8_t ackBuf[sizeof(PN532_ACK)]; - - if (PN532_receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0) { - return PN532_TIMEOUT; - } - - if (memcmp(&ackBuf, &PN532_ACK, sizeof(PN532_ACK))) { - return PN532_INVALID_ACK; - } - return 0; -} - -int8_t PN532_writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) -{ - - PN532_Serial->flush(); - - pn532_command = header[0]; - PN532_Serial->write((uint8_t)PN532_PREAMBLE); - PN532_Serial->write((uint8_t)PN532_STARTCODE1); - PN532_Serial->write(PN532_STARTCODE2); - - uint8_t length = hlen + blen + 1; - PN532_Serial->write(length); - PN532_Serial->write(~length + 1); - - PN532_Serial->write(PN532_HOSTTOPN532); - uint8_t sum = PN532_HOSTTOPN532; - - PN532_Serial->write(header, hlen); - for (uint32_t i = 0; i < hlen; i++) { - sum += header[i]; - } - - PN532_Serial->write(body, blen); - for (uint32_t i = 0; i < blen; i++) { - sum += body[i]; - } - - uint8_t checksum = ~sum + 1; - PN532_Serial->write(checksum); - PN532_Serial->write((uint8_t)PN532_POSTAMBLE); - - return PN532_readAckFrame(); -} - -int16_t PN532_readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 50) -{ - uint8_t tmp[3]; - - - if (PN532_receive(tmp, 3, timeout)<=0) { - return PN532_TIMEOUT; - } - if (0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]) { - return PN532_INVALID_FRAME; - } - - - uint8_t length[2]; - if (PN532_receive(length, 2, timeout) <= 0) { - return PN532_TIMEOUT; - } - - if (0 != (uint8_t)(length[0] + length[1])) { - return PN532_INVALID_FRAME; - } - length[0] -= 2; - if (length[0] > len) { - return PN532_NO_SPACE; - } - - - uint8_t cmd = pn532_command + 1; - if (PN532_receive(tmp, 2, timeout) <= 0) { - return PN532_TIMEOUT; - } - if (PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]) { - return PN532_INVALID_FRAME; - } - - if (PN532_receive(buf, length[0], timeout) != length[0]) { - return PN532_TIMEOUT; - } - - uint8_t sum = PN532_PN532TOHOST + cmd; - for (uint32_t i=0; i status) { - return 0; - } - - response = pn532_packetbuffer[0]; - response <<= 8; - response |= pn532_packetbuffer[1]; - response <<= 8; - response |= pn532_packetbuffer[2]; - response <<= 8; - response |= pn532_packetbuffer[3]; - - return response; -} - -void PN532_wakeup(void) -{ - uint8_t wakeup[5] = {0x55, 0x55, 0, 0, 0 }; - PN532_Serial->write(wakeup,sizeof(wakeup)); - - - PN532_Serial->flush(); -} - -bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 50) -{ - pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; - pn532_packetbuffer[1] = 1; - pn532_packetbuffer[2] = cardbaudrate; - if (PN532_writeCommand(pn532_packetbuffer, 3)) { - return 0x0; - } - - if (PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { - return 0x0; - } -# 274 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_40_pn532.ino" - if (pn532_packetbuffer[0] != 1) { - return 0; - } - - uint16_t sens_res = pn532_packetbuffer[2]; - sens_res <<= 8; - sens_res |= pn532_packetbuffer[3]; - - - *uidLength = pn532_packetbuffer[5]; - - for (uint32_t i = 0; i < pn532_packetbuffer[5]; i++) { - uid[i] = pn532_packetbuffer[6 + i]; - } - - return 1; -} - -bool PN532_setPassiveActivationRetries(uint8_t maxRetries) -{ - pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION; - pn532_packetbuffer[1] = 5; - pn532_packetbuffer[2] = 0xFF; - pn532_packetbuffer[3] = 0x01; - pn532_packetbuffer[4] = maxRetries; - if (PN532_writeCommand(pn532_packetbuffer, 5)) { - return 0; - } - return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); -} - -bool PN532_SAMConfig(void) -{ - pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; - pn532_packetbuffer[1] = 0x01; - pn532_packetbuffer[2] = 0x14; - pn532_packetbuffer[3] = 0x00; - if (PN532_writeCommand(pn532_packetbuffer, 4)) { - return false; - } - return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); -} - -#ifdef USE_PN532_DATA_FUNCTION - -uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) -{ - uint8_t i; - uint8_t _key[6]; - uint8_t _uid[7]; - uint8_t _uidLen; - - - memcpy(&_key, keyData, 6); - memcpy(&_uid, uid, uidLen); - _uidLen = uidLen; - - - pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_packetbuffer[1] = 1; - pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; - pn532_packetbuffer[3] = blockNumber; - memcpy(&pn532_packetbuffer[4], &_key, 6); - for (i = 0; i < _uidLen; i++) { - pn532_packetbuffer[10 + i] = _uid[i]; - } - - if (PN532_writeCommand(pn532_packetbuffer, 10 + _uidLen)) { return 0; } - - - PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); - - - - - if (pn532_packetbuffer[0] != 0x00) { - - return 0; - } - - return 1; -} - -uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) -{ - - pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_packetbuffer[1] = 1; - pn532_packetbuffer[2] = MIFARE_CMD_READ; - pn532_packetbuffer[3] = blockNumber; - - - if (PN532_writeCommand(pn532_packetbuffer, 4)) { - return 0; - } - - - PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); - - - if (pn532_packetbuffer[0] != 0x00) { - return 0; - } - - - - memcpy (data, &pn532_packetbuffer[1], 16); - - return 1; -} - -uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) -{ - - pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_packetbuffer[1] = 1; - pn532_packetbuffer[2] = MIFARE_CMD_WRITE; - pn532_packetbuffer[3] = blockNumber; - memcpy(&pn532_packetbuffer[4], data, 16); - - - if (PN532_writeCommand(pn532_packetbuffer, 20)) { - return 0; - } - - - return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); -} - -#endif - -void PN532_ScanForTag(void) -{ - if (!pn532_model) { return; } - uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; - uint8_t uid_len = 0; - uint8_t card_data[16]; - bool erase_success = false; - bool set_success = false; - if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) { - char uids[15]; - -#ifdef USE_PN532_DATA_FUNCTION - char card_datas[34]; -#endif - - ToHex_P((unsigned char*)uid, uid_len, uids, sizeof(uids)); - -#ifdef USE_PN532_DATA_FUNCTION - if (uid_len == 4) { - uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { - if (mifareclassic_ReadDataBlock(1, card_data)) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_datas,&card_data,sizeof(card_data)); -#else - for (uint32_t i = 0;i < sizeof(card_data);i++) { - if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { - card_datas[i] = char(card_data[i]); - } else { - card_datas[i] = '\0'; - } - } -#endif - } - if (pn532_function == 1) { - for (uint32_t i = 0;i<16;i++) { - card_data[i] = 0x00; - } - if (mifareclassic_WriteDataBlock(1, card_data)) { - erase_success = true; - AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase success")); - memcpy(&card_datas,&card_data,sizeof(card_data)); - } - } - if (pn532_function == 2) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_data,&pn532_newdata,sizeof(card_data)); - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful")); - memcpy(&card_datas,&card_data,sizeof(card_data)); - } -#else - bool IsAlphaNumeric = true; - for (uint32_t i = 0;i < pn532_newdata_len;i++) { - if ((!isalpha(pn532_newdata[i])) && (!isdigit(pn532_newdata[i]))) { - IsAlphaNumeric = false; - } - } - if (IsAlphaNumeric) { - memcpy(&card_data,&pn532_newdata,pn532_newdata_len); - card_data[pn532_newdata_len] = '\0'; - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful")); - memcpy(&card_datas,&card_data,sizeof(card_data)); - } - } else { - AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data must be alphanumeric")); - } -#endif - } - } else { - sprintf(card_datas,"AUTHFAIL"); - } - } - switch (pn532_function) { - case 0x01: - if (!erase_success) { - AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase fail - exiting erase mode")); - } - break; - case 0x02: - if (!set_success) { - AddLog_P(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Write failed - exiting set mode")); - } - default: - break; - } - pn532_function = 0; -#endif - -#ifdef USE_PN532_DATA_FUNCTION - ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), uids, card_datas); -#else - ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\"}}"), uids); -#endif - - MqttPublishTeleSensor(); - -#ifdef USE_PN532_CAUSE_EVENTS - - char command[71]; -#ifdef USE_PN532_DATA_FUNCTION - sprintf(command,"backlog event PN532_UID=%s;event PN532_DATA=%s",uids,card_datas); -#else - sprintf(command,"event PN532_UID=%s",uids); -#endif - ExecuteCommand(command, SRC_RULE); -#endif - - pn532_scantimer = 7; - } -} - -#ifdef USE_PN532_DATA_FUNCTION - -bool PN532_Command(void) -{ - bool serviced = true; - uint8_t paramcount = 0; - if (XdrvMailbox.data_len > 0) { - paramcount=1; - } else { - serviced = false; - return serviced; - } - char sub_string[XdrvMailbox.data_len]; - char sub_string_tmp[XdrvMailbox.data_len]; - for (uint32_t ca=0;ca 1) { - if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { - serviced = false; - return serviced; - } - sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2)); - pn532_newdata_len = strlen(sub_string_tmp); - if (pn532_newdata_len > 15) { pn532_newdata_len = 15; } - memcpy(&pn532_newdata,&sub_string_tmp,pn532_newdata_len); - pn532_newdata[pn532_newdata_len] = 0x00; - pn532_function = 2; - AddLog_P2(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'"), pn532_newdata); - ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"S\"}}")); - return serviced; - } - } -} - -#endif - -bool Xsns40(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_INIT: - PN532_Init(); - result = true; - break; - case FUNC_EVERY_50_MSECOND: - break; - case FUNC_EVERY_100_MSECOND: - break; - case FUNC_EVERY_250_MSECOND: - if (pn532_scantimer > 0) { - pn532_scantimer--; - } else { - PN532_ScanForTag(); - } - break; - case FUNC_EVERY_SECOND: - break; -#ifdef USE_PN532_DATA_FUNCTION - case FUNC_COMMAND_SENSOR: - if (XSNS_40 == XdrvMailbox.index) { - result = PN532_Command(); - } - break; -#endif - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_41_max44009.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_41_max44009.ino" -#ifdef USE_I2C -#ifdef USE_MAX44009 - - - - - - -#define XSNS_41 41 -#define XI2C_28 28 - -#define MAX44009_ADDR1 0x4A -#define MAX44009_ADDR2 0x4B -#define MAX44009_NO_REGISTERS 8 -#define REG_CONFIG 0x02 -#define REG_LUMINANCE 0x03 -#define REG_LOWER_THRESHOLD 0x06 -#define REG_THRESHOLD_TIMER 0x07 - -#define MAX44009_CONTINUOUS_AUTO_MODE 0x80 - -uint8_t max44009_address; -uint8_t max44009_addresses[] = { MAX44009_ADDR1, MAX44009_ADDR2, 0 }; -uint8_t max44009_found = 0; -uint8_t max44009_valid = 0; -float max44009_illuminance = 0; -char max44009_types[] = "MAX44009"; - -bool Max4409Read_lum(void) -{ - max44009_valid = 0; - uint8_t regdata[2]; - - - if (I2cValidRead16((uint16_t *)®data, max44009_address, REG_LUMINANCE)) { - int exponent = (regdata[0] & 0xF0) >> 4; - int mantissa = ((regdata[0] & 0x0F) << 4) | (regdata[1] & 0x0F); - max44009_illuminance = (float)(((0x00000001 << exponent) * (float)mantissa) * 0.045); - max44009_valid = 1; - return true; - } else { - return false; - } -} - - - -void Max4409Detect(void) -{ - uint8_t buffer1; - uint8_t buffer2; - for (uint32_t i = 0; 0 != max44009_addresses[i]; i++) { - - max44009_address = max44009_addresses[i]; - if (I2cActive(max44009_address)) { continue; } - - if ((I2cValidRead8(&buffer1, max44009_address, REG_LOWER_THRESHOLD)) && - (I2cValidRead8(&buffer2, max44009_address, REG_THRESHOLD_TIMER))) { - - if ((0x00 == buffer1) && - (0xFF == buffer2)) { - - - - Wire.beginTransmission(max44009_address); - - - Wire.write(REG_CONFIG); - Wire.write(MAX44009_CONTINUOUS_AUTO_MODE); - if (0 == Wire.endTransmission()) { - I2cSetActiveFound(max44009_address, max44009_types); - max44009_found = 1; - break; - } - } - } - } -} - -void Max4409EverySecond(void) -{ - Max4409Read_lum(); -} - -void Max4409Show(bool json) -{ - char illum_str[8]; - - if (max44009_valid) { - - - - uint8_t prec = 0; - if (10 > max44009_illuminance ) { - prec = 3; - } else if (100 > max44009_illuminance) { - prec = 2; - } else if (1000 > max44009_illuminance) { - prec = 1; - } - dtostrf(max44009_illuminance, sizeof(illum_str) -1, prec, illum_str); - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%s}"), max44009_types, illum_str); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_ILLUMINANCE, illum_str); - } -#endif -#ifdef USE_WEBSERVER - } else { - - WSContentSend_PD(HTTP_SNS_ILLUMINANCE, max44009_types, (int)max44009_illuminance); -#endif - } - } -} - - - - - -bool Xsns41(uint8_t function) -{ - if (!I2cEnabled(XI2C_28)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Max4409Detect(); - } - else if (max44009_found) { - switch (function) { - case FUNC_EVERY_SECOND: - Max4409EverySecond(); - break; - case FUNC_JSON_APPEND: - Max4409Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Max4409Show(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_42_scd30.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_42_scd30.ino" -#ifdef USE_I2C -#ifdef USE_SCD30 - -#define XSNS_42 42 -#define XI2C_29 29 - - - -#define SCD30_ADDRESS 0x61 - -#define SCD30_MAX_MISSED_READS 3 -#define SCD30_STATE_NO_ERROR 0 -#define SCD30_STATE_ERROR_DATA_CRC 1 -#define SCD30_STATE_ERROR_READ_MEAS 2 -#define SCD30_STATE_ERROR_SOFT_RESET 3 -#define SCD30_STATE_ERROR_I2C_RESET 4 -#define SCD30_STATE_ERROR_UNKNOWN 5 - -#include "Arduino.h" -#include - -#define D_CMND_SCD30 "SCD30" - -const char S_JSON_SCD30_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_SCD30 "%s\":%d}"; -const char S_JSON_SCD30_COMMAND_NFW_VALUE[] PROGMEM = "{\"" D_CMND_SCD30 "%s\":%d.%d}"; -const char S_JSON_SCD30_COMMAND[] PROGMEM = "{\"" D_CMND_SCD30 "%s\"}"; -const char kSCD30_Commands[] PROGMEM = "Alt|Auto|Cal|FW|Int|Pres|TOff"; - - - - - -enum SCD30_Commands { - CMND_SCD30_ALTITUDE, - CMND_SCD30_AUTOMODE, - CMND_SCD30_CALIBRATE, - CMND_SCD30_FW, - CMND_SCD30_INTERVAL, - CMND_SCD30_PRESSURE, - CMND_SCD30_TEMPOFFSET -}; - -FrogmoreScd30 scd30; - -bool scd30Found = false; -bool scd30IsDataValid = false; -int scd30ErrorState = SCD30_STATE_NO_ERROR; -uint16_t scd30Interval_sec; -int scd30Loop_count = 0; -int scd30DataNotAvailable_count = 0; -int scd30GoodMeas_count = 0; -int scd30Reset_count = 0; -int scd30CrcError_count = 0; -int scd30Co2Zero_count = 0; -int i2cReset_count = 0; -uint16_t scd30_CO2 = 0; -uint16_t scd30_CO2EAvg = 0; -float scd30_Humid = 0.0; -float scd30_Temp = 0.0; - -void Scd30Detect(void) -{ - if (I2cActive(SCD30_ADDRESS)) { return; } - - scd30.begin(); - - uint8_t major = 0; - uint8_t minor = 0; - if (scd30.getFirmwareVersion(&major, &minor)) { return; } - uint16_t interval_sec; - if (scd30.getMeasurementInterval(&scd30Interval_sec)) { return; } - if (scd30.beginMeasuring()) { return; } - - I2cSetActiveFound(SCD30_ADDRESS, "SCD30"); - scd30Found = true; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SCD: FW v%d.%d"), major, minor); -} - - -void Scd30Update(void) -{ - scd30Loop_count++; - if (scd30Loop_count > (scd30Interval_sec - 1)) { - int error = 0; - switch (scd30ErrorState) { - case SCD30_STATE_NO_ERROR: { - error = scd30.readMeasurement(&scd30_CO2, &scd30_CO2EAvg, &scd30_Temp, &scd30_Humid); - switch (error) { - case ERROR_SCD30_NO_ERROR: - scd30Loop_count = 0; - scd30IsDataValid = true; - scd30GoodMeas_count++; - break; - - case ERROR_SCD30_NO_DATA: - scd30DataNotAvailable_count++; - break; - - case ERROR_SCD30_CRC_ERROR: - scd30ErrorState = SCD30_STATE_ERROR_DATA_CRC; - scd30CrcError_count++; -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: CRC error, CRC error: %ld, CO2 zero: %ld, good: %ld, no data: %ld, sc30_reset: %ld, i2c_reset: %ld"), - scd30CrcError_count, scd30Co2Zero_count, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); -#endif - break; - - case ERROR_SCD30_CO2_ZERO: - scd30Co2Zero_count++; -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: CO2 zero, CRC error: %ld, CO2 zero: %ld, good: %ld, no data: %ld, sc30_reset: %ld, i2c_reset: %ld"), - scd30CrcError_count, scd30Co2Zero_count, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); -#endif - break; - - default: { - scd30ErrorState = SCD30_STATE_ERROR_READ_MEAS; -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: Update: ReadMeasurement error: 0x%lX, counter: %ld"), error, scd30Loop_count); -#endif - return; - } - break; - } - } - break; - - case SCD30_STATE_ERROR_DATA_CRC: { - -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: in error state: %d, good: %ld, no data: %ld, sc30 reset: %ld, i2c reset: %ld"), - scd30ErrorState, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: got CRC error, try again, counter: %ld"), scd30Loop_count); -#endif - scd30ErrorState = ERROR_SCD30_NO_ERROR; - } - break; - - case SCD30_STATE_ERROR_READ_MEAS: { - -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: in error state: %d, good: %ld, no data: %ld, sc30 reset: %ld, i2c reset: %ld"), - scd30ErrorState, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: not answering, sending soft reset, counter: %ld"), scd30Loop_count); -#endif - scd30Reset_count++; - error = scd30.softReset(); - if (error) { -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: resetting got error: 0x%lX"), error); -#endif - error >>= 8; - if (error == 4) { - scd30ErrorState = SCD30_STATE_ERROR_SOFT_RESET; - } else { - scd30ErrorState = SCD30_STATE_ERROR_UNKNOWN; - } - } else { - scd30ErrorState = ERROR_SCD30_NO_ERROR; - } - } - break; - - case SCD30_STATE_ERROR_SOFT_RESET: { - -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: in error state: %d, good: %ld, no data: %ld, sc30 reset: %ld, i2c reset: %ld"), - scd30ErrorState, scd30GoodMeas_count, scd30DataNotAvailable_count, scd30Reset_count, i2cReset_count); - AddLog_P(LOG_LEVEL_ERROR, PSTR("SCD30: clearing i2c bus")); -#endif - i2cReset_count++; - error = scd30.clearI2CBus(); - if (error) { - scd30ErrorState = SCD30_STATE_ERROR_I2C_RESET; -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: error clearing i2c bus: 0x%lX"), error); -#endif - } else { - scd30ErrorState = ERROR_SCD30_NO_ERROR; - } - } - break; - - default: { - -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: unknown error state: 0x%lX"), scd30ErrorState); -#endif - scd30ErrorState = SCD30_STATE_ERROR_SOFT_RESET; - } - } - - if (scd30Loop_count > (SCD30_MAX_MISSED_READS * scd30Interval_sec)) { - scd30IsDataValid = false; - } - } -} - - -int Scd30GetCommand(int command_code, uint16_t *pvalue) -{ - switch (command_code) - { - case CMND_SCD30_ALTITUDE: - return scd30.getAltitudeCompensation(pvalue); - break; - - case CMND_SCD30_AUTOMODE: - return scd30.getCalibrationType(pvalue); - break; - - case CMND_SCD30_CALIBRATE: - return scd30.getForcedRecalibrationFactor(pvalue); - break; - - case CMND_SCD30_INTERVAL: - return scd30.getMeasurementInterval(pvalue); - break; - - case CMND_SCD30_PRESSURE: - return scd30.getAmbientPressure(pvalue); - break; - - case CMND_SCD30_TEMPOFFSET: - return scd30.getTemperatureOffset(pvalue); - break; - - default: - - break; - } -} - -int Scd30SetCommand(int command_code, uint16_t value) -{ - switch (command_code) - { - case CMND_SCD30_ALTITUDE: - return scd30.setAltitudeCompensation(value); - break; - - case CMND_SCD30_AUTOMODE: - return scd30.setCalibrationType(value); - break; - - case CMND_SCD30_CALIBRATE: - return scd30.setForcedRecalibrationFactor(value); - break; - - case CMND_SCD30_INTERVAL: - { - int error = scd30.setMeasurementInterval(value); - if (!error) - { - scd30Interval_sec = value; - } - - return error; - } - break; - - case CMND_SCD30_PRESSURE: - return scd30.setAmbientPressure(value); - break; - - case CMND_SCD30_TEMPOFFSET: - return scd30.setTemperatureOffset(value); - break; - - default: - - break; - } -} - - - - - -bool Scd30CommandSensor() -{ - char command[CMDSZ]; - bool serviced = true; - uint8_t prefix_len = strlen(D_CMND_SCD30); - - if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_SCD30), prefix_len)) { - int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + prefix_len, kSCD30_Commands); - - switch (command_code) { - case CMND_SCD30_ALTITUDE: - case CMND_SCD30_AUTOMODE: - case CMND_SCD30_CALIBRATE: - case CMND_SCD30_INTERVAL: - case CMND_SCD30_PRESSURE: - case CMND_SCD30_TEMPOFFSET: - { - uint16_t value = 0; - if (XdrvMailbox.data_len > 0) - { - value = XdrvMailbox.payload; - Scd30SetCommand(command_code, value); - } - else - { - Scd30GetCommand(command_code, &value); - } - - Response_P(S_JSON_SCD30_COMMAND_NVALUE, command, value); - } - break; - - case CMND_SCD30_FW: - { - uint8_t major = 0; - uint8_t minor = 0; - int error; - error = scd30.getFirmwareVersion(&major, &minor); - if (error) - { -#ifdef SCD30_DEBUG - AddLog_P2(LOG_LEVEL_ERROR, PSTR("SCD30: error getting FW version: 0x%lX"), error); -#endif - serviced = false; - } - else - { - Response_P(S_JSON_SCD30_COMMAND_NFW_VALUE, command, major, minor); - } - } - break; - - default: - - serviced = false; - break; - } - } - return serviced; -} - -void Scd30Show(bool json) -{ - if (scd30IsDataValid) - { - float t = ConvertTemp(scd30_Temp); - float h = ConvertHumidity(scd30_Humid); - - if (json) { - ResponseAppend_P(PSTR(",\"SCD30\":{\"" D_JSON_CO2 "\":%d,\"" D_JSON_ECO2 "\":%d,"), scd30_CO2, scd30_CO2EAvg); - ResponseAppendTHD(t, h); - ResponseJsonEnd(); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_AIRQUALITY, scd30_CO2); - DomoticzTempHumPressureSensor(t, h); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CO2EAVG, "SCD30", scd30_CO2EAvg); - WSContentSend_PD(HTTP_SNS_CO2, "SCD30", scd30_CO2); - WSContentSend_THD("SCD30", t, h); -#endif - } - } -} - - - - - -bool Xsns42(byte function) -{ - if (!I2cEnabled(XI2C_29)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Scd30Detect(); - } - else if (scd30Found) { - switch (function) { - case FUNC_EVERY_SECOND: - Scd30Update(); - break; - case FUNC_COMMAND: - result = Scd30CommandSensor(); - break; - case FUNC_JSON_APPEND: - Scd30Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Scd30Show(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_43_hre.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_43_hre.ino" -#ifdef USE_HRE -# 49 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_43_hre.ino" -#define XSNS_43 43 - -enum hre_states { - hre_idle, - hre_sync, - hre_syncing, - hre_read, - hre_reading, - hre_sleep, - hre_sleeping -}; - -hre_states hre_state = hre_idle; - -float hre_usage = 0; -float hre_rate = 0; -uint32_t hre_usage_time = 0; - -int hre_read_errors = 0; -bool hre_good = false; - - - -int hreReadBit() -{ - digitalWrite(pin[GPIO_HRE_CLOCK], HIGH); - delay(1); - int bit = digitalRead(pin[GPIO_HRE_DATA]); - digitalWrite(pin[GPIO_HRE_CLOCK], LOW); - delay(1); - return bit; -} - - - -char hreReadChar(int &parity_errors) -{ - - hreReadBit(); - - unsigned ch=0; - int sum=0; - for (uint32_t i=0; i<7; i++) - { - int b = hreReadBit(); - ch |= b << i; - sum += b; - } - - - if ( (sum & 0x1) != hreReadBit()) - parity_errors++; - - - hreReadBit(); - - return ch; -} - -void hreInit(void) -{ - hre_read_errors = 0; - hre_good = false; - - pinMode(pin[GPIO_HRE_CLOCK], OUTPUT); - pinMode(pin[GPIO_HRE_DATA], INPUT); - - - - digitalWrite(pin[GPIO_HRE_CLOCK], LOW); - - hre_state = hre_sync; -} - - -void hreEvery50ms(void) -{ - static int sync_counter = 0; - static int sync_run = 0; - - static uint32_t curr_start = 0; - static int read_counter = 0; - static int parity_errors = 0; - static char buff[46]; - - static char ch; - static size_t i; - - switch (hre_state) - { - case hre_sync: - if (uptime < 10) - break; - sync_run = 0; - sync_counter = 0; - hre_state = hre_syncing; - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HRE "hre_state:hre_syncing")); - break; - - case hre_syncing: - - - for (uint32_t i=0; i<20; i++) - { - if (hreReadBit()) - sync_run++; - else - sync_run = 0; - if (sync_run == 62) - { - hre_state = hre_read; - break; - } - sync_counter++; - } - - if (sync_counter > 1000) - { - hre_state = hre_sleep; - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HRE D_ERROR)); - } - break; - - - case hre_read: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HRE "sync_run:%d, sync_counter:%d"), sync_run, sync_counter); - read_counter = 0; - parity_errors = 0; - curr_start = uptime; - memset(buff, 0, sizeof(buff)); - hre_state = hre_reading; - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HRE "hre_state:hre_reading")); - - - - - - case hre_reading: - - buff[read_counter++] = hreReadChar(parity_errors); - buff[read_counter++] = hreReadChar(parity_errors); - - if (read_counter == 46) - { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HRE "pe:%d, re:%d, buff:%s"), - parity_errors, hre_read_errors, buff); - if (parity_errors == 0) - { - float curr_usage; - curr_usage = 0.01 * atol(buff+24); - if (hre_usage_time) - { - double dt = 1.666e-2 * (curr_start - hre_usage_time); - hre_rate = (curr_usage - hre_usage)/dt; - } - hre_usage = curr_usage; - hre_usage_time = curr_start; - hre_good = true; - - hre_state = hre_sleep; - } - else - { - hre_read_errors++; - hre_state = hre_sleep; - } - } - break; - - case hre_sleep: - hre_usage_time = curr_start; - hre_state = hre_sleeping; - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HRE "hre_state:hre_sleeping")); - - case hre_sleeping: - - - if (uptime - hre_usage_time >= 27) - hre_state = hre_sync; - } -} - -void hreShow(boolean json) -{ - if (!hre_good) - return; - - const char *id = "HRE"; - - char usage[16]; - char rate[16]; - dtostrfd(hre_usage, 2, usage); - dtostrfd(hre_rate, 3, rate); - - if (json) - { - ResponseAppend_P(JSON_SNS_GNGPM, id, usage, rate); -#ifdef USE_WEBSERVER - } - else - { - WSContentSend_PD(HTTP_SNS_GALLONS, id, usage); - WSContentSend_PD(HTTP_SNS_GPM, id, rate); -#endif - } -} - - - - - -bool Xsns43(byte function) -{ - - if (pin[GPIO_HRE_CLOCK] >= 99 || pin[GPIO_HRE_DATA] >= 99) - return false; - - switch (function) - { - case FUNC_INIT: - hreInit(); - break; - case FUNC_EVERY_50_MSECOND: - hreEvery50ms(); - break; - case FUNC_EVERY_SECOND: - break; - case FUNC_JSON_APPEND: - hreShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - hreShow(0); - break; -#endif - } - return false; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_44_sps30.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_44_sps30.ino" -#ifdef USE_I2C -#ifdef USE_SPS30 - -#define XSNS_44 44 -#define XI2C_30 30 - -#define SPS30_ADDR 0x69 - -#include -#include - -uint8_t sps30_ready = 0; -uint8_t sps30_running; - -struct SPS30 { - float PM1_0; - float PM2_5; - float PM4_0; - float PM10; - float NCPM0_5; - float NCPM1_0; - float NCPM2_5; - float NCPM4_0; - float NCPM10; - float TYPSIZ; -} sps30_result; - -#define SPS_CMD_START_MEASUREMENT 0x0010 -#define SPS_CMD_START_MEASUREMENT_ARG 0x0300 -#define SPS_CMD_STOP_MEASUREMENT 0x0104 -#define SPS_CMD_READ_MEASUREMENT 0x0300 -#define SPS_CMD_GET_DATA_READY 0x0202 -#define SPS_CMD_AUTOCLEAN_INTERVAL 0x8004 -#define SPS_CMD_CLEAN 0x5607 -#define SPS_CMD_GET_ACODE 0xd025 -#define SPS_CMD_GET_SERIAL 0xd033 -#define SPS_CMD_RESET 0xd304 -#define SPS_WRITE_DELAY_US 20000 -#define SPS_MAX_SERIAL_LEN 32 - -uint8_t sps30_calc_CRC(uint8_t *data) { - uint8_t crc = 0xFF; - for (uint32_t i = 0; i < 2; i++) { - crc ^= data[i]; - for (uint32_t bit = 8; bit > 0; --bit) { - if(crc & 0x80) { - crc = (crc << 1) ^ 0x31u; - } else { - crc = (crc << 1); - } - } - } - return crc; -} - -void CmdClean(void); - -unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop); - -void sps30_get_data(uint16_t cmd, uint8_t *data, uint8_t dlen) { -unsigned char cmdb[2]; -uint8_t tmp[3]; -uint8_t index=0; -memset(data,0,dlen); -uint8_t twi_buff[64]; - - Wire.beginTransmission(SPS30_ADDR); - cmdb[0]=cmd>>8; - cmdb[1]=cmd; - Wire.write(cmdb,2); - Wire.endTransmission(); - - - dlen/=2; - dlen*=3; - - twi_readFrom(SPS30_ADDR,twi_buff,dlen,1); - - uint8_t bind=0; - while (bind>8; - cmdb[1]=cmd; - - if (cmd==SPS_CMD_START_MEASUREMENT) { - cmdb[2]=SPS_CMD_START_MEASUREMENT_ARG>>8; - cmdb[3]=SPS_CMD_START_MEASUREMENT_ARG&0xff; - cmdb[4]=sps30_calc_CRC(&cmdb[2]); - Wire.write(cmdb,5); - } else { - Wire.write(cmdb,2); - } - Wire.endTransmission(); -} - -void SPS30_Detect(void) -{ - if (!I2cSetDevice(SPS30_ADDR)) { return; } - I2cSetActiveFound(SPS30_ADDR, "SPS30"); - - uint8_t dcode[32]; - sps30_get_data(SPS_CMD_GET_SERIAL,dcode,sizeof(dcode)); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("sps30 found with serial: %s"),dcode); - sps30_cmd(SPS_CMD_START_MEASUREMENT); - sps30_running = 1; - sps30_ready = 1; -} - -#define D_UNIT_PM "ug/m3" -#define D_UNIT_NCPM "#/m3" - -#ifdef USE_WEBSERVER -const char HTTP_SNS_SPS30_a[] PROGMEM ="{s}SPS30 " "%s" "{m}%s " D_UNIT_PM "{e}"; -const char HTTP_SNS_SPS30_b[] PROGMEM ="{s}SPS30 " "%s" "{m}%s " D_UNIT_NCPM "{e}"; -const char HTTP_SNS_SPS30_c[] PROGMEM ="{s}SPS30 " "TYPSIZ" "{m}%s " "um" "{e}"; -#endif - -#define PMDP 2 - -#define SPS30_HOURS Settings.sps30_inuse_hours - - - -void SPS30_Every_Second() { - if (!sps30_running) return; - - if (uptime%10==0) { - uint8_t vars[sizeof(float)*10]; - sps30_get_data(SPS_CMD_READ_MEASUREMENT,vars,sizeof(vars)); - float *fp=&sps30_result.PM1_0; - - typedef union { - uint8_t array[4]; - float value; - } ByteToFloat; - - ByteToFloat conv; - - for (uint32_t count=0; count<10; count++) { - for (uint32_t i = 0; i < 4; i++){ - conv.array[3-i] = vars[count*sizeof(float)+i]; - } - *fp++=conv.value; - } - } - - if (uptime%3600==0 && uptime>60) { - - - SPS30_HOURS++; - if (SPS30_HOURS>(7*24)) { - CmdClean(); - SPS30_HOURS=0; - } - } - -} - -void SPS30_Show(bool json) -{ - if (!sps30_running) { return; } - - char str[64]; - if (json) { - dtostrfd(sps30_result.PM1_0,PMDP,str); - ResponseAppend_P(PSTR(",\"SPS30\":{\"" "PM1_0" "\":%s"), str); - dtostrfd(sps30_result.PM2_5,PMDP,str); - ResponseAppend_P(PSTR(",\"" "PM2_5" "\":%s"), str); - dtostrfd(sps30_result.PM4_0,PMDP,str); - ResponseAppend_P(PSTR(",\"" "PM4_0" "\":%s"), str); - dtostrfd(sps30_result.PM10,PMDP,str); - ResponseAppend_P(PSTR(",\"" "PM10" "\":%s"), str); - dtostrfd(sps30_result.NCPM0_5,PMDP,str); - ResponseAppend_P(PSTR(",\"" "NCPM0_5" "\":%s"), str); - dtostrfd(sps30_result.NCPM1_0,PMDP,str); - ResponseAppend_P(PSTR(",\"" "NCPM1_0" "\":%s"), str); - dtostrfd(sps30_result.NCPM2_5,PMDP,str); - ResponseAppend_P(PSTR(",\"" "NCPM2_5" "\":%s"), str); - dtostrfd(sps30_result.NCPM4_0,PMDP,str); - ResponseAppend_P(PSTR(",\"" "NCPM4_0" "\":%s"), str); - dtostrfd(sps30_result.NCPM10,PMDP,str); - ResponseAppend_P(PSTR(",\"" "NCPM10" "\":%s"), str); - dtostrfd(sps30_result.TYPSIZ,PMDP,str); - ResponseAppend_P(PSTR(",\"" "TYPSIZ" "\":%s}"), str); - -#ifdef USE_WEBSERVER - } else { - dtostrfd(sps30_result.PM1_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 1.0",str); - dtostrfd(sps30_result.PM2_5,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 2.5",str); - dtostrfd(sps30_result.PM4_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 4.0",str); - dtostrfd(sps30_result.PM10,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 10",str); - dtostrfd(sps30_result.NCPM0_5,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 0.5",str); - dtostrfd(sps30_result.NCPM1_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 1.0",str); - dtostrfd(sps30_result.NCPM2_5,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 2.5",str); - dtostrfd(sps30_result.NCPM4_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 4.0",str); - dtostrfd(sps30_result.NCPM10,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 10",str); - dtostrfd(sps30_result.TYPSIZ,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_c,str); -#endif - } -} - -void CmdClean(void) -{ - sps30_cmd(SPS_CMD_CLEAN); - ResponseTime_P(PSTR(",\"SPS30\":{\"CFAN\":\"true\"}}")); - MqttPublishTeleSensor(); -} - -bool SPS30_cmd(void) -{ - bool serviced = true; - if (XdrvMailbox.data_len > 0) { - char *cp=XdrvMailbox.data; - if (*cp=='c') { - - CmdClean(); - } else if (*cp=='0' || *cp=='1') { - sps30_running=*cp&1; - sps30_cmd(sps30_running?SPS_CMD_START_MEASUREMENT:SPS_CMD_STOP_MEASUREMENT); - } else { - serviced=false; - } - } - Response_P(PSTR("{\"SPS30\":\"%s\"}"), sps30_running?"running":"stopped"); - - return serviced; -} - - - - - -bool Xsns44(byte function) -{ - if (!I2cEnabled(XI2C_30)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - SPS30_Detect(); - } - else if (sps30_ready) { - switch (function) { - case FUNC_EVERY_SECOND: - SPS30_Every_Second(); - break; - case FUNC_JSON_APPEND: - SPS30_Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - SPS30_Show(0); - break; - #endif - case FUNC_COMMAND_SENSOR: - if (XSNS_44 == XdrvMailbox.index) { - result = SPS30_cmd(); - } - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_45_vl53l0x.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_45_vl53l0x.ino" -#ifdef USE_I2C -#ifdef USE_VL53L0X - -#define XSNS_45 45 -#define XI2C_31 31 - -#include -#include "VL53L0X.h" -VL53L0X sensor; - -uint8_t vl53l0x_ready = 0; -uint16_t vl53l0x_distance; -uint16_t Vl53l0_buffer[5]; -uint8_t Vl53l0_index; - - - -void Vl53l0Detect(void) -{ - if (!I2cSetDevice(0x29)) { return; } - - if (!sensor.init()) { return; } - - I2cSetActiveFound(sensor.getAddress(), "VL53L0X"); - - sensor.setTimeout(500); - - - - - - sensor.startContinuous(); - vl53l0x_ready = 1; - - Vl53l0_index=0; -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_VL53L0X[] PROGMEM = - "{s}VL53L0X " D_DISTANCE "{m}%d" D_UNIT_MILLIMETER "{e}"; -#endif - -#define USE_VL_MEDIAN - -void Vl53l0Every_250MSecond(void) -{ - uint16_t tbuff[5],tmp; - uint8_t flag; - - - uint16_t dist = sensor.readRangeContinuousMillimeters(); - if (dist==0 || dist>2000) { - dist=9999; - } - -#ifdef USE_VL_MEDIAN - - Vl53l0_buffer[Vl53l0_index]=dist; - Vl53l0_index++; - if (Vl53l0_index>=5) Vl53l0_index=0; - - - memmove(tbuff,Vl53l0_buffer,sizeof(tbuff)); - for (byte ocnt=0; ocnt<5; ocnt++) { - flag=0; - for (byte count=0; count<4; count++) { - if (tbuff[count]>tbuff[count+1]) { - tmp=tbuff[count]; - tbuff[count]=tbuff[count+1]; - tbuff[count+1]=tmp; - flag=1; - } - } - if (!flag) break; - } - vl53l0x_distance=tbuff[2]; -#else - vl53l0x_distance=dist; -#endif -} - -void Vl53l0Show(boolean json) -{ - if (json) { - ResponseAppend_P(PSTR(",\"VL53L0X\":{\"" D_JSON_DISTANCE "\":%d}"), vl53l0x_distance); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_VL53L0X, vl53l0x_distance); -#endif - } -} - - - - - -bool Xsns45(byte function) -{ - if (!I2cEnabled(XI2C_31)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Vl53l0Detect(); - } - else if (vl53l0x_ready) { - switch (function) { - case FUNC_EVERY_250_MSECOND: - Vl53l0Every_250MSecond(); - break; - case FUNC_JSON_APPEND: - Vl53l0Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Vl53l0Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_46_MLX90614.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_46_MLX90614.ino" -#ifdef USE_I2C -#ifdef USE_MLX90614 - -#define XSNS_46 46 -#define XI2C_32 32 - -#define I2_ADR_IRT 0x5a - -#define MLX90614_RAWIR1 0x04 -#define MLX90614_RAWIR2 0x05 -#define MLX90614_TA 0x06 -#define MLX90614_TOBJ1 0x07 -#define MLX90614_TOBJ2 0x08 - -struct { - union { - uint16_t value; - uint32_t i2c_buf; - }; - float obj_temp; - float amb_temp; - bool ready = false; -} mlx90614; - -void MLX90614_Init(void) -{ - if (!I2cSetDevice(I2_ADR_IRT)) { return; } - I2cSetActiveFound(I2_ADR_IRT, "MLX90614"); - mlx90614.ready = true; -} - -void MLX90614_Every_Second(void) -{ - mlx90614.i2c_buf = I2cRead24(I2_ADR_IRT, MLX90614_TOBJ1); - if (mlx90614.value & 0x8000) { - mlx90614.obj_temp = -999; - } else { - mlx90614.obj_temp = ((float)mlx90614.value * 0.02) - 273.15; - } - mlx90614.i2c_buf = I2cRead24(I2_ADR_IRT,MLX90614_TA); - if (mlx90614.value & 0x8000) { - mlx90614.amb_temp = -999; - } else { - mlx90614.amb_temp = ((float)mlx90614.value * 0.02) - 273.15; - } -} - -#ifdef USE_WEBSERVER - const char HTTP_IRTMP[] PROGMEM = - "{s}MXL90614 " "OBJ-" D_TEMPERATURE "{m}%s C" "{e}" - "{s}MXL90614 " "AMB-" D_TEMPERATURE "{m}%s C" "{e}"; -#endif - -void MLX90614_Show(uint8_t json) -{ - char obj_tstr[16]; - dtostrfd(mlx90614.obj_temp, Settings.flag2.temperature_resolution, obj_tstr); - char amb_tstr[16]; - dtostrfd(mlx90614.amb_temp, Settings.flag2.temperature_resolution, amb_tstr); - - if (json) { - ResponseAppend_P(PSTR(",\"MLX90614\":{\"OBJTMP\":%s,\"AMBTMP\":%s}"), obj_tstr, amb_tstr); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_IRTMP, obj_tstr, amb_tstr); -#endif - } -} - - - - - -bool Xsns46(byte function) -{ - if (!I2cEnabled(XI2C_32)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - MLX90614_Init(); - } - else if (mlx90614.ready) { - switch (function) { - case FUNC_EVERY_SECOND: - MLX90614_Every_Second(); - break; - case FUNC_JSON_APPEND: - MLX90614_Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MLX90614_Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_47_max31865.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_47_max31865.ino" -#ifdef USE_MAX31865 - -#ifndef USE_SPI -#error "MAX31865 requires USE_SPI enabled" -#endif - -#include "Adafruit_MAX31865.h" - -#define XSNS_47 47 - -#if MAX31865_PTD_WIRES == 4 - #define PTD_WIRES MAX31865_4WIRE -#elif MAX31865_PTD_WIRES == 3 - #define PTD_WIRES MAX31865_3WIRE -#else - #define PTD_WIRES MAX31865_2WIRE -#endif - -int8_t init_status = 0; - -Adafruit_MAX31865 max31865; - -struct MAX31865_Result_Struct { - uint8_t ErrorCode; - uint16_t Rtd; - float PtdResistance; - float PtdTemp; -} MAX31865_Result; - -void MAX31865_Init(void){ - if(init_status) - return; - - max31865.setPins( - pin[GPIO_SSPI_CS], - pin[GPIO_SSPI_MOSI], - pin[GPIO_SSPI_MISO], - pin[GPIO_SSPI_SCLK] - ); - - if(max31865.begin(PTD_WIRES)) - init_status = 1; - else - init_status = -1; -} - - - - - -void MAX31865_GetResult(void){ - uint16_t rtd; - - rtd = max31865.readRTD(); - MAX31865_Result.Rtd = rtd; - MAX31865_Result.PtdResistance = max31865.rtd_to_resistance(rtd, MAX31865_REF_RES); - MAX31865_Result.PtdTemp = max31865.rtd_to_temperature(rtd, MAX31865_PTD_RES, MAX31865_REF_RES) + MAX31865_PTD_BIAS; -} - -void MAX31865_Show(bool Json){ - char temperature[33]; - char resistance[33]; - - dtostrfd(MAX31865_Result.PtdResistance, Settings.flag2.temperature_resolution, resistance); - dtostrfd(MAX31865_Result.PtdTemp, Settings.flag2.temperature_resolution, temperature); - - if(Json){ - ResponseAppend_P(PSTR(",\"MAX31865\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_RESISTANCE "\":%s,\"" D_JSON_ERROR "\":%d}"), \ - temperature, resistance, MAX31865_Result.ErrorCode); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_TEMP, temperature); - } -#endif -#ifdef USE_KNX - if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, MAX31865_Result.PtdTemp); - } -#endif - } else { -#ifdef USE_WEBSERVER - WSContentSend_PD(HTTP_SNS_TEMP, "MAX31865", temperature, TempUnit()); -#endif - } -} - - - - - -bool Xsns47(uint8_t function) -{ - bool result = false; - if((pin[GPIO_SSPI_MISO] < 99) && (pin[GPIO_SSPI_MOSI] < 99) && - (pin[GPIO_SSPI_SCLK] < 99) && (pin[GPIO_SSPI_CS] < 99)) { - - switch (function) { - case FUNC_INIT: - MAX31865_Init(); - break; - - case FUNC_EVERY_SECOND: - MAX31865_GetResult(); - break; - - case FUNC_JSON_APPEND: - MAX31865_Show(true); - break; - -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MAX31865_Show(false); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_48_chirp.ino" -# 35 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_48_chirp.ino" -#ifdef USE_I2C -#ifdef USE_CHIRP -# 47 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_48_chirp.ino" -#define XSNS_48 48 -#define XI2C_33 33 - -#define CHIRP_MAX_SENSOR_COUNT 3 - -#define CHIRP_ADDR_STANDARD 0x20 - - - - - -#define D_CMND_CHIRP "CHIRP" - -const char S_JSON_CHIRP_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_CHIRP "%s\":%d}"; -const char S_JSON_CHIRP_COMMAND[] PROGMEM = "{\"" D_CMND_CHIRP "%s\"}"; -const char kCHIRP_Commands[] PROGMEM = "Select|Set|Scan|Reset|Sleep|Wake"; - -const char kChirpTypes[] PROGMEM = "CHIRP"; - - - - - -enum CHIRP_Commands { - CMND_CHIRP_SELECT, - CMND_CHIRP_SET, - CMND_CHIRP_SCAN, - CMND_CHIRP_RESET, - CMND_CHIRP_SLEEP, - CMND_CHIRP_WAKE }; - - - - - - -#define CHIRP_GET_CAPACITANCE 0x00 -#define CHIRP_SET_ADDRESS 0x01 -#define CHIRP_GET_ADDRESS 0x02 -#define CHIRP_MEASURE_LIGHT 0x03 -#define CHIRP_GET_LIGHT 0x04 -#define CHIRP_GET_TEMPERATURE 0x05 -#define CHIRP_RESET 0x06 -#define CHIRP_GET_VERSION 0x07 -#define CHIRP_SLEEP 0x08 -#define CHIRP_GET_BUSY 0x09 - - - - - -void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg) { - Wire.beginTransmission(addr); - Wire.write(reg); - Wire.endTransmission(); -} - -uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr) { - Wire.requestFrom(addr,(uint8_t)2); - uint16_t t = Wire.read() << 8; - t = t | Wire.read(); - return t; -} - - - - - -uint8_t chirp_current = 0; -uint8_t chirp_found_sensors = 0; - -char chirp_name[7]; -uint8_t chirp_next_job = 0; -uint32_t chirp_timeout_count = 0; - -#pragma pack(1) -struct ChirpSensor_t{ - uint16_t moisture = 0; - uint16_t light = 0; - int16_t temperature = 0; - uint8_t version = 0; - uint8_t address:7; - uint8_t explicitSleep:1; -}; -#pragma pack() - -ChirpSensor_t chirp_sensor[CHIRP_MAX_SENSOR_COUNT]; - - - -void ChirpReset(uint8_t addr) { - ChirpWriteI2CRegister(addr, CHIRP_RESET); -} - - - -void ChirpResetAll(void) { - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version) { - ChirpReset(chirp_sensor[i].address); - } - } -} - - -void ChirpClockSet() { - Wire.setClockStretchLimit(4000); - Wire.setClock(50000); -} - - - -void ChirpSleep(uint8_t addr) { - ChirpWriteI2CRegister(addr, CHIRP_SLEEP); -} -# 185 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_48_chirp.ino" -void ChirpSelect(uint8_t sensor) { - if(sensor < chirp_found_sensors) { - chirp_current = sensor; - DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u now active."), chirp_current); - } - if (sensor == 255) { - DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address); - } -} - - - -uint8_t ChirpReadVersion(uint8_t addr) { - return (I2cRead8(addr, CHIRP_GET_VERSION)); -} - - - -bool ChirpSet(uint8_t addr) { - if(addr < 128){ - if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){ - if(chirp_sensor[chirp_current].version>0x25 && chirp_sensor[chirp_current].version != 255){ - delay(5); - I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr); - - } - DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr); - ChirpReset(chirp_sensor[chirp_current].address); - chirp_sensor[chirp_current].address = addr; - chirp_timeout_count = 10; - chirp_next_job = 0; - if(chirp_sensor[chirp_current].version == 255){ - AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: wrote new address %u, please power off device"), addr); - chirp_sensor[chirp_current].version == 0; - } - return true; - } - } - AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: address %u incorrect and not used"), addr); - return false; -} - - - -bool ChirpScan() -{ - ChirpClockSet(); - chirp_found_sensors = 0; - for (uint8_t address = 1; address <= 127; address++) { - chirp_sensor[chirp_found_sensors].version = 0; - chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); - delay(2); - chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); - if (chirp_sensor[chirp_found_sensors].version > 0) { - I2cSetActiveFound(address, "CHIRP"); - if (chirp_found_sensors 0); -} - - - -void ChirpDetect(void) -{ - if (chirp_next_job > 0) { return; } - - DEBUG_SENSOR_LOG(PSTR("CHIRP: scan will start ...")); - if (ChirpScan()) { - uint8_t chirp_model = 0; - GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes); - } -} - - -void ChirpServiceAllSensors(uint8_t job){ - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) { - DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare for sensor at address 0x%x"), chirp_sensor[i].address); - switch(job){ - case 0: - ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); - break; - case 1: - chirp_sensor[i].moisture = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); - break; - case 2: - ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE); - break; - case 3: - chirp_sensor[i].temperature = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); - break; - case 4: - ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT); - break; - case 5: - ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_LIGHT); - break; - case 6: - chirp_sensor[i].light = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); - break; - default: - break; - } - } - } -} - - - -void ChirpEvery100MSecond(void) -{ - - if(chirp_timeout_count == 0) { - switch(chirp_next_job) { - case 0: - DEBUG_SENSOR_LOG(PSTR("CHIRP: reset all")); - ChirpResetAll(); - chirp_timeout_count = 10; - chirp_next_job++; - break; - case 1: - - - chirp_next_job++; - break; - case 2: - DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read")); - ChirpServiceAllSensors(0); - chirp_timeout_count = 11; - chirp_next_job++; - break; - case 3: - DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read")); - ChirpServiceAllSensors(1); - chirp_next_job++; - break; - case 4: - DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read - 2nd")); - ChirpServiceAllSensors(0); - chirp_timeout_count = 11; - chirp_next_job++; - break; - case 5: - DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read - 2nd")); - ChirpServiceAllSensors(1); - chirp_next_job++; - break; - case 6: - DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read")); - ChirpServiceAllSensors(2); - chirp_timeout_count = 11; - chirp_next_job++; - break; - case 7: - DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read")); - ChirpServiceAllSensors(3); - chirp_next_job++; - break; - case 8: - DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read - 2nd")); - ChirpServiceAllSensors(2); - chirp_timeout_count = 11; - chirp_next_job++; - break; - case 9: - DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read - 2nd")); - ChirpServiceAllSensors(3); - chirp_next_job++; - break; - case 10: - DEBUG_SENSOR_LOG(PSTR("CHIRP: start light measure process")); - ChirpServiceAllSensors(4); - chirp_timeout_count = 90; - chirp_next_job++; - break; - case 11: - DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare light read")); - ChirpServiceAllSensors(5); - chirp_timeout_count = 11; - chirp_next_job++; - break; - case 12: - DEBUG_SENSOR_LOG(PSTR("CHIRP: finish light read")); - ChirpServiceAllSensors(6); - chirp_next_job++; - break; - case 13: - DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); - break; - case 14: - if (Settings.tele_period > 16){ - chirp_timeout_count = (Settings.tele_period - 17) * 10; - DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); - } - else{ - AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !")); - - } - chirp_next_job = 1; - break; - } - } - else { - chirp_timeout_count--; - } -} - - - - -#ifdef USE_WEBSERVER - - -const char HTTP_SNS_DARKNESS[] PROGMEM = "{s} " D_JSON_DARKNESS "{m}%s %%{e}"; -const char HTTP_SNS_CHIRPVER[] PROGMEM = "{s} CHIRP-sensor %u at address{m}0x%x{e}" - "{s} FW-version{m}%s {e}"; ; -const char HTTP_SNS_CHIRPSLEEP[] PROGMEM = "{s} {m} is sleeping ...{e}"; -#endif - - - -void ChirpShow(bool json) -{ - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version) { - - char str_temperature[33]; - double t_temperature = ((double) chirp_sensor[i].temperature )/10.0; - dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); - char str_light[33]; - dtostrfd(chirp_sensor[i].light, 0, str_light); - char str_version[7]; - if(chirp_sensor[i].version == 0xff){ - strncpy_P(str_version, PSTR("Chirp!"), sizeof(str_version)); - } - else{ - sprintf(str_version, "%x", chirp_sensor[i].version); - } - - if (json) { - if(!chirp_sensor[i].explicitSleep) { - ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%d"), chirp_name, i, chirp_sensor[i].moisture); - if(chirp_sensor[i].temperature!=-1){ - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"),str_temperature); - } - ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":%s}"),str_light); - } - else { - ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"),chirp_name, i); - } - #ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzTempHumPressureSensor(t_temperature, chirp_sensor[i].moisture); - DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); - } - #endif - #ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version); - if (chirp_sensor[i].explicitSleep){ - WSContentSend_PD(HTTP_SNS_CHIRPSLEEP); - } - else { - WSContentSend_PD(HTTP_SNS_MOISTURE, "", chirp_sensor[i].moisture); - WSContentSend_PD(HTTP_SNS_DARKNESS, str_light); - if (chirp_sensor[i].temperature!=-1) { - WSContentSend_PD(HTTP_SNS_TEMP, "", str_temperature, TempUnit()); - } - } - - #endif - } - } - } -} - - - - - -bool ChirpCmd(void) { - char command[CMDSZ]; - bool serviced = true; - uint8_t disp_len = strlen(D_CMND_CHIRP); - - if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_CHIRP), disp_len)) { - int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kCHIRP_Commands); - - switch (command_code) { - case CMND_CHIRP_SELECT: - case CMND_CHIRP_SET: - if (XdrvMailbox.data_len > 0) { - if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(XdrvMailbox.payload); } - if (command_code == CMND_CHIRP_SET) { ChirpSet((uint8_t)XdrvMailbox.payload); } - Response_P(S_JSON_CHIRP_COMMAND_NVALUE, command, XdrvMailbox.payload); - } - else { - if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(255); } - Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); - } - break; - case CMND_CHIRP_SCAN: - case CMND_CHIRP_SLEEP: - case CMND_CHIRP_WAKE: - case CMND_CHIRP_RESET: - if (command_code == CMND_CHIRP_SCAN) { chirp_next_job = 0; - ChirpDetect(); } - if (command_code == CMND_CHIRP_SLEEP) { chirp_sensor[chirp_current].explicitSleep = true; - ChirpSleep(chirp_sensor[chirp_current].address); } - if (command_code == CMND_CHIRP_WAKE) { chirp_sensor[chirp_current].explicitSleep = false; - ChirpReadVersion(chirp_sensor[chirp_current].address); } - if (command_code == CMND_CHIRP_RESET) { ChirpReset(chirp_sensor[chirp_current].address); } - Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); - break; - default: - - serviced = false; - break; - } - } - return serviced; -} - - - - - -bool Xsns48(uint8_t function) -{ - if (!I2cEnabled(XI2C_33)) { return false; } - - bool result = false; - - switch (function) { - case FUNC_EVERY_100_MSECOND: - if(chirp_found_sensors > 0){ - ChirpEvery100MSecond(); - } - break; - case FUNC_COMMAND: - result = ChirpCmd(); - break; - case FUNC_JSON_APPEND: - ChirpShow(1); - chirp_next_job = 14; - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - ChirpShow(0); - break; -#endif - case FUNC_INIT: - ChirpDetect(); - break; - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_50_paj7620.ino" -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_50_paj7620.ino" -#ifdef USE_I2C -#ifdef USE_PAJ7620 - - - - - - -#define XSNS_50 50 -#define XI2C_34 34 - -#define PAJ7620_ADDR 0x73 - -#define PAJ7620_BANK_SEL 0xEF - - - -#define PAJ7620_GET_GESTURE 0x43 -#define PAJ7620_PROXIMITY_AVG_Y 0x6c - -#define PAJ7620_OBJECT_CENTER_X 0xad -#define PAJ7620_OBJECT_CENTER_Y 0xaf - -#define PAJ7620_DOWN 1 -#define PAJ7620_UP 2 -#define PAJ7620_RIGHT 4 -#define PAJ7620_LEFT 8 -#define PAJ7620_NEAR 16 -#define PAJ7620_FAR 32 -#define PAJ7620_CW 64 -#define PAJ7620_CCW 128 - - - - -const uint8_t PAJ7620initRegisterArray[][2] PROGMEM = { - {0xEF,0x00}, - {0x32,0x29}, {0x33,0x01}, {0x34,0x00}, {0x35,0x01}, {0x36,0x00}, {0x37,0x07}, {0x38,0x17}, {0x39,0x06}, - {0x3A,0x12}, {0x3F,0x00}, {0x40,0x02}, {0x41,0xFF}, {0x42,0x01}, {0x46,0x2D}, {0x47,0x0F}, {0x48,0x3C}, - {0x49,0x00}, {0x4A,0x1E}, {0x4B,0x00}, {0x4C,0x20}, {0x4D,0x00}, {0x4E,0x1A}, {0x4F,0x14}, {0x50,0x00}, - {0x51,0x10}, {0x52,0x00}, {0x5C,0x02}, {0x5D,0x00}, {0x5E,0x10}, {0x5F,0x3F}, {0x60,0x27}, {0x61,0x28}, - {0x62,0x00}, {0x63,0x03}, {0x64,0xF7}, {0x65,0x03}, {0x66,0xD9}, {0x67,0x03}, {0x68,0x01}, {0x69,0xC8}, - {0x6A,0x40}, {0x6D,0x04}, {0x6E,0x00}, {0x6F,0x00}, {0x70,0x80}, {0x71,0x00}, {0x72,0x00}, {0x73,0x00}, - {0x74,0xF0}, {0x75,0x00}, {0x80,0x42}, {0x81,0x44}, {0x82,0x04}, {0x83,0x20}, {0x84,0x20}, {0x85,0x00}, - {0x86,0x10}, {0x87,0x00}, {0x88,0x05}, {0x89,0x18}, {0x8A,0x10}, {0x8B,0x01}, {0x8C,0x37}, {0x8D,0x00}, - {0x8E,0xF0}, {0x8F,0x81}, {0x90,0x06}, {0x91,0x06}, {0x92,0x1E}, {0x93,0x0D}, {0x94,0x0A}, {0x95,0x0A}, - {0x96,0x0C}, {0x97,0x05}, {0x98,0x0A}, {0x99,0x41}, {0x9A,0x14}, {0x9B,0x0A}, {0x9C,0x3F}, {0x9D,0x33}, - {0x9E,0xAE}, {0x9F,0xF9}, {0xA0,0x48}, {0xA1,0x13}, {0xA2,0x10}, {0xA3,0x08}, {0xA4,0x30}, {0xA5,0x19}, - {0xA6,0x10}, {0xA7,0x08}, {0xA8,0x24}, {0xA9,0x04}, {0xAA,0x1E}, {0xAB,0x1E}, {0xCC,0x19}, {0xCD,0x0B}, - {0xCE,0x13}, {0xCF,0x64}, {0xD0,0x21}, {0xD1,0x0F}, {0xD2,0x88}, {0xE0,0x01}, {0xE1,0x04}, {0xE2,0x41}, - {0xE3,0xD6}, {0xE4,0x00}, {0xE5,0x0C}, {0xE6,0x0A}, {0xE7,0x00}, {0xE8,0x00}, {0xE9,0x00}, {0xEE,0x07}, - {0xEF,0x01}, - {0x00,0x1E}, {0x01,0x1E}, {0x02,0x0F}, {0x03,0x10}, {0x04,0x02}, {0x05,0x00}, {0x06,0xB0}, {0x07,0x04}, - {0x08,0x0D}, {0x09,0x0E}, {0x0A,0x9C}, {0x0B,0x04}, {0x0C,0x05}, {0x0D,0x0F}, {0x0E,0x02}, {0x0F,0x12}, - {0x10,0x02}, {0x11,0x02}, {0x12,0x00}, {0x13,0x01}, {0x14,0x05}, {0x15,0x07}, {0x16,0x05}, {0x17,0x07}, - {0x18,0x01}, {0x19,0x04}, {0x1A,0x05}, {0x1B,0x0C}, {0x1C,0x2A}, {0x1D,0x01}, {0x1E,0x00}, {0x21,0x00}, - {0x22,0x00}, {0x23,0x00}, {0x25,0x01}, {0x26,0x00}, {0x27,0x39}, {0x28,0x7F}, {0x29,0x08}, {0x30,0x03}, - {0x31,0x00}, {0x32,0x1A}, {0x33,0x1A}, {0x34,0x07}, {0x35,0x07}, {0x36,0x01}, {0x37,0xFF}, {0x38,0x36}, - {0x39,0x07}, {0x3A,0x00}, {0x3E,0xFF}, {0x3F,0x00}, {0x40,0x77}, {0x41,0x40}, {0x42,0x00}, {0x43,0x30}, - {0x44,0xA0}, {0x45,0x5C}, {0x46,0x00}, {0x47,0x00}, {0x48,0x58}, {0x4A,0x1E}, {0x4B,0x1E}, {0x4C,0x00}, - {0x4D,0x00}, {0x4E,0xA0}, {0x4F,0x80}, {0x50,0x00}, {0x51,0x00}, {0x52,0x00}, {0x53,0x00}, {0x54,0x00}, - {0x57,0x80}, {0x59,0x10}, {0x5A,0x08}, {0x5B,0x94}, {0x5C,0xE8}, {0x5D,0x08}, {0x5E,0x3D}, {0x5F,0x99}, - {0x60,0x45}, {0x61,0x40}, {0x63,0x2D}, {0x64,0x02}, {0x65,0x96}, {0x66,0x00}, {0x67,0x97}, {0x68,0x01}, - {0x69,0xCD}, {0x6A,0x01}, {0x6B,0xB0}, {0x6C,0x04}, {0x6D,0x2C}, {0x6E,0x01}, {0x6F,0x32}, {0x71,0x00}, - {0x72,0x01}, {0x73,0x35}, {0x74,0x00}, {0x75,0x33}, {0x76,0x31}, {0x77,0x01}, {0x7C,0x84}, {0x7D,0x03}, - {0x7E,0x01}, - {0xEF,0x00} -}; - - - - - -const char kPaj7620Directions[] PROGMEM = "Down|Up|Right|Left|Near|Far|CW|CCW"; - -const uint8_t PAJ7620_PIN[]= {1,2,3,4}; - - - - - -char PAJ7620_name[] = "PAJ7620"; - -uint32_t PAJ7620_timeout_counter = 10; -uint32_t PAJ7620_next_job = 0; -uint32_t PAJ7620_mode = 1; - -struct { - uint8_t current; - uint8_t last; - uint8_t same; - uint8_t unfinished; -} PAJ7620_gesture; - -bool PAJ7620_finished_gesture = false; -char PAJ7620_currentGestureName[6]; - -struct{ - uint8_t x; - uint8_t y; - uint8_t last_x; - uint8_t last_y; - uint8_t proximity; - uint8_t last_proximity; - uint8_t corner; - struct { - uint8_t step:3; - uint8_t countdown:3; - uint8_t valid:1; - } PIN; -} PAJ7620_state; - - - - - -void PAJ7620SelectBank(uint8_t bank) -{ - I2cWrite(PAJ7620_ADDR, PAJ7620_BANK_SEL, bank &1, 1); -} - - - -void PAJ7620DecodeGesture(void) -{ - uint32_t index = 0; - switch (PAJ7620_gesture.current) { - case PAJ7620_LEFT: - index++; - case PAJ7620_RIGHT: - index++; - case PAJ7620_UP: - index++; - case PAJ7620_DOWN: - if (PAJ7620_gesture.unfinished) { - PAJ7620_finished_gesture = true; - break; - } - PAJ7620_gesture.unfinished = PAJ7620_gesture.current; - PAJ7620_timeout_counter = 5; - break; - case PAJ7620_NEAR: - index = 4; - PAJ7620_finished_gesture = true; - PAJ7620_timeout_counter = 25; - break; - case PAJ7620_FAR: - index = 5; - PAJ7620_finished_gesture = true; - PAJ7620_timeout_counter = 25; - break; - case PAJ7620_CW: - index = 6; - PAJ7620_finished_gesture = true; - break; - case PAJ7620_CCW: - index = 7; - PAJ7620_finished_gesture = true; - break; - default: - index = 8; - if (PAJ7620_gesture.unfinished) { - PAJ7620_finished_gesture = true; - } - break; - } - if (index < 8) { - GetTextIndexed(PAJ7620_currentGestureName, sizeof(PAJ7620_currentGestureName), index, kPaj7620Directions); - } - - if (PAJ7620_finished_gesture) { - if (PAJ7620_gesture.unfinished) { - if ((PAJ7620_gesture.current != PAJ7620_NEAR) && (PAJ7620_gesture.current != PAJ7620_FAR)) { - PAJ7620_gesture.current = PAJ7620_gesture.unfinished; - } - } - if (PAJ7620_gesture.current == PAJ7620_gesture.last) { - PAJ7620_gesture.same++; - } else { - PAJ7620_gesture.same = 1; - } - PAJ7620_gesture.last = PAJ7620_gesture.current; - PAJ7620_finished_gesture = false; - PAJ7620_gesture.unfinished = 0; - PAJ7620_timeout_counter += 3; - MqttPublishSensor(); - } -} - - - -void PAJ7620ReadGesture(void) -{ - switch (PAJ7620_mode) { - case 1: - PAJ7620_gesture.current = I2cRead8(PAJ7620_ADDR,PAJ7620_GET_GESTURE); - if ((PAJ7620_gesture.current > 0) || PAJ7620_gesture.unfinished) { - DEBUG_SENSOR_LOG(PSTR("PAJ: gesture: %u"), PAJ7620_gesture.current); - PAJ7620DecodeGesture(); - } - break; - case 2: - PAJ7620_state.proximity = I2cRead8(PAJ7620_ADDR, PAJ7620_PROXIMITY_AVG_Y); - if ((PAJ7620_state.proximity > 0) || (PAJ7620_state.last_proximity > 0)) { - if (PAJ7620_state.proximity != PAJ7620_state.last_proximity) { - PAJ7620_state.last_proximity = PAJ7620_state.proximity; - DEBUG_SENSOR_LOG(PSTR("PAJ: Proximity: %u"), PAJ7620_state.proximity); - MqttPublishSensor(); - } - } - break; - case 3: - case 4: - case 5: - PAJ7620_state.x = I2cRead8(PAJ7620_ADDR, PAJ7620_OBJECT_CENTER_X); - PAJ7620_state.y = I2cRead8(PAJ7620_ADDR, PAJ7620_OBJECT_CENTER_Y); - if ((PAJ7620_state.y > 0) && (PAJ7620_state.x > 0)) { - if ((PAJ7620_state.y != PAJ7620_state.last_y) || (PAJ7620_state.x != PAJ7620_state.last_x)) { - PAJ7620_state.last_y = PAJ7620_state.y; - PAJ7620_state.last_x = PAJ7620_state.x; - DEBUG_SENSOR_LOG(PSTR("PAJ: x: %u y: %u"), PAJ7620_state.x, PAJ7620_state.y); - - PAJ7620_state.corner = 0; - - - - switch (PAJ7620_state.y) { - case 0: case 1: case 2: case 3: case 4: case 5: - PAJ7620_state.corner = 3; - break; - case 9: case 10: case 11: case 12: case 13: case 14: - PAJ7620_state.corner = 1; - break; - } - if (PAJ7620_state.corner != 0) { - switch (PAJ7620_state.x) { - case 0: case 1: case 2: case 3: case 4: case 5: - break; - case 9: case 10: case 11: case 12: case 13: case 14: - PAJ7620_state.corner++; - break; - default: - PAJ7620_state.corner = 0; - break; - } - } - DEBUG_SENSOR_LOG(PSTR("PAJ: corner: %u"), PAJ7620_state.corner); - - if (PAJ7620_state.PIN.countdown == 0) { - PAJ7620_state.PIN.step = 0; - PAJ7620_state.PIN.valid = 0; - } - if (!PAJ7620_state.PIN.step) { - if (PAJ7620_state.corner == PAJ7620_PIN[PAJ7620_state.PIN.step]) { - PAJ7620_state.PIN.step = 1; - PAJ7620_state.PIN.countdown = 7; - } - } else { - if (PAJ7620_state.corner == PAJ7620_PIN[PAJ7620_state.PIN.step]) { - PAJ7620_state.PIN.step += 1; - PAJ7620_state.PIN.countdown = 7; - } else { - PAJ7620_state.PIN.countdown -= 1; - } - } - if (PAJ7620_state.PIN.step == 4) { - PAJ7620_state.PIN.valid = 1; - DEBUG_SENSOR_LOG(PSTR("PAJ: PIN valid!!")); - PAJ7620_state.PIN.countdown = 0; - } - MqttPublishSensor(); - } - } - break; - } -} - - - -void PAJ7620Detect(void) -{ - if (I2cActive(PAJ7620_ADDR)) { return; } - - PAJ7620SelectBank(0); - PAJ7620SelectBank(0); - uint16_t PAJ7620_id = I2cRead16LE(PAJ7620_ADDR,0); - uint8_t PAJ7620_ver = I2cRead8(PAJ7620_ADDR,2); - if (0x7620 == PAJ7620_id) { - I2cSetActiveFound(PAJ7620_ADDR, PAJ7620_name); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PAJ: ID: 0x%x and VER: %u"), PAJ7620_id, PAJ7620_ver); - PAJ7620_next_job = 1; - } - else { - DEBUG_SENSOR_LOG(PSTR("PAJ: sensor not found, false ID 0x%x"), PAJ7620_id); - } -} - - - -void PAJ7620Init(void) -{ - DEBUG_SENSOR_LOG(PSTR("PAJ: init sensor start %u"),millis()); - union{ - uint32_t raw; - uint8_t reg_val[4]; - } buf; - - for (uint32_t i = 0; i < (sizeof(PAJ7620initRegisterArray) / 2); i += 2) - { - buf.raw = pgm_read_dword(PAJ7620initRegisterArray + i); - DEBUG_SENSOR_LOG("PAJ: %x %x %x %x",buf.reg_val[0],buf.reg_val[1],buf.reg_val[2],buf.reg_val[3]); - I2cWrite(PAJ7620_ADDR, buf.reg_val[0], buf.reg_val[1], 1); - I2cWrite(PAJ7620_ADDR, buf.reg_val[2], buf.reg_val[3], 1); - } - DEBUG_SENSOR_LOG(PSTR("PAJ: init sensor done %u"),millis()); - PAJ7620_next_job = 2; -} - - - -void PAJ7620Loop(void) -{ - if (0 == PAJ7620_timeout_counter) { - switch (PAJ7620_next_job) { - case 1: - PAJ7620Init(); - break; - case 2: - if (PAJ7620_mode != 0) { - PAJ7620ReadGesture(); - } - break; - } - } else { - PAJ7620_timeout_counter--; - } -} - - - -void PAJ7620Show(bool json) -{ - if (json) { - if (PAJ7620_currentGestureName[0] != '\0' ) { - ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%u}"), PAJ7620_name, PAJ7620_currentGestureName, PAJ7620_gesture.same); - PAJ7620_currentGestureName[0] = '\0'; - return; - } - switch (PAJ7620_mode) { - case 2: - ResponseAppend_P(PSTR(",\"%s\":{\"Proximity\":%u}"), PAJ7620_name, PAJ7620_state.proximity); - break; - case 3: - if (PAJ7620_state.corner > 0) { - ResponseAppend_P(PSTR(",\"%s\":{\"Corner\":%u}"), PAJ7620_name, PAJ7620_state.corner); - } - break; - case 4: - if (PAJ7620_state.PIN.valid) { - ResponseAppend_P(PSTR(",\"%s\":{\"PIN\":%u}"), PAJ7620_name, 1); - PAJ7620_state.PIN.valid = 0; - } - break; - case 5: - ResponseAppend_P(PSTR(",\"%s\":{\"x\":%u,\"y\":%u}"), PAJ7620_name, PAJ7620_state.x, PAJ7620_state.y); - break; - } - } -} -# 411 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_50_paj7620.ino" -bool PAJ7620CommandSensor(void) -{ - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) { - PAJ7620_mode = XdrvMailbox.payload; - } - Response_P(S_JSON_SENSOR_INDEX_NVALUE, XSNS_50, PAJ7620_mode); - - return true; -} - - - - - -bool Xsns50(uint8_t function) -{ - if (!I2cEnabled(XI2C_34)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - PAJ7620Detect(); - } - else if (PAJ7620_next_job) { - switch (function) { - case FUNC_COMMAND_SENSOR: - if (XSNS_50 == XdrvMailbox.index){ - result = PAJ7620CommandSensor(); - } - break; - case FUNC_EVERY_100_MSECOND: - PAJ7620Loop(); - break; - case FUNC_JSON_APPEND: - PAJ7620Show(1); - break; - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_51_rdm6300.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_51_rdm6300.ino" -#ifdef USE_RDM6300 - -#define XSNS_51 51 - -#define RDM6300_BAUDRATE 9600 - -#include - -#define RDM_TIMEOUT 100 -char rdm_uid_str[10]; - - -#define RDM6300_BLOCK 2*10 - -uint8_t rdm_blcnt; -TasmotaSerial *RDM6300_Serial = nullptr; - -void RDM6300_Init() { - if (pin[GPIO_RDM6300_RX] < 99) { - RDM6300_Serial = new TasmotaSerial(pin[GPIO_RDM6300_RX],-1,1); - if (RDM6300_Serial->begin(RDM6300_BAUDRATE)) { - if (RDM6300_Serial->hardwareSerial()) { - ClaimSerial(); - } - } - } - rdm_blcnt=0; -} - - -void RDM6300_ScanForTag() { - char rdm_buffer[14]; - uint8_t rdm_index; - uint8_t rdm_array[6]; - - if (!RDM6300_Serial) return; - - if (rdm_blcnt>0) { - rdm_blcnt--; - while (RDM6300_Serial->available()) RDM6300_Serial->read(); - return; - } - - if (RDM6300_Serial->available()) { - - char c=RDM6300_Serial->read(); - if (c!=2) return; - - - rdm_index=0; - uint32_t cmillis=millis(); - while (1) { - if (RDM6300_Serial->available()) { - char c=RDM6300_Serial->read(); - if (c==3) { - - break; - } - rdm_buffer[rdm_index++]=c; - if (rdm_index>13) { - - return; - } - } - if ((millis()-cmillis)>RDM_TIMEOUT) { - - return; - } - } - - - rdm_blcnt=RDM6300_BLOCK; - - - rm6300_hstring_to_array(rdm_array,sizeof(rdm_array),rdm_buffer); - uint8_t accu=0; - for (uint8_t count=0;count<5;count++) { - accu^=rdm_array[count]; - } - if (accu!=rdm_array[5]) { - - return; - } - - - memcpy(rdm_uid_str,&rdm_buffer[2],8); - rdm_uid_str[9]=0; - - ResponseTime_P(PSTR(",\"RDM6300\":{\"UID\":\"%s\"}}"), rdm_uid_str); - MqttPublishTeleSensor(); - - - - - - } - - -} - -uint8_t rm6300_hexnibble(char chr) { - uint8_t rVal = 0; - if (isdigit(chr)) { - rVal = chr - '0'; - } else { - if (chr >= 'A' && chr <= 'F') rVal = chr + 10 - 'A'; - if (chr >= 'a' && chr <= 'f') rVal = chr + 10 - 'a'; - } - return rVal; -} - - -void rm6300_hstring_to_array(uint8_t array[], uint8_t len, char buffer[]) -{ - char *cp=buffer; - for (uint8_t i = 0; i < len; i++) { - uint8_t val = rm6300_hexnibble(*cp++) << 4; - array[i]= val | rm6300_hexnibble(*cp++); - } -} - -#ifdef USE_WEBSERVER -const char HTTP_RDM6300[] PROGMEM = - "{s}RDM6300 " "UID" "{m}%s" "{e}"; - -void RDM6300_Show(void) { - if (!RDM6300_Serial) return; - if (!rdm_uid_str[0]) strcpy(rdm_uid_str,"????"); - WSContentSend_PD(HTTP_RDM6300,rdm_uid_str); -} -#endif - - - - - -bool Xsns51(byte function) -{ - bool result = false; - - switch (function) { - case FUNC_INIT: - RDM6300_Init(); - break; - case FUNC_EVERY_100_MSECOND: - RDM6300_ScanForTag(); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - RDM6300_Show(); - break; -#endif - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_52_ibeacon.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_52_ibeacon.ino" -#ifdef USE_IBEACON - - - -#define XSNS_52 52 - -#include - -#define HM17_BAUDRATE 9600 - -#define IBEACON_DEBUG - - -#define HM17_V110 - - - -#define IB_TIMEOUT_INTERVAL 30 - -#define IB_UPDATE_TIME_INTERVAL 10 - -TasmotaSerial *IBEACON_Serial = nullptr; - - -uint8_t hm17_found,hm17_cmd,hm17_flag; - -#ifdef IBEACON_DEBUG -uint8_t hm17_debug=0; -#endif - - - -#define HM17_BSIZ 128 -char hm17_sbuffer[HM17_BSIZ]; -uint8_t hm17_sindex,hm17_result,hm17_scanning,hm17_connecting; -uint32_t hm17_lastms; -char ib_mac[14]; - - -#if 1 -uint8_t ib_upd_interval,ib_tout_interval; -#define IB_UPDATE_TIME ib_upd_interval -#define IB_TIMEOUT_TIME ib_tout_interval -#else -#undef IB_UPDATE_TIME -#undef IB_TIMEOUT_TIME -#define IB_UPDATE_TIME Settings.ib_upd_interval -#define IB_TIMEOUT_TIME Settings.ib_tout_interval -#endif - -enum {HM17_TEST,HM17_ROLE,HM17_IMME,HM17_DISI,HM17_IBEA,HM17_SCAN,HM17_DISC,HM17_RESET,HM17_RENEW,HM17_CON}; -#define HM17_SUCESS 99 - -struct IBEACON { - char FACID[8]; - char UID[32]; - char MAJOR[4]; - char MINOR[4]; - char PWR[2]; - char MAC[12]; - char RSSI[4]; -}; - -#define MAX_IBEACONS 16 - -struct IBEACON_UID { - char MAC[12]; - char RSSI[4]; - uint8_t FLAGS; - uint8_t TIME; -} ibeacons[MAX_IBEACONS]; - - -void IBEACON_Init() { - - hm17_found=0; - - - if ((pin[GPIO_IBEACON_RX] < 99) && (pin[GPIO_IBEACON_TX] < 99)) { - IBEACON_Serial = new TasmotaSerial(pin[GPIO_IBEACON_RX], pin[GPIO_IBEACON_TX],1); - if (IBEACON_Serial->begin(HM17_BAUDRATE)) { - if (IBEACON_Serial->hardwareSerial()) { - ClaimSerial(); - } - hm17_sendcmd(HM17_TEST); - hm17_lastms=millis(); - - IB_UPDATE_TIME=IB_UPDATE_TIME_INTERVAL; - IB_TIMEOUT_TIME=IB_TIMEOUT_INTERVAL; - } - } -} - -void hm17_every_second(void) { - if (!IBEACON_Serial) return; - - if (hm17_found) { - if (IB_UPDATE_TIME && (uptime%IB_UPDATE_TIME==0)) { - if (hm17_cmd!=99) { - if (hm17_flag&2) { - ib_sendbeep(); - } else { - if (!hm17_connecting) { - hm17_sendcmd(HM17_DISI); - } - } - } - } - for (uint32_t cnt=0;cntIB_TIMEOUT_TIME) { - ibeacons[cnt].FLAGS=0; - ibeacon_mqtt(ibeacons[cnt].MAC,"0000"); - } - } - } - } else { - if (uptime%20==0) { - hm17_sendcmd(HM17_TEST); - } - } -} - -void hm17_sbclr(void) { - memset(hm17_sbuffer,0,HM17_BSIZ); - hm17_sindex=0; - IBEACON_Serial->flush(); -} - -void hm17_sendcmd(uint8_t cmd) { - hm17_sbclr(); - hm17_cmd=cmd; -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("hm17cmd %d"),cmd); -#endif - switch (cmd) { - case HM17_TEST: - IBEACON_Serial->write("AT"); - break; - case HM17_ROLE: - IBEACON_Serial->write("AT+ROLE1"); - break; - case HM17_IMME: - IBEACON_Serial->write("AT+IMME1"); - break; - case HM17_DISI: - IBEACON_Serial->write("AT+DISI?"); - hm17_scanning=1; - break; - case HM17_IBEA: - IBEACON_Serial->write("AT+IBEA1"); - break; - case HM17_RESET: - IBEACON_Serial->write("AT+RESET"); - break; - case HM17_RENEW: - IBEACON_Serial->write("AT+RENEW"); - break; - case HM17_SCAN: - IBEACON_Serial->write("AT+SCAN5"); - break; - case HM17_DISC: - IBEACON_Serial->write("AT+DISC?"); - hm17_scanning=1; - break; - case HM17_CON: - IBEACON_Serial->write((const uint8_t*)"AT+CON",6); - IBEACON_Serial->write((const uint8_t*)ib_mac,12); - hm17_connecting=1; - break; - } -} - -uint32_t ibeacon_add(struct IBEACON *ib) { - - if (!strncmp(ib->MAC,"FFFF",4) || strncmp(ib->FACID,"00000000",8)) { - for (uint32_t cnt=0;cntMAC,12)) { - - memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); - ibeacons[cnt].TIME=0; - return 1; - } - } - } - for (uint32_t cnt=0;cntMAC,12); - memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); - ibeacons[cnt].FLAGS=1; - ibeacons[cnt].TIME=0; - return 1; - } - } - } - return 0; -} - -void hm17_decode(void) { - struct IBEACON ib; - switch (hm17_cmd) { - case HM17_TEST: - if (!strncmp(hm17_sbuffer,"OK",2)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("AT OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - hm17_found=1; - } - break; - case HM17_ROLE: - if (!strncmp(hm17_sbuffer,"OK+Set:1",8)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("ROLE OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - } - break; - case HM17_IMME: - if (!strncmp(hm17_sbuffer,"OK+Set:1",8)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("IMME OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - } - break; - case HM17_IBEA: - if (!strncmp(hm17_sbuffer,"OK+Set:1",8)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("IBEA OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - } - break; - case HM17_SCAN: - if (!strncmp(hm17_sbuffer,"OK+Set:5",8)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("SCAN OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - } - break; - case HM17_RESET: - if (!strncmp(hm17_sbuffer,"OK+RESET",8)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("RESET OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - } - break; - case HM17_RENEW: - if (!strncmp(hm17_sbuffer,"OK+RENEW",8)) { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("RENEW OK")); -#endif - hm17_sbclr(); - hm17_result=HM17_SUCESS; - } - break; - case HM17_CON: - if (!strncmp(hm17_sbuffer,"OK+CONNA",8)) { - hm17_sbclr(); -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("CONNA OK")); -#endif - hm17_connecting=2; - break; - } - if (!strncmp(hm17_sbuffer,"OK+CONNE",8)) { - hm17_sbclr(); -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("CONNE ERROR")); -#endif - break; - } - if (!strncmp(hm17_sbuffer,"OK+CONNF",8)) { - hm17_sbclr(); -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("CONNF ERROR")); -#endif - break; - } - if (hm17_connecting==2 && !strncmp(hm17_sbuffer,"OK+CONN",7)) { - hm17_sbclr(); -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("CONN OK")); -#endif - hm17_connecting=3; - hm17_sendcmd(HM17_TEST); - hm17_connecting=0; - break; - } - break; - - case HM17_DISI: - case HM17_DISC: - if (!strncmp(hm17_sbuffer,"OK+DISCS",8)) { - hm17_sbclr(); - hm17_result=1; -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("DISCS OK")); -#endif - break; - } - if (!strncmp(hm17_sbuffer,"OK+DISIS",8)) { - hm17_sbclr(); - hm17_result=1; -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("DISIS OK")); -#endif - break; - } - if (!strncmp(hm17_sbuffer,"OK+DISCE",8)) { - hm17_sbclr(); - hm17_result=HM17_SUCESS; -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR("DISCE OK")); -#endif - hm17_scanning=0; - break; - } - if (!strncmp(hm17_sbuffer,"OK+NAME:",8)) { - if (hm17_sbuffer[hm17_sindex-1]=='\n') { - hm17_result=HM17_SUCESS; -#ifdef IBEACON_DEBUG - if (hm17_debug) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("NAME OK")); - AddLog_P2(LOG_LEVEL_INFO, PSTR(">>%s"),&hm17_sbuffer[8]); - } -#endif - hm17_sbclr(); - } - break; - } - if (!strncmp(hm17_sbuffer,"OK+DIS0:",8)) { - if (hm17_cmd==HM17_DISI) { -#ifdef HM17_V110 - goto hm17_v110; -#endif - } else { - if (hm17_sindex==20) { - hm17_result=HM17_SUCESS; -#ifdef IBEACON_DEBUG - if (hm17_debug) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("DIS0 OK")); - AddLog_P2(LOG_LEVEL_INFO, PSTR(">>%s"),&hm17_sbuffer[8]); - } -#endif - hm17_sbclr(); - } - } - break; - } - if (!strncmp(hm17_sbuffer,"OK+DISC:",8)) { -hm17_v110: - if (hm17_cmd==HM17_DISI) { - if (hm17_sindex==78) { -#ifdef IBEACON_DEBUG - if (hm17_debug) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("DISC: OK")); - - AddLog_P2(LOG_LEVEL_INFO, PSTR(">>%s"),&hm17_sbuffer[8]); - } -#endif - memcpy(ib.FACID,&hm17_sbuffer[8],8); - memcpy(ib.UID,&hm17_sbuffer[8+8+1],32); - memcpy(ib.MAJOR,&hm17_sbuffer[8+8+1+32+1],4); - memcpy(ib.MINOR,&hm17_sbuffer[8+8+1+32+1+4],4); - memcpy(ib.PWR,&hm17_sbuffer[8+8+1+32+1+4+4],2); - memcpy(ib.MAC,&hm17_sbuffer[8+8+1+32+1+4+4+2+1],12); - memcpy(ib.RSSI,&hm17_sbuffer[8+8+1+32+1+4+4+2+1+12+1],4); - - if (ibeacon_add(&ib)) { - ibeacon_mqtt(ib.MAC,ib.RSSI); - } - hm17_sbclr(); - hm17_result=1; - } - } else { -#ifdef IBEACON_DEBUG - if (hm17_debug) AddLog_P2(LOG_LEVEL_INFO, PSTR(">>%s"),&hm17_sbuffer[8]); -#endif - } - break; - } - } -} - -void IBEACON_loop() { - - if (!IBEACON_Serial) return; - -uint32_t difftime=millis()-hm17_lastms; - - while (IBEACON_Serial->available()) { - hm17_lastms=millis(); - - if (hm17_sindexread(); - hm17_sindex++; - hm17_decode(); - } else { - hm17_sindex=0; - break; - } - } - - if (hm17_cmd==99) { - if (hm17_sindex>=HM17_BSIZ-2 || (hm17_sindex && (difftime>100))) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),hm17_sbuffer); - hm17_sbclr(); - } - } - -} - -#ifdef USE_WEBSERVER -const char HTTP_IBEACON[] PROGMEM = - "{s}IBEACON-UID : %s" " - RSSI : %s" "{m}{e}"; - -void IBEACON_Show(void) { -char mac[14]; -char rssi[6]; - - for (uint32_t cnt=0;cnt 0) { - char *cp=XdrvMailbox.data; - if (*cp>='0' && *cp<='8') { - hm17_sendcmd(*cp&7); - Response_P(S_JSON_IBEACON, XSNS_52,"hm17cmd",*cp&7); - } else if (*cp=='s') { - cp++; - len--; - while (*cp==' ') { - len--; - cp++; - } - IBEACON_Serial->write((uint8_t*)cp,len); - hm17_cmd=99; - Response_P(S_JSON_IBEACON1, XSNS_52,"hm17cmd",cp); - } else if (*cp=='u') { - cp++; - if (*cp) IB_UPDATE_TIME=atoi(cp); - Response_P(S_JSON_IBEACON, XSNS_52,"uintv",IB_UPDATE_TIME); - } else if (*cp=='t') { - cp++; - if (*cp) IB_TIMEOUT_TIME=atoi(cp); - Response_P(S_JSON_IBEACON, XSNS_52,"lintv",IB_TIMEOUT_TIME); - } else if (*cp=='c') { - for (uint32_t cnt=0;cnt - - -#define SPECIAL_SS - - - - - - -#define DJ_TPWRIN "Total_in" -#define DJ_TPWROUT "Total_out" -#define DJ_TPWRCURR "Power_curr" -#define DJ_TPWRCURR1 "Power_p1" -#define DJ_TPWRCURR2 "Power_p2" -#define DJ_TPWRCURR3 "Power_p3" -#define DJ_CURR1 "Curr_p1" -#define DJ_CURR2 "Curr_p2" -#define DJ_CURR3 "Curr_p3" -#define DJ_VOLT1 "Volt_p1" -#define DJ_VOLT2 "Volt_p2" -#define DJ_VOLT3 "Volt_p3" -#define DJ_METERNR "Meter_number" -#define DJ_METERSID "Meter_id" -#define DJ_CSUM "Curr_summ" -#define DJ_VAVG "Volt_avg" -#define DJ_COUNTER "Count" - -struct METER_DESC { - uint8_t srcpin; - uint8_t type; - uint16_t flag; - int32_t params; - char prefix[8]; - int8_t trxpin; - uint8_t tsecs; - char *txmem; - uint8_t index; - uint8_t max_index; -}; - - - - - - -#define EHZ161_0 1 -#define EHZ161_1 2 -#define EHZ363 3 -#define EHZH 4 -#define EDL300 5 -#define Q3B 6 -#define COMBO3 7 -#define COMBO2 8 -#define COMBO3a 9 -#define Q3B_V1 10 -#define EHZ363_2 11 -#define COMBO3b 12 -#define WGS_COMBO 13 -#define EBZD_G 14 - - -#define METER EHZ161_1 - - -#if METER==EHZ161_0 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; -const uint8_t meter[]= -"1,1-0:1.8.0*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.0*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,1-0:21.7.0*255(@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",0|" -"1,1-0:41.7.0*255(@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",0|" -"1,1-0:61.7.0*255(@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",0|" -"1,=m 3+4+5 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - - - -#if METER==EHZ161_1 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; -#endif - - - -#if METER==EHZ363 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; - -const uint8_t meter[]= - -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" - -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" - -"1,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" - -"1,77070100000009ff@#," D_METERNR ",," DJ_METERNR ",0"; -#endif - - - -#if METER==EHZH -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; - - -const uint8_t meter[]= - -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" - -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" - -"1,770701000f0700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0"; -#endif - - - -#if METER==EDL300 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; - - -const uint8_t meter[]= - -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" - -"1,77070100020801ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" - -"1,770701000f0700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0"; -#endif - -#if METER==EBZD_G -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"strom",-1,1,0}}; -const uint8_t meter[]= - -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" - -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" - -"1,77070100010801ff@1000," D_TPWRCURR1 ",kWh," DJ_TPWRCURR1 ",4|" - -"1,77070100010802ff@1000," D_TPWRCURR2 ",kWh," DJ_TPWRCURR2 ",4|" - -"1,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" - -"1,77070100600100ff@#," D_METERNR ",," DJ_METERNR ",0"; -#endif - - - - -#if METER==Q3B -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -const uint8_t meter[]= - -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" - -"1,77070100020801ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" - -"1,77070100010700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0"; -#endif - -#if METER==COMBO3 - -#undef METERS_USED -#define METERS_USED 3 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, - [1]={14,'s',0,SML_BAUDRATE,"SML",-1,1,0}, - [2]={4,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; - - -const uint8_t meter[]= -"1,1-0:1.8.0*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.0*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,1-0:21.7.0*255(@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",0|" -"1,1-0:41.7.0*255(@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",0|" -"1,1-0:61.7.0*255(@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",0|" -"1,=m 3+4+5 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" -"2,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"2,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"2,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"3,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"3,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"3,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"3,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - -#if METER==COMBO2 - -#undef METERS_USED -#define METERS_USED 2 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, - [1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; - - -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" - -"2,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"2,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"2,=d 6 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"2,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - -#if METER==COMBO3a -#undef METERS_USED -#define METERS_USED 3 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, - [1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}, - [2]={1,'o',0,SML_BAUDRATE,"OBIS3",-1,1,0}}; - - -const uint8_t meter[]= -"1,=h --- Zähler Nr 1 ---|" -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" -"2,=h --- Zähler Nr 2 ---|" -"2,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"2,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"2,=d 6 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"2,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" -"3,=h --- Zähler Nr 3 ---|" -"3,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"3,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"3,=d 10 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"3,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - - - -#if METER==Q3B_V1 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ -[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,=d 1 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; -#endif - - - -#if METER==EHZ363_2 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ -[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; - -const uint8_t meter[]= - -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" - -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" - -"1,77070100010801ff@1000," D_TPWRCURR1 ",kWh," DJ_TPWRCURR1 ",4|" - -"1,77070100010802ff@1000," D_TPWRCURR2 ",kWh," DJ_TPWRCURR2 ",4|" - -"1,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" - -"1,77070100000009ff@#," D_METERNR ",," DJ_METERNR ",0"; -#endif - - -#if METER==COMBO3b -#undef METERS_USED -#define METERS_USED 3 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, - [1]={14,'c',0,50,"Gas"}, - [2]={1,'c',0,10,"Wasser"}}; - - -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" - - -"2,1-0:1.8.0*255(@100," D_GasIN ",cbm," DJ_COUNTER ",2|" - -"3,1-0:1.8.0*255(@100," D_H2oIN ",cbm," DJ_COUNTER ",2"; -#endif - - -#if METER==WGS_COMBO -#undef METERS_USED -#define METERS_USED 3 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={1,'c',0,10,"H20",-1,1,0}, - [1]={4,'c',0,50,"GAS",-1,1,0}, - [2]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; - -const uint8_t meter[]= - - -"1,1-0:1.8.0*255(@10000," D_H2oIN ",cbm," DJ_COUNTER ",4|" - - -"2,=h==================|" -"2,1-0:1.8.0*255(@100," D_GasIN ",cbm," DJ_COUNTER ",3|" - -"3,=h==================|" - -"3,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",3|" -"3,=h==================|" - -"3,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",2|" -"3,=h -------------------------------|" -"3,=m 10+11+12 @100," D_StL1L2L3 ",A," DJ_CSUM ",2|" - -"3,=m 13+14+15/#3 @100," D_SpL1L2L3 ",V," DJ_VAVG ",2|" -"3,=h==================|" - -"3,77070100240700ff@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",2|" - -"3,77070100380700ff@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",2|" - -"3,770701004c0700ff@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",2|" -"3,=h -------------------------------|" - -"3,770701001f0700ff@100," D_Strom_L1 ",A," DJ_CURR1 ",2|" - -"3,77070100330700ff@100," D_Strom_L2 ",A," DJ_CURR2 ",2|" - -"3,77070100470700ff@100," D_Strom_L3 ",A," DJ_CURR3 ",2|" -"3,=h -------------------------------|" - -"3,77070100200700ff@100," D_Spannung_L1 ",V," DJ_VOLT1 ",2|" - -"3,77070100340700ff@100," D_Spannung_L2 ",V," DJ_VOLT2 ",2|" - -"3,77070100480700ff@100," D_Spannung_L3 ",V," DJ_VOLT3 ",2|" -"3,=h==================|" - -"3,77070100000009ff@#," D_METERSID ",," DJ_METERSID ",0|" -"3,=h--------------------------------"; -#endif -# 435 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_53_sml.ino" -#define USE_SML_MEDIAN_FILTER - - -#ifndef SML_MAX_VARS -#define SML_MAX_VARS 20 -#endif - - -#define MAX_METERS 5 -double meter_vars[SML_MAX_VARS]; - -#define MAX_DVARS MAX_METERS*2 -double dvalues[MAX_DVARS]; -uint32_t dtimes[MAX_DVARS]; -uint8_t meters_used; - -struct METER_DESC const *meter_desc_p; -const uint8_t *meter_p; -uint8_t meter_spos[MAX_METERS]; - - -TasmotaSerial *meter_ss[MAX_METERS]; - - -#define SML_BSIZ 48 -uint8_t smltbuf[MAX_METERS][SML_BSIZ]; - - -#define METER_ID_SIZE 24 -char meter_id[MAX_METERS][METER_ID_SIZE]; - -#define EBUS_SYNC 0xaa -#define EBUS_ESC 0xa9 - -uint8_t sml_send_blocks; -uint8_t sml_100ms_cnt; -uint8_t sml_desc_cnt; - -#ifdef USE_SML_MEDIAN_FILTER - -#define MEDIAN_SIZE 5 -struct SML_MEDIAN_FILTER { -double buffer[MEDIAN_SIZE]; -int8_t index; -} sml_mf[SML_MAX_VARS]; - -#ifndef FLT_MAX -#define FLT_MAX 99999999 -#endif - -double sml_median_array(double *array,uint8_t len) { - uint8_t ind[len]; - uint8_t mind=0,index=0,flg; - double min=FLT_MAX; - - for (uint8_t hcnt=0; hcntbuffer[mf->index]=in; - mf->index++; - if (mf->index>=MEDIAN_SIZE) mf->index=0; - - return sml_median_array(mf->buffer,MEDIAN_SIZE); -# 539 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_53_sml.ino" -} -#endif - -#ifdef ANALOG_OPTO_SENSOR - -uint8_t ads1115_up; - - -#define SAMPLE_BIT (0x8000) - -#define ADS1115_COMP_QUEUE_SHIFT 0 -#define ADS1115_COMP_LATCH_SHIFT 2 -#define ADS1115_COMP_POLARITY_SHIFT 3 -#define ADS1115_COMP_MODE_SHIFT 4 -#define ADS1115_DATA_RATE_SHIFT 5 -#define ADS1115_MODE_SHIFT 8 -#define ADS1115_PGA_SHIFT 9 -#define ADS1115_MUX_SHIFT 12 - -enum ads1115_comp_queue { - ADS1115_COMP_QUEUE_AFTER_ONE = 0, - ADS1115_COMP_QUEUE_AFTER_TWO = 0x1 << ADS1115_COMP_QUEUE_SHIFT, - ADS1115_COMP_QUEUE_AFTER_FOUR = 0x2 << ADS1115_COMP_QUEUE_SHIFT, - ADS1115_COMP_QUEUE_DISABLE = 0x3 << ADS1115_COMP_QUEUE_SHIFT, - ADS1115_COMP_QUEUE_MASK = 0x3 << ADS1115_COMP_QUEUE_SHIFT, -}; - -enum ads1115_comp_latch { - ADS1115_COMP_LATCH_NO = 0, - ADS1115_COMP_LATCH_YES = 1 << ADS1115_COMP_LATCH_SHIFT, - ADS1115_COMP_LATCH_MASK = 1 << ADS1115_COMP_LATCH_SHIFT, -}; - -enum ads1115_comp_polarity { - ADS1115_COMP_POLARITY_ACTIVE_LOW = 0, - ADS1115_COMP_POLARITY_ACTIVE_HIGH = 1 << ADS1115_COMP_POLARITY_SHIFT, - ADS1115_COMP_POLARITY_MASK = 1 << ADS1115_COMP_POLARITY_SHIFT, -}; - -enum ads1115_comp_mode { - ADS1115_COMP_MODE_WINDOW = 0, - ADS1115_COMP_MODE_HYSTERESIS = 1 << ADS1115_COMP_MODE_SHIFT, - ADS1115_COMP_MODE_MASK = 1 << ADS1115_COMP_MODE_SHIFT, -}; - -enum ads1115_data_rate { - ADS1115_DATA_RATE_8_SPS = 0, - ADS1115_DATA_RATE_16_SPS = 0x1 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_32_SPS = 0x2 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_64_SPS = 0x3 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_128_SPS = 0x4 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_250_SPS = 0x5 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_475_SPS = 0x6 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_860_SPS = 0x7 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_MASK = 0x7 << ADS1115_DATA_RATE_SHIFT, -}; - -enum ads1115_mode { - ADS1115_MODE_CONTINUOUS = 0, - ADS1115_MODE_SINGLE_SHOT = 1 << ADS1115_MODE_SHIFT, - ADS1115_MODE_MASK = 1 << ADS1115_MODE_SHIFT, -}; - -enum ads1115_pga { - ADS1115_PGA_TWO_THIRDS = 0, - ADS1115_PGA_ONE = 0x1 << ADS1115_PGA_SHIFT, - ADS1115_PGA_TWO = 0x2 << ADS1115_PGA_SHIFT, - ADS1115_PGA_FOUR = 0x3 << ADS1115_PGA_SHIFT, - ADS1115_PGA_EIGHT = 0x4 << ADS1115_PGA_SHIFT, - ADS1115_PGA_SIXTEEN = 0x5 << ADS1115_PGA_SHIFT, - ADS1115_PGA_MASK = 0x7 << ADS1115_PGA_SHIFT, -}; - - -enum ads1115_mux { - ADS1115_MUX_DIFF_AIN0_AIN1 = 0, - ADS1115_MUX_DIFF_AIN0_AIN3 = 0x1 << ADS1115_MUX_SHIFT, - ADS1115_MUX_DIFF_AIN1_AIN3 = 0x2 << ADS1115_MUX_SHIFT, - ADS1115_MUX_DIFF_AIN2_AIN3 = 0x3 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN0 = 0x4 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN1 = 0x5 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN2 = 0x6 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN3 = 0x7 << ADS1115_MUX_SHIFT, - ADS1115_MUX_MASK = 0x7 << ADS1115_MUX_SHIFT, -}; - -class ADS1115 { -public: - ADS1115(uint8_t address = 0x48); - - void begin(); - uint8_t trigger_sample(); - uint8_t reset(); - bool is_sample_in_progress(); - int16_t read_sample(); - float sample_to_float(int16_t val); - float read_sample_float(); - - void set_comp_queue(enum ads1115_comp_queue val) { set_config(val, ADS1115_COMP_QUEUE_MASK); } - void set_comp_latching(enum ads1115_comp_latch val) { set_config(val, ADS1115_COMP_LATCH_MASK); } - void set_comp_polarity(enum ads1115_comp_polarity val) { set_config(val, ADS1115_COMP_POLARITY_MASK); } - void set_comp_mode(enum ads1115_comp_mode val) { set_config(val, ADS1115_COMP_MODE_MASK); } - void set_data_rate(enum ads1115_data_rate val) { set_config(val, ADS1115_DATA_RATE_MASK); } - void set_mode(enum ads1115_mode val) { set_config(val, ADS1115_MODE_MASK); } - void set_pga(enum ads1115_pga val) { set_config(val, ADS1115_PGA_MASK); m_voltage_range = val >> ADS1115_PGA_SHIFT; } - void set_mux(enum ads1115_mux val) { set_config(val, ADS1115_MUX_MASK); } - -private: - void set_config(uint16_t val, uint16_t mask) { - m_config = (m_config & ~mask) | val; - } - - uint8_t write_register(uint8_t reg, uint16_t val); - uint16_t read_register(uint8_t reg); - - uint8_t m_address; - uint16_t m_config; - int m_voltage_range; -}; - - -enum ads1115_register { - ADS1115_REGISTER_CONVERSION = 0, - ADS1115_REGISTER_CONFIG = 1, - ADS1115_REGISTER_LOW_THRESH = 2, - ADS1115_REGISTER_HIGH_THRESH = 3, -}; - -#define FACTOR 32768.0 -static float ranges[] = { 6.144 / FACTOR, 4.096 / FACTOR, 2.048 / FACTOR, 1.024 / FACTOR, 0.512 / FACTOR, 0.256 / FACTOR}; - -ADS1115::ADS1115(uint8_t address) -{ - m_address = address; - m_config = ADS1115_COMP_QUEUE_AFTER_ONE | - ADS1115_COMP_LATCH_NO | - ADS1115_COMP_POLARITY_ACTIVE_LOW | - ADS1115_COMP_MODE_WINDOW | - ADS1115_DATA_RATE_128_SPS | - ADS1115_MODE_SINGLE_SHOT | - ADS1115_MUX_GND_AIN0; - set_pga(ADS1115_PGA_ONE); -} - -uint8_t ADS1115::write_register(uint8_t reg, uint16_t val) -{ - Wire.beginTransmission(m_address); - Wire.write(reg); - Wire.write(val>>8); - Wire.write(val & 0xFF); - return Wire.endTransmission(); -} - -uint16_t ADS1115::read_register(uint8_t reg) -{ - Wire.beginTransmission(m_address); - Wire.write(reg); - Wire.endTransmission(); - - uint8_t result = Wire.requestFrom((int)m_address, 2, 1); - if (result != 2) { - return 0; - } - - uint16_t val; - - val = Wire.read() << 8; - val |= Wire.read(); - return val; -} - -void ADS1115::begin() -{ - Wire.begin(); -} - -uint8_t ADS1115::trigger_sample() -{ - return write_register(ADS1115_REGISTER_CONFIG, m_config | SAMPLE_BIT); -} - -uint8_t ADS1115::reset() -{ - Wire.beginTransmission(0); - Wire.write(0x6); - return Wire.endTransmission(); -} - -bool ADS1115::is_sample_in_progress() -{ - uint16_t val = read_register(ADS1115_REGISTER_CONFIG); - return (val & SAMPLE_BIT) == 0; -} - -int16_t ADS1115::read_sample() -{ - return read_register(ADS1115_REGISTER_CONVERSION); -} - -float ADS1115::sample_to_float(int16_t val) -{ - return val * ranges[m_voltage_range]; -} - -float ADS1115::read_sample_float() -{ - return sample_to_float(read_sample()); -} - -ADS1115 adc; - -void ADS1115_init(void) { - - ads1115_up=0; - if (!i2c_flg) return; - - adc.begin(); - adc.set_data_rate(ADS1115_DATA_RATE_128_SPS); - adc.set_mode(ADS1115_MODE_CONTINUOUS); - adc.set_mux(ADS1115_MUX_DIFF_AIN0_AIN3); - adc.set_pga(ADS1115_PGA_TWO); - - int16_t val = adc.read_sample(); - ads1115_up=1; -} - -#endif - -char sml_start; -uint8_t dump2log=0; - -#define SML_SAVAILABLE Serial_available() -#define SML_SREAD Serial_read() -#define SML_SPEAK Serial_peek() - -bool Serial_available() { - uint8_t num=dump2log&7; - if (num<1 || num>meters_used) num=1; - return meter_ss[num-1]->available(); -} - -uint8_t Serial_read() { - uint8_t num=dump2log&7; - if (num<1 || num>meters_used) num=1; - return meter_ss[num-1]->read(); -} - -uint8_t Serial_peek() { - uint8_t num=dump2log&7; - if (num<1 || num>meters_used) num=1; - return meter_ss[num-1]->peek(); -} - -uint8_t sml_logindex; - -void Dump2log(void) { - -int16_t index=0,hcnt=0; -uint32_t d_lastms; -uint8_t dchars[16]; - - - - if (dump2log&8) { - - while (SML_SAVAILABLE) { - log_data[index]=':'; - index++; - log_data[index]=' '; - index++; - d_lastms=millis(); - while ((millis()-d_lastms)<40) { - if (SML_SAVAILABLE) { - uint8_t c=SML_SREAD; - sprintf(&log_data[index],"%02x ",c); - dchars[hcnt]=c; - index+=3; - hcnt++; - if (hcnt>15) { - - log_data[index]='='; - index++; - log_data[index]='>'; - index++; - log_data[index]=' '; - index++; - for (uint8_t ccnt=0; ccnt<16; ccnt++) { - if (isprint(dchars[ccnt])) { - log_data[index]=dchars[ccnt]; - } else { - log_data[index]=' '; - } - index++; - } - break; - } - } - } - if (index>0) { - log_data[index]=0; - AddLog(LOG_LEVEL_INFO); - index=0; - hcnt=0; - } - } - } else { - if (meter_desc_p[(dump2log&7)-1].type=='o') { - - while (SML_SAVAILABLE) { - char c=SML_SREAD&0x7f; - if (c=='\n' || c=='\r') { - log_data[sml_logindex]=0; - AddLog(LOG_LEVEL_INFO); - sml_logindex=2; - log_data[0]=':'; - log_data[1]=' '; - break; - } - log_data[sml_logindex]=c; - if (sml_logindex2) { - log_data[index]=0; - AddLog(LOG_LEVEL_INFO); - } - } - } -} - -#ifdef ED300L -uint8_t sml_status[MAX_METERS]; -uint8_t g_mindex; -#endif - - -uint8_t *skip_sml(uint8_t *cp,int16_t *res) { - uint8_t len,len1,type; - len=*cp&0xf; - type=*cp&0x70; - if (type==0x70) { - - - cp++; - while (len--) { - len1=*cp&0x0f; - cp+=len1; - } - *res=0; - } else { - - *res=(signed char)*(cp+1); - cp+=len; - } - return cp; -} - - - -double sml_getvalue(unsigned char *cp,uint8_t index) { -uint8_t len,unit,type; -int16_t scaler,result; -int64_t value; -double dval; - - - -#ifdef ED300L - unsigned char *cpx=cp-5; - - if (*cp==0x64 && *cpx==0 && *(cpx+1)==0x01 && *(cpx+2)==0x08 && *(cpx+3)==0) { - sml_status[g_mindex]=*(cp+3); - } -#endif - - cp=skip_sml(cp,&result); - - cp=skip_sml(cp,&result); - - cp=skip_sml(cp,&result); - - cp=skip_sml(cp,&result); - scaler=result; - - - type=*cp&0x70; - len=*cp&0x0f; - cp++; - if (type==0x50 || type==0x60) { - - uint64_t uvalue=0; - uint8_t nlen=len; - while (--nlen) { - uvalue<<=8; - uvalue|=*cp++; - } - if (type==0x50) { - - switch (len-1) { - case 1: - - value=(signed char)uvalue; - break; - case 2: - -#ifdef DWS74_BUG - if (scaler==-2) { - value=(uint32_t)uvalue; - } else { - value=(int16_t)uvalue; - } -#else - value=(int16_t)uvalue; -#endif - break; - case 3: - case 4: - - value=(int32_t)uvalue; - break; - case 5: - case 6: - case 7: - case 8: - - value=(int64_t)uvalue; - break; - } - } else { - - value=uvalue; - } - - } else { - if (!(type&0xf0)) { - - - - if (len==9) { - - cp++; - uint32_t s1,s2; - s1=*cp<<16|*(cp+1)<<8|*(cp+2); - cp+=4; - s2=*cp<<16|*(cp+1)<<8|*(cp+2); - sprintf(&meter_id[index][0],"%u-%u",s1,s2); - } else { - - char *str=&meter_id[index][0]; - for (type=0; type= 'A' && chr <= 'F') rVal = chr + 10 - 'A'; - } - return rVal; -} - -uint8_t sb_counter; - - -double CharToDouble(const char *str) -{ - - char strbuf[24]; - - strlcpy(strbuf, str, sizeof(strbuf)); - char *pt = strbuf; - while ((*pt != '\0') && isblank(*pt)) { pt++; } - - signed char sign = 1; - if (*pt == '-') { sign = -1; } - if (*pt == '-' || *pt=='+') { pt++; } - - double left = 0; - if (*pt != '.') { - left = atoi(pt); - while (isdigit(*pt)) { pt++; } - } - - double right = 0; - if (*pt == '.') { - pt++; - right = atoi(pt); - while (isdigit(*pt)) { - pt++; - right /= 10.0; - } - } - - double result = left + right; - if (sign < 0) { - return -result; - } - return result; -} - - - -void ebus_esc(uint8_t *ebus_buffer, unsigned char len) { - short count,count1; - for (count=0; countavailable()) { - meter_ss[meters]->read(); - } -} - - -void sml_shift_in(uint32_t meters,uint32_t shard) { - uint32_t count; - if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p') { - - for (count=0; countread(); - - if (meter_desc_p[meters].type=='o') { - smltbuf[meters][SML_BSIZ-1]=iob&0x7f; - } else if (meter_desc_p[meters].type=='s') { - smltbuf[meters][SML_BSIZ-1]=iob; - } else if (meter_desc_p[meters].type=='r') { - smltbuf[meters][SML_BSIZ-1]=iob; - } else if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M') { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters]>=9) { - SML_Decode(meters); - sml_empty_receiver(meters); - meter_spos[meters]=0; - } - } else if (meter_desc_p[meters].type=='p') { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters]>=7) { - SML_Decode(meters); - sml_empty_receiver(meters); - meter_spos[meters]=0; - } - } else { - if (iob==EBUS_SYNC) { - - - if (meter_spos[meters]>4+5) { - - uint8_t tlen=smltbuf[meters][4]+5; - - if (smltbuf[meters][tlen]=ebus_CalculateCRC(smltbuf[meters],tlen)) { - ebus_esc(smltbuf[meters],tlen); - SML_Decode(meters); - } else { - - - } - } - meter_spos[meters]=0; - return; - } - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters]>=SML_BSIZ) { - meter_spos[meters]=0; - } - } - sb_counter++; - if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p') SML_Decode(meters); -} - - - -void SML_Poll(void) { -uint32_t meters; - - for (meters=0; metersavailable()) { - sml_shift_in(meters,0); - } - } - } -} - - -void SML_Decode(uint8_t index) { - const char *mp=(const char*)meter_p; - int8_t mindex; - uint8_t *cp; - uint8_t dindex=0,vindex=0; - delay(0); - while (mp != NULL) { - - - - mindex=((*mp)&7)-1; - - if (mindex<0 || mindex>=meters_used) mindex=0; - mp+=2; - if (*mp=='=' && *(mp+1)=='h') { - mp = strchr(mp, '|'); - if (mp) mp++; - continue; - } - - if (index!=mindex) goto nextsect; - - - cp=&smltbuf[mindex][0]; - - - if (*mp=='=') { - - mp++; - - if (*mp=='m' && !sb_counter) { - - - mp++; - while (*mp==' ') mp++; - - double dvar; - uint8_t opr; - uint32_t ind; - ind=atoi(mp); - while (*mp>='0' && *mp<='9') mp++; - if (ind<1 || ind>SML_MAX_VARS) ind=1; - dvar=meter_vars[ind-1]; - for (uint8_t p=0;p<5;p++) { - if (*mp=='@') { - - meter_vars[vindex]=dvar; - mp++; - SML_Immediate_MQTT((const char*)mp,vindex,mindex); - break; - } - opr=*mp; - mp++; - uint8_t iflg=0; - if (*mp=='#') { - iflg=1; - mp++; - } - ind=atoi(mp); - while (*mp>='0' && *mp<='9') mp++; - if (ind<1 || ind>SML_MAX_VARS) ind=1; - switch (opr) { - case '+': - if (iflg) dvar+=ind; - else dvar+=meter_vars[ind-1]; - break; - case '-': - if (iflg) dvar-=ind; - else dvar-=meter_vars[ind-1]; - break; - case '*': - if (iflg) dvar*=ind; - else dvar*=meter_vars[ind-1]; - break; - case '/': - if (iflg) dvar/=ind; - else dvar/=meter_vars[ind-1]; - break; - } - while (*mp==' ') mp++; - if (*mp=='@') { - - meter_vars[vindex]=dvar; - mp++; - SML_Immediate_MQTT((const char*)mp,vindex,mindex); - break; - } - } - } else if (*mp=='d') { - - if (dindex='0' && *mp<='9') mp++; - if (ind<1 || ind>SML_MAX_VARS) ind=1; - uint32_t delay=atoi(mp)*1000; - uint32_t dtime=millis()-dtimes[dindex]; - if (dtime>delay) { - - dtimes[dindex]=millis(); - double vdiff = meter_vars[ind-1]-dvalues[dindex]; - dvalues[dindex]=meter_vars[ind-1]; - meter_vars[vindex]=(double)360000.0*vdiff/((double)dtime/10000.0); - - mp=strchr(mp,'@'); - if (mp) { - mp++; - SML_Immediate_MQTT((const char*)mp,vindex,mindex); - } - } - dindex++; - } - } else if (*mp=='h') { - - mp = strchr(mp, '|'); - if (mp) mp++; - continue; - } - } else { - - uint8_t found=1; - uint32_t ebus_dval=99; - float mbus_dval=99; - while (*mp!='@') { - if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') { - if (*mp++!=*cp++) { - found=0; - } - } else { - if (meter_desc_p[mindex].type=='s') { - - uint8_t val = hexnibble(*mp++) << 4; - val |= hexnibble(*mp++); - if (val!=*cp++) { - found=0; - } - } else { - - - if (*mp=='x' && *(mp+1)=='x') { - - mp+=2; - cp++; - } else if (!strncmp(mp,"UUuuUUuu",8)) { - uint32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0); - ebus_dval=val; - mbus_dval=val; - mp+=8; - cp+=4; - } else if (*mp=='U' && *(mp+1)=='U' && *(mp+2)=='u' && *(mp+3)=='u'){ - uint16_t val = cp[1]|(cp[0]<<8); - mbus_dval=val; - ebus_dval=val; - mp+=4; - cp+=2; - } else if (!strncmp(mp,"SSssSSss",8)) { - int32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0); - ebus_dval=val; - mbus_dval=val; - mp+=8; - cp+=4; - } else if (*mp=='u' && *(mp+1)=='u' && *(mp+2)=='U' && *(mp+3)=='U'){ - uint16_t val = cp[0]|(cp[1]<<8); - mbus_dval=val; - ebus_dval=val; - mp+=4; - cp+=2; - } else if (*mp=='u' && *(mp+1)=='u') { - uint8_t val = *cp++; - mbus_dval=val; - ebus_dval=val; - mp+=2; - } else if (*mp=='s' && *(mp+1)=='s' && *(mp+2)=='S' && *(mp+3)=='S') { - int16_t val = *cp|(*(cp+1)<<8); - mbus_dval=val; - ebus_dval=val; - mp+=4; - cp+=2; - } else if (*mp=='S' && *(mp+1)=='S' && *(mp+2)=='s' && *(mp+3)=='s') { - int16_t val = cp[1]|(cp[0]<<8); - mbus_dval=val; - ebus_dval=val; - mp+=4; - cp+=2; - } - else if (*mp=='s' && *(mp+1)=='s') { - int8_t val = *cp++; - mbus_dval=val; - ebus_dval=val; - mp+=2; - } - else if (!strncmp(mp,"ffffffff",8)) { - uint32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0); - float *fp=(float*)&val; - ebus_dval=*fp; - mbus_dval=*fp; - mp+=8; - cp+=4; - } - else if (!strncmp(mp,"FFffFFff",8)) { - - uint32_t val= (cp[1]<<0)|(cp[0]<<8)|(cp[3]<<16)|(cp[2]<<24); - float *fp=(float*)&val; - ebus_dval=*fp; - mbus_dval=*fp; - mp+=8; - cp+=4; - } - else if (!strncmp(mp,"eeeeee",6)) { - uint32_t val=(cp[0]<<16)|(cp[1]<<8)|(cp[2]<<0); - mbus_dval=val; - mp+=6; - cp+=3; - } - else if (!strncmp(mp,"vvvvvv",6)) { - mbus_dval=(float)((cp[0]<<8)|(cp[1])) + ((float)cp[2]/10.0); - mp+=6; - cp+=3; - } - else if (!strncmp(mp,"cccccc",6)) { - mbus_dval=(float)((cp[0]<<8)|(cp[1])) + ((float)cp[2]/100.0); - mp+=6; - cp+=3; - } - else if (!strncmp(mp,"pppp",4)) { - mbus_dval=(float)((cp[0]<<8)|cp[1]); - mp+=4; - cp+=2; - } - else { - uint8_t val = hexnibble(*mp++) << 4; - val |= hexnibble(*mp++); - if (val!=*cp++) { - found=0; - } - } - } - } - } - if (found) { - - mp++; -#ifdef ED300L - g_mindex=mindex; -#endif - if (*mp=='#') { - - mp++; - if (meter_desc_p[mindex].type=='o') { - for (uint8_t p=0;p>=shift; - ebus_dval&=1; - mp+=2; - } - if (*mp=='i') { - - mp++; - uint8_t mb_index=strtol((char*)mp,(char**)&mp,10); - if (mb_index!=meter_desc_p[mindex].index) { - goto nextsect; - } - uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0],7); - if (lowByte(crc)!=smltbuf[mindex][7]) goto nextsect; - if (highByte(crc)!=smltbuf[mindex][8]) goto nextsect; - dval=mbus_dval; - - mp++; - } else { - if (meter_desc_p[mindex].type=='p') { - uint8_t crc = SML_PzemCrc(&smltbuf[mindex][0],6); - if (crc!=smltbuf[mindex][6]) goto nextsect; - dval=mbus_dval; - } else { - dval=ebus_dval; - } - } - - } -#ifdef USE_SML_MEDIAN_FILTER - if (meter_desc_p[mindex].flag&16) { - meter_vars[vindex]=sml_median(&sml_mf[vindex],dval); - } else { - meter_vars[vindex]=dval; - } -#else - meter_vars[vindex]=dval; -#endif - - - double fac=CharToDouble((char*)mp); - meter_vars[vindex]/=fac; - SML_Immediate_MQTT((const char*)mp,vindex,mindex); - } - } - } -nextsect: - - if (vindex=meters_used) lastmind=0; - while (mp != NULL) { - - mindex=((*mp)&7)-1; - if (mindex<0 || mindex>=meters_used) mindex=0; - mp+=2; - if (*mp=='=' && *(mp+1)=='h') { - mp+=2; - - if (json) { - mp = strchr(mp, '|'); - if (mp) mp++; - continue; - } - - uint8_t i; - for (i=0;isml_counters[index].sml_debounce) { - RtcSettings.pulse_counter[index]++; - InjektCounterValue(sml_counters[index].sml_cnt_old_state,RtcSettings.pulse_counter[index]); - } - } else { - - sml_counters[index].sml_counter_ltime=millis(); - } -} - -void SML_CounterUpd1(void) { - SML_CounterUpd(0); -} - -void SML_CounterUpd2(void) { - SML_CounterUpd(1); -} - -void SML_CounterUpd3(void) { - SML_CounterUpd(2); -} - -void SML_CounterUpd4(void) { - SML_CounterUpd(3); -} - -#ifdef USE_SCRIPT -struct METER_DESC script_meter_desc[MAX_METERS]; -uint8_t *script_meter; -#endif - -#ifndef METER_DEF_SIZE -#define METER_DEF_SIZE 3000 -#endif - -bool Gpio_used(uint8_t gpiopin) { - for (uint16_t i=0;iM",-2,0); - if (meter_script==99) { - - if (script_meter) free(script_meter); - script_meter=0; - uint8_t *tp=0; - uint16_t index=0; - uint8_t section=0; - uint8_t srcpin=0; - char *lp=glob_script_mem.scriptptr; - sml_send_blocks=0; - while (lp) { - if (!section) { - if (*lp=='>' && *(lp+1)=='M') { - lp+=2; - meters_used=strtol(lp,0,10); - section=1; - uint32_t mlen=0; - for (uint32_t cnt=0;cnt') { - if (*(tp-1)=='|') *(tp-1)=0; - break; - } - if (*lp=='+') { - - - lp++; - index=*lp&7; - lp+=2; - if (index<1 || index>meters_used) goto next_line; - index--; - srcpin=strtol(lp,&lp,10); - if (Gpio_used(srcpin)) { - AddLog_P(LOG_LEVEL_INFO, PSTR("gpio rx double define!")); -dddef_exit: - if (script_meter) free(script_meter); - script_meter=0; - meters_used=METERS_USED; - goto init10; - } - script_meter_desc[index].srcpin=srcpin; - if (*lp!=',') goto next_line; - lp++; - script_meter_desc[index].type=*lp; - lp+=2; - script_meter_desc[index].flag=strtol(lp,&lp,10); - if (*lp!=',') goto next_line; - lp++; - script_meter_desc[index].params=strtol(lp,&lp,10); - if (*lp!=',') goto next_line; - lp++; - script_meter_desc[index].prefix[7]=0; - for (uint32_t cnt=0; cnt<8; cnt++) { - if (*lp==SCRIPT_EOL || *lp==',') { - script_meter_desc[index].prefix[cnt]=0; - break; - } - script_meter_desc[index].prefix[cnt]=*lp++; - } - if (*lp==',') { - lp++; - script_meter_desc[index].trxpin=strtol(lp,&lp,10); - if (Gpio_used(script_meter_desc[index].trxpin)) { - AddLog_P(LOG_LEVEL_INFO, PSTR("gpio tx double define!")); - goto dddef_exit; - } - if (*lp!=',') goto next_line; - lp++; - script_meter_desc[index].tsecs=strtol(lp,&lp,10); - if (*lp==',') { - lp++; - char txbuff[256]; - uint32_t txlen=0,tx_entries=1; - for (uint32_t cnt=0; cntmeters_used) goto next_line; - while (1) { - if (*lp==SCRIPT_EOL) { - if (*(tp-1)!='|') *tp++='|'; - goto next_line; - } - *tp++=*lp++; - index++; - if (index>=METER_DEF_SIZE) break; - } - } - - } - -next_line: - if (*lp==SCRIPT_EOL) { - lp++; - } else { - lp = strchr(lp, SCRIPT_EOL); - if (!lp) break; - lp++; - } - } - *tp=0; - meter_desc_p=script_meter_desc; - meter_p=script_meter; - } -#endif - -init10: - typedef void (*function)(); - function counter_callbacks[] = {SML_CounterUpd1,SML_CounterUpd2,SML_CounterUpd3,SML_CounterUpd4}; - uint8_t cindex=0; - - for (byte i = 0; i < MAX_COUNTERS; i++) { - RtcSettings.pulse_counter[i]=Settings.pulse_counter[i]; - sml_counters[i].sml_cnt_last_ts=millis(); - } - for (uint8_t meters=0; metersbegin(meter_desc_p[meters].params)) { - meter_ss[meters]->flush(); - } - if (meter_ss[meters]->hardwareSerial()) { - if (meter_desc_p[meters].type=='M') { - Serial.begin(meter_desc_p[meters].params, SERIAL_8E1); - } - ClaimSerial(); - } - - } - } - -} - - -#ifdef USE_SML_SCRIPT_CMD -uint32_t SML_SetBaud(uint32_t meter, uint32_t br) { - if (meter<1 || meter>meters_used) return 0; - meter--; - if (!meter_ss[meter]) return 0; - if (meter_ss[meter]->begin(br)) { - meter_ss[meter]->flush(); - } - if (meter_ss[meter]->hardwareSerial()) { - if (meter_desc_p[meter].type=='M') { - Serial.begin(br, SERIAL_8E1); - } - } - return 1; -} - -uint32_t SML_Status(uint32_t meter) { - if (meter<1 || meter>meters_used) return 0; - meter--; -#ifdef ED300L - return sml_status[meter]; -#else - return 0; -#endif -} - - -uint32_t SML_Write(uint32_t meter,char *hstr) { - if (meter<1 || meter>meters_used) return 0; - meter--; - if (!meter_ss[meter]) return 0; - SML_Send_Seq(meter,hstr); - return 1; -} -#endif - - -void SetDBGLed(uint8_t srcpin, uint8_t ledpin) { - pinMode(ledpin, OUTPUT); - if (digitalRead(srcpin)) { - digitalWrite(ledpin,LOW); - } else { - digitalWrite(ledpin,HIGH); - } -} - - -void SML_Counter_Poll(void) { -uint16_t meters,cindex=0; -uint32_t ctime=millis(); - - for (meters=0; meters0) { - if (ctime-sml_counters[cindex].sml_cnt_last_ts>meter_desc_p[meters].params) { - sml_counters[cindex].sml_cnt_last_ts=ctime; - - if (meter_desc_p[meters].flag&2) { - -#ifdef ANALOG_OPTO_SENSOR - if (ads1115_up) { - int16_t val = adc.read_sample(); - if (val>sml_counters[cindex].ana_max) sml_counters[cindex].ana_max=val; - if (val10) { - sml_counters[cindex].sml_cnt_last_ts=ctime; -#ifdef DEBUG_CNT_LED1 - if (cindex==0) SetDBGLed(meter_desc_p[meters].srcpin,DEBUG_CNT_LED1); -#endif -#ifdef DEBUG_CNT_LED2 - if (cindex==1) SetDBGLed(meter_desc_p[meters].srcpin,DEBUG_CNT_LED2); -#endif - } - } - cindex++; - } - } -} - -#ifdef USE_SCRIPT -char *SML_Get_Sequence(char *cp,uint32_t index) { - if (!index) return cp; - uint32_t cindex=0; - while (cp) { - cp=strchr(cp,','); - if (cp) { - cp++; - cindex++; - if (cindex==index) { - return cp; - } - } - } -} - -void SML_Check_Send(void) { - sml_100ms_cnt++; - char *cp; - for (uint32_t cnt=sml_desc_cnt; cnt=0 && script_meter_desc[cnt].txmem) { - if ((sml_100ms_cnt%script_meter_desc[cnt].tsecs)==0) { - if (script_meter_desc[cnt].max_index>1) { - script_meter_desc[cnt].index++; - if (script_meter_desc[cnt].index>=script_meter_desc[cnt].max_index) { - script_meter_desc[cnt].index=0; - sml_desc_cnt++; - } - cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index); - - } else { - cp=script_meter_desc[cnt].txmem; - - sml_desc_cnt++; - } - - SML_Send_Seq(cnt,cp); - if (sml_desc_cnt>=meters_used) { - sml_desc_cnt=0; - } - break; - } - } else { - sml_desc_cnt++; - } - - if (sml_desc_cnt>=meters_used) { - sml_desc_cnt=0; - } - } -} - -uint8_t sml_hexnibble(char chr) { - uint8_t rVal = 0; - if (isdigit(chr)) { - rVal = chr - '0'; - } else { - if (chr >= 'A' && chr <= 'F') rVal = chr + 10 - 'A'; - if (chr >= 'a' && chr <= 'f') rVal = chr + 10 - 'a'; - } - return rVal; -} - - -void SML_Send_Seq(uint32_t meter,char *seq) { - uint8_t sbuff[32]; - uint8_t *ucp=sbuff,slen=0; - char *cp=seq; - while (*cp) { - if (!*cp || !*(cp+1)) break; - if (*cp==',') break; - uint8_t iob=(sml_hexnibble(*cp) << 4) | sml_hexnibble(*(cp+1)); - cp+=2; - *ucp++=iob; - slen++; - if (slen>=sizeof(sbuff)) break; - } - if (script_meter_desc[meter].type=='m' || script_meter_desc[meter].type=='M') { - *ucp++=0; - *ucp++=2; - - uint16_t crc = MBUS_calculateCRC(sbuff,6); - *ucp++=lowByte(crc); - *ucp++=highByte(crc); - slen+=4; - } - if (script_meter_desc[meter].type=='o') { - for (uint32_t cnt=0;cntwrite(sbuff,slen); -} -#endif - -uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num) { - uint16_t crc, flag; - crc = 0xFFFF; - for (uint32_t i = 0; i < num; i++) { - crc ^= frame[i]; - for (uint32_t j = 8; j; j--) { - if ((crc & 0x0001) != 0) { - crc >>= 1; - crc ^= 0xA001; - } else { - crc >>= 1; - } - } - } - return crc; -} - -uint8_t SML_PzemCrc(uint8_t *data, uint8_t len) { - uint16_t crc = 0; - for (uint32_t i = 0; i < len; i++) crc += *data++; - return (uint8_t)(crc & 0xFF); -} - - -uint8_t CalcEvenParity(uint8_t data) { -uint8_t parity=0; - - while(data) { - parity^=(data &1); - data>>=1; - } - return parity; -} -# 2334 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_53_sml.ino" -bool XSNS_53_cmd(void) { - bool serviced = true; - if (XdrvMailbox.data_len > 0) { - char *cp=XdrvMailbox.data; - if (*cp=='d') { - - cp++; - uint8_t index=atoi(cp); - if ((index&7)>meters_used) index=1; - if (index>0 && meter_desc_p[(index&7)-1].type=='c') { - index=0; - } - dump2log=index; - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"),dump2log); - } else if (*cp=='c') { - - cp++; - uint8_t index=*cp&7; - if (index<1 || index>MAX_COUNTERS) index=1; - cp++; - while (*cp==' ') cp++; - if (isdigit(*cp)) { - uint32_t cval=atoi(cp); - while (isdigit(*cp)) cp++; - RtcSettings.pulse_counter[index-1]=cval; - uint8_t cindex=0; - for (uint8_t meters=0; metersaddress, INA226_REG_CALIBRATION, si->calibrationValue); - -} - - - - - - -bool Ina226TestPresence(uint8_t device) -{ - - - - uint16_t config = I2cRead16( slaveInfo[device].address, INA226_REG_CONFIG ); - - - if (config != slaveInfo[device].config) - return false; - - return true; - -} - -void Ina226ResetActive(void) -{ - Ina226SlaveInfo_t *p = slaveInfo; - - for (uint32_t i = 0; i < INA226_MAX_ADDRESSES; i++) { - p = &slaveInfo[i]; - - uint8_t addr = p->address; - if (addr) { - I2cResetActive(addr); - } - } -} - - - - - -void Ina226Init() -{ - uint32_t i; - - slavesFound = 0; - - Ina226SlaveInfo_t *p = slaveInfo; -# 215 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_54_ina226.ino" - for (i = 0; i < 4; i++){ - *p = {0}; - } - - - - - - for (i = 0; i < INA226_MAX_ADDRESSES; i++){ - uint8_t addr = pgm_read_byte(probeAddresses + i); - - if (I2cActive(addr)) { continue; } - - - - - if (!Settings.ina226_i_fs[i]) - continue; - - - - - - - if (!I2cWrite16( addr, INA226_REG_CONFIG, INA226_CONFIG_RESET)){ - - AddLog_P2( LOG_LEVEL_DEBUG, "No INA226 at address: %02X", addr); - continue; - } - - - - uint16_t config = I2cRead16( addr, INA226_REG_CONFIG ); - - - if (INA226_RES_CONFIG != config) - continue; - - - config = INA226_DEF_CONFIG; - - - if (!I2cWrite16( addr, INA226_REG_CONFIG, config)) - continue; - - - p = &slaveInfo[i]; - - p->address = addr; - - p->config = config; - - - p->i_lsb = (((float) Settings.ina226_i_fs[i])/10.0f)/32768.0f; - - - - uint32_t r_shunt_uohms = _expand_r_shunt(Settings.ina226_r_shunt[i]); - - - - p->calibrationValue = ((uint16_t) (0.00512/(p->i_lsb * r_shunt_uohms/1000000.0f))); - - p->present = true; - - - Ina226SetCalibration(i); - - I2cSetActiveFound(addr, Ina226Str); - - slavesFound++; - } -} - - - - - -float Ina226ReadBus_v(uint8_t device) -{ - uint8_t addr = slaveInfo[device].address; - int16_t reg_bus_v = I2cReadS16( addr, INA226_REG_BUSVOLTAGE); - - float result = ((float) reg_bus_v) * 0.00125f; - - return result; - -} - - - - - -float Ina226ReadShunt_i(uint8_t device) -{ - uint8_t addr = slaveInfo[device].address; - int16_t reg_shunt_i = I2cReadS16( addr, INA226_REG_CURRENT); - - float result = ((float) reg_shunt_i) * slaveInfo[device].i_lsb; - - return result; -} - - - - - -float Ina226ReadPower_w(uint8_t device) -{ - uint8_t addr = slaveInfo[device].address; - int16_t reg_shunt_i = I2cReadS16( addr, INA226_REG_POWER); - - float result = ((float) reg_shunt_i) * (slaveInfo[device].i_lsb * 25.0); - - return result; -} - - - - - - -void Ina226Read(uint8_t device) -{ - - voltages[device] = Ina226ReadBus_v(device); - currents[device] = Ina226ReadShunt_i(device); - powers[device] = Ina226ReadPower_w(device); - - - - -} - - - - - -void Ina226EverySecond() -{ - - for (uint8_t device = 0; device < INA226_MAX_ADDRESSES; device++){ - - if (slavesFound && slaveInfo[device].present && Ina226TestPresence(device)){ - Ina226Read(device); - } - else { - powers[device] = currents[device] = voltages[device] = 0.0f; - - - - - - - slaveInfo[device].present = false; - } - } -} - - - - - -bool Ina226CommandSensor() -{ - bool serviced = true; - bool show_config = false; - char param_str[64]; - char *cp, *params[4]; - uint8_t i, param_count, device, p1 = XdrvMailbox.payload; - uint32_t r_shunt_uohms; - uint16_t compact_r_shunt_uohms; - - - - - - if (XdrvMailbox.data_len > 62){ - return false; - } - - strncpy(param_str, XdrvMailbox.data, XdrvMailbox.data_len + 1); - param_str[XdrvMailbox.data_len] = 0; - - - for (cp = param_str, i = 0, param_count = 0; *cp && (i < XdrvMailbox.data_len + 1) && (param_count <= 3); i++) - if (param_str[i] == ' ' || param_str[i] == ',' || param_str[i] == 0){ - param_str[i] = 0; - params[param_count] = cp; - - param_count++; - cp = param_str + i + 1; - } - - - if (p1 < 10 || p1 >= 50){ - - switch (p1){ - case 1: - Ina226ResetActive(); - Ina226Init(); - Response_P(PSTR("{\"Sensor54-Command-Result\":{\"SlavesFound\":%d}}"),slavesFound); - break; - - case 2: - restart_flag = 2; - Response_P(PSTR("{\"Sensor54-Command-Result\":{\"Restart_flag\":%d}}"),restart_flag); - break; - - default: - serviced = false; - } - } - else if (p1 < 50){ - - device = (p1 / 10) - 1; - switch (p1 % 10){ - case 0: - show_config = true; - break; - - case 1: - r_shunt_uohms = (uint32_t) ((CharToFloat(params[1])) * 1000000.0f); - - - - if (r_shunt_uohms > 32767){ - uint32_t r_shunt_mohms = r_shunt_uohms/1000UL; - Settings.ina226_r_shunt[device] = (uint16_t) (r_shunt_mohms | 0x8000); - } - else - Settings.ina226_r_shunt[device] = (uint16_t) r_shunt_uohms; - - - show_config = true; - break; - - case 2: - Settings.ina226_i_fs[device] = (uint16_t) ((CharToFloat(params[1])) * 10.0f); - - show_config = true; - break; - - - default: - serviced = false; - break; - } - } - else - serviced = false; - - if (show_config) { - char shunt_r_str[16]; - char fs_i_str[16]; - - - r_shunt_uohms = _expand_r_shunt(Settings.ina226_r_shunt[device]); - dtostrfd(((float)r_shunt_uohms)/1000000.0f, 6, shunt_r_str); - - dtostrfd(((float)Settings.ina226_i_fs[device])/10.0f, 1, fs_i_str); - - Response_P(PSTR("{\"Sensor54-device-settings-%d\":{\"SHUNT_R\":%s,\"FS_I\":%s}}"), - device + 1, shunt_r_str, fs_i_str); - } - - return serviced; -} - - - - - -#ifdef USE_WEBSERVER -const char HTTP_SNS_INA226_DATA[] PROGMEM = - "{s}%s " D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}" - "{s}%s " D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}" - "{s}%s " D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; -#endif - -void Ina226Show(bool json) -{ - int i, num_found; - for (num_found = 0, i = 0; i < INA226_MAX_ADDRESSES; i++) { - - if (!slaveInfo[i].present) - continue; - - num_found++; - - char voltage[16]; - dtostrfd(voltages[i], Settings.flag2.voltage_resolution, voltage); - char current[16]; - dtostrfd(currents[i], Settings.flag2.current_resolution, current); - char power[16]; - dtostrfd(powers[i], Settings.flag2.wattage_resolution, power); - char name[16]; - snprintf_P(name, sizeof(name), PSTR("INA226%c%d"),IndexSeparator(), i + 1); - - - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"Id\":%d,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s,\"" D_JSON_POWERUSAGE "\":%s}"), - name, i, voltage, current, power); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_VOLTAGE, voltage); - DomoticzSensor(DZ_CURRENT, current); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_INA226_DATA, name, voltage, name, current, name, power); -#endif - } - - } - -} -# 546 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_54_ina226.ino" -bool Xsns54(byte callback_id) -{ - if (!I2cEnabled(XI2C_35)) { return false; } - - - bool result = false; - - - switch (callback_id) { - case FUNC_EVERY_SECOND: - Ina226EverySecond(); - break; - case FUNC_JSON_APPEND: - Ina226Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Ina226Show(0); - break; -#endif - case FUNC_COMMAND_SENSOR: - if (XSNS_54 == XdrvMailbox.index) { - result = Ina226CommandSensor(); - } - break; - case FUNC_INIT: - Ina226Init(); - break; - } - - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_55_hih_series.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_55_hih_series.ino" -#ifdef USE_I2C -#ifdef USE_HIH6 -# 33 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_55_hih_series.ino" -#define XSNS_55 55 -#define XI2C_36 36 - -#define HIH6_ADDR 0x27 - -struct HIH6 { - float temperature = 0; - float humidity = 0; - uint8_t valid = 0; - uint8_t type = 0; - char types[4] = "HIH"; -} Hih6; - -bool Hih6Read(void) -{ - Wire.beginTransmission(HIH6_ADDR); - if (Wire.endTransmission() != 0) { return false; } - - delay(40); - - uint8_t data[4]; - Wire.requestFrom(HIH6_ADDR, 4); - if (4 == Wire.available()) { - data[0] = Wire.read(); - data[1] = Wire.read(); - data[2] = Wire.read(); - data[3] = Wire.read(); - } else { return false; } - - - - Hih6.humidity = ConvertHumidity(((float)(((data[0] & 0x3F) << 8) | data[1]) * 100.0) / 16383.0); - - int temp = ((data[2] << 8) | (data[3] & 0xFC)) / 4; - Hih6.temperature = ConvertTemp(((float)temp / 16384.0) * 165.0 - 40.0); - - Hih6.valid = SENSOR_MAX_MISS; - return true; -} - - - -void Hih6Detect(void) -{ - if (I2cActive(HIH6_ADDR)) { return; } - - if (uptime < 2) { delay(20); } - Hih6.type = Hih6Read(); - if (Hih6.type) { - I2cSetActiveFound(HIH6_ADDR, Hih6.types); - } -} - -void Hih6EverySecond(void) -{ - if (uptime &1) { - - if (!Hih6Read()) { - AddLogMissed(Hih6.types, Hih6.valid); - } - } -} - -void Hih6Show(bool json) -{ - if (Hih6.valid) { - TempHumDewShow(json, (0 == tele_period), Hih6.types, Hih6.temperature, Hih6.humidity); - } -} - - - - - -bool Xsns55(uint8_t function) -{ - if (!I2cEnabled(XI2C_36)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Hih6Detect(); - } - else if (Hih6.type) { - switch (function) { - case FUNC_EVERY_SECOND: - Hih6EverySecond(); - break; - case FUNC_JSON_APPEND: - Hih6Show(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Hih6Show(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_56_hpma.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_56_hpma.ino" -#ifdef USE_HPMA -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_56_hpma.ino" -#define XSNS_56 56 - -#include -#include - -TasmotaSerial *HpmaSerial; -HPMA115S0 *hpma115S0; - -uint8_t hpma_type = 1; -uint8_t hpma_valid = 0; - -struct hpmadata { - unsigned int pm10; - unsigned int pm2_5; -} hpma_data; - - - -void HpmaSecond(void) -{ - unsigned int pm2_5, pm10; - - - - - if (hpma115S0->ReadParticleMeasurement(&pm2_5, &pm10)) { - hpma_data.pm2_5 = pm2_5; - hpma_data.pm10 = pm10; - hpma_valid = 1; - } - -} - -void HpmaInit(void) -{ - hpma_type = 0; - if (pin[GPIO_HPMA_RX] < 99 && pin[GPIO_HPMA_TX] < 99) { - HpmaSerial = new TasmotaSerial(pin[GPIO_HPMA_RX], pin[GPIO_HPMA_TX], 1); - hpma115S0 = new HPMA115S0(*HpmaSerial); - - if (HpmaSerial->begin(9600)) { - if (HpmaSerial->hardwareSerial()) { - ClaimSerial(); - } - hpma_type = 1; - hpma115S0->Init(); - hpma115S0->StartParticleMeasurement(); - } - } -} - -#ifdef USE_WEBSERVER -const char HTTP_HPMA_SNS[] PROGMEM = - "{s}HPMA " D_ENVIRONMENTAL_CONCENTRATION "2.5 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}HPMA " D_ENVIRONMENTAL_CONCENTRATION "10 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; -#endif - -void HpmaShow(bool json) -{ - if (hpma_valid) { - char pm10[33]; - snprintf_P(pm10, 33, PSTR("%d"), hpma_data.pm10); - char pm2_5[33]; - snprintf_P(pm2_5, 33, PSTR("%d"), hpma_data.pm2_5); - - if (json) { - ResponseAppend_P(PSTR(",\"HPMA\":{\"PM2.5\":%d,\"PM10\":%d}"), hpma_data.pm2_5, hpma_data.pm10); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzSensor(DZ_VOLTAGE, pm2_5); - DomoticzSensor(DZ_CURRENT, pm10); - } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_HPMA_SNS, pm2_5, pm10); -#endif - } - } -} - - - - - -bool Xsns56(uint8_t function) -{ - bool result = false; - - if (hpma_type) { - switch (function) { - case FUNC_INIT: - HpmaInit(); - break; - case FUNC_EVERY_SECOND: - HpmaSecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_56 == XdrvMailbox.index) { - return true; - } - break; - case FUNC_JSON_APPEND: - HpmaShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HpmaShow(0); - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_57_tsl2591.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_57_tsl2591.ino" -#ifdef USE_I2C -#ifdef USE_TSL2591 - - - - - - - -#define XSNS_57 57 -#define XI2C_40 40 - -#define TSL2591_ADDRESS 0x29 - -#include - -Adafruit_TSL2591 tsl = Adafruit_TSL2591(); - -uint8_t tsl2591_type = 0; -uint8_t tsl2591_valid = 0; -float tsl2591_lux = 0; - -void Tsl2591Init(void) -{ - - if (I2cSetDevice(0x29)) { - if (tsl.begin()) { - tsl.setGain(TSL2591_GAIN_MED); - tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); - tsl2591_type = 1; - I2cSetActiveFound(TSL2591_ADDRESS, "TSL2591"); - } - } -} - -bool Tsl2591Read(void) -{ - uint32_t lum = tsl.getFullLuminosity(); - uint16_t ir, full; - ir = lum >> 16; - full = lum & 0xFFFF; - tsl2591_lux = tsl.calculateLux(full, ir); - tsl2591_valid = 1; -} - -void Tsl2591EverySecond(void) -{ - Tsl2591Read(); -} - -#ifdef USE_WEBSERVER -const char HTTP_SNS_TSL2591[] PROGMEM = - "{s}TSL2591 " D_ILLUMINANCE "{m}%s " D_UNIT_LUX "{e}"; -#endif - -void Tsl2591Show(bool json) -{ - if (tsl2591_valid) { - char lux_str[10]; - dtostrf(tsl2591_lux, sizeof(lux_str)-1, 3, lux_str); - if (json) { - ResponseAppend_P(PSTR(",\"TSL2591\":{\"" D_JSON_ILLUMINANCE "\":%s}"), lux_str); -#ifdef USE_DOMOTICZ - if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, tsl2591_lux); } -#endif -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TSL2591, lux_str); -#endif - } - } -} - - - - - -bool Xsns57(uint8_t function) -{ - if (!I2cEnabled(XI2C_40)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Tsl2591Init(); - } - else if (tsl2591_type) { - switch (function) { - case FUNC_EVERY_SECOND: - Tsl2591EverySecond(); - break; - case FUNC_JSON_APPEND: - Tsl2591Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Tsl2591Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_58_dht12.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_58_dht12.ino" -#ifdef USE_I2C -#ifdef USE_DHT12 - - - - - - -#define XSNS_58 58 -#define XI2C_41 41 - -#define DHT12_ADDR 0x5C - -struct DHT12 { - float temperature = NAN; - float humidity = NAN; - uint8_t valid = 0; - uint8_t count = 0; - char name[6] = "DHT12"; -} Dht12; - -bool Dht12Read(void) -{ - if (Dht12.valid) { Dht12.valid--; } - - Wire.beginTransmission(DHT12_ADDR); - Wire.write(0); - if (Wire.endTransmission() != 0) { return false; } - - delay(50); - - Wire.requestFrom(DHT12_ADDR, 5); - delay(5); - uint8_t humidity = Wire.read(); - uint8_t humidityTenth = Wire.read(); - uint8_t temp = Wire.read(); - uint8_t tempTenth = Wire.read(); - uint8_t checksum = Wire.read(); - - Dht12.humidity = ConvertHumidity( (float) humidity + (float) humidityTenth/(float) 10.0 ); - Dht12.temperature = ConvertTemp( (float) temp + (float) tempTenth/(float) 10.0 ); - - if (isnan(Dht12.temperature) || isnan(Dht12.humidity)) { return false; } - - Dht12.valid = SENSOR_MAX_MISS; - return true; -} - - - -void Dht12Detect(void) -{ - if (I2cActive(DHT12_ADDR)) { return; } - - if (Dht12Read()) { - I2cSetActiveFound(DHT12_ADDR, Dht12.name); - Dht12.count = 1; - } -} - -void Dht12EverySecond(void) -{ - if (uptime &1) { - - if (!Dht12Read()) { - AddLogMissed(Dht12.name, Dht12.valid); - } - } -} - -void Dht12Show(bool json) -{ - if (Dht12.valid) { - TempHumDewShow(json, (0 == tele_period), Dht12.name, Dht12.temperature, Dht12.humidity); - } -} - - - - - -bool Xsns58(uint8_t function) -{ - if (!I2cEnabled(XI2C_41)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Dht12Detect(); - } - else if (Dht12.count) { - switch (function) { - case FUNC_EVERY_SECOND: - Dht12EverySecond(); - break; - case FUNC_JSON_APPEND: - Dht12Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Dht12Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_59_ds1624.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_59_ds1624.ino" -#ifdef USE_I2C -#ifdef USE_DS1624 - - - - - - - -#define XSNS_59 59 -#define XI2C_42 42 - -#define DS1624_MEM_REGISTER 0x17 -#define DS1624_CONF_REGISTER 0xAC -#define DS1624_TEMP_REGISTER 0xAA -#define DS1624_START_REGISTER 0xEE -#define DS1624_STOP_REGISTER 0x22 - -#define DS1621_COUNTER_REGISTER 0xA8 -#define DS1621_SLOPE_REGISTER 0xA9 - -#define DS1621_CFG_1SHOT (1<<0) -#define DS1621_CFG_DONE (1<<7) - -enum { - DS1624_TYPE_DS1624, - DS1624_TYPE_DS1621 -}; - -#define DS1624_MAX_SENSORS 8 - -bool ds1624_init = false; - -struct { - float value; - uint8_t type; - int errcnt; - int misscnt; - bool valid; - char name[9]; -} ds1624_sns[DS1624_MAX_SENSORS]; - -uint32_t DS1624_Idx2Addr(uint32_t idx) { - return 0x48 + idx; -} - -int DS1624_Restart(uint8_t config, uint32_t idx) { - uint32_t addr = DS1624_Idx2Addr(idx); - if ((config & 1) == 1) { - config &= ~(DS1621_CFG_DONE|DS1621_CFG_1SHOT); - I2cWrite8(addr, DS1624_CONF_REGISTER, config); - delay(10); - AddLog_P2(LOG_LEVEL_ERROR, "%s addr %x is reset, reconfig: %x", ds1624_sns[idx].name, addr, config); - } - I2cValidRead(addr, DS1624_START_REGISTER, 1); -} - -void DS1624_HotPlugUp(uint32_t idx) -{ - uint32_t addr = DS1624_Idx2Addr(idx); - - if (I2cActive(addr)) { return; } - if (!I2cSetDevice(addr)) { return; } - - uint8_t config; - if (I2cValidRead8(&config, addr, DS1624_CONF_REGISTER)) { - uint8_t tmp; - ds1624_sns[idx].type = (I2cValidRead8(&tmp, addr, DS1624_MEM_REGISTER)) ? DS1624_TYPE_DS1624 : DS1624_TYPE_DS1621; - - snprintf_P(ds1624_sns[idx].name, sizeof(ds1624_sns[idx].name), PSTR("DS162%c%c%d"), - (ds1624_sns[idx].type == DS1624_TYPE_DS1621) ? '1' : '4', IndexSeparator(), idx); - I2cSetActiveFound(addr, ds1624_sns[idx].name); - - ds1624_sns[idx].valid = true; - ds1624_sns[idx].errcnt = 0; - ds1624_sns[idx].misscnt = 0; - DS1624_Restart(config,idx); - AddLog_P2(LOG_LEVEL_INFO, "Hot Plug %s addr %x config: %x", ds1624_sns[idx].name, addr, config); - } -} - -void DS1624_HotPlugDown(int idx) -{ - uint32_t addr = DS1624_Idx2Addr(idx); - if (!I2cActive(addr)) { return; } - I2cResetActive(addr); - ds1624_sns[idx].valid = false; - AddLog_P2(LOG_LEVEL_INFO, "Hot UnPlug %s", ds1624_sns[idx].name); -} - -bool DS1624GetTemp(float *value, int idx) -{ - uint32_t addr = DS1624_Idx2Addr(idx); - - uint8_t config; - if (!I2cValidRead8(&config, addr, DS1624_CONF_REGISTER)) { - ds1624_sns[idx].misscnt++; - AddLog_P2(LOG_LEVEL_INFO, "%s device missing (errors: %i)", ds1624_sns[idx].name, ds1624_sns[idx].misscnt); - return false; - } - ds1624_sns[idx].misscnt=0; - if (config & (DS1621_CFG_1SHOT|DS1621_CFG_DONE)) { - ds1624_sns[idx].errcnt++; - AddLog_P2(LOG_LEVEL_INFO, "%s config error, restart... (errors: %i)", ds1624_sns[idx].name, ds1624_sns[idx].errcnt); - DS1624_Restart(config, idx); - return false; - } - - uint16_t t; - if (!I2cValidRead16(&t, DS1624_Idx2Addr(idx), DS1624_TEMP_REGISTER)) { return false; } - if (ds1624_sns[idx].type == DS1624_TYPE_DS1624) { - *value = ((float)(int8_t)(t>>8)) + ((t>>4)&0xf)*0.0625; - } else { - - *value = ((float)(int8_t)(t>>8)); - uint8_t remain; - if (!I2cValidRead8(&remain, addr, DS1621_COUNTER_REGISTER)) { return true; } - uint8_t perc; - if (!I2cValidRead8(&perc, addr, DS1621_SLOPE_REGISTER)) { return true; } - float fix=(float)(perc - remain)/(float)perc; - *value+=fix; - } - ds1624_sns[idx].errcnt=0; - config &= ~(DS1621_CFG_DONE); - I2cWrite8(addr, DS1624_CONF_REGISTER, config); - return true; -} - -void DS1624HotPlugScan(void) -{ - uint16_t t; - - for (uint32_t idx = 0; idx < DS1624_MAX_SENSORS; idx++) { - uint32_t addr = DS1624_Idx2Addr(idx); - if (I2cActive(addr) && !ds1624_sns[idx].valid) { - continue; - } - if (ds1624_sns[idx].valid) { - if ((ds1624_sns[idx].misscnt>2)||(ds1624_sns[idx].errcnt>2)) { - DS1624_HotPlugDown(idx); - continue; - } - } - DS1624_HotPlugUp(idx); - } -} - -void DS1624EverySecond(void) -{ - float t; - for (uint32_t i = 0; i < DS1624_MAX_SENSORS; i++) { - if (!ds1624_sns[i].valid) { continue; } - if (!DS1624GetTemp(&t, i)) { continue; } - ds1624_sns[i].value = ConvertTemp(t); - } -} - -void DS1624Show(bool json) -{ - char temperature[33]; - bool once = true; - - for (uint32_t i = 0; i < DS1624_MAX_SENSORS; i++) { - if (!ds1624_sns[i].valid) { continue; } - - dtostrfd(ds1624_sns[i].value, Settings.flag2.temperature_resolution, temperature); - if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), ds1624_sns[i].name, temperature); - if ((0 == tele_period) && once) { -#ifdef USE_DOMOTICZ - DomoticzSensor(DZ_TEMP, temperature); -#endif -#ifdef USE_KNX - KnxSensor(KNX_TEMPERATURE, ds1624_sns[i].value); -#endif - once = false; - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_TEMP, ds1624_sns[i].name, temperature, TempUnit()); -#endif - } - } -} - - - - - -bool Xsns59(uint8_t function) -{ - if (!I2cEnabled(XI2C_42)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - if (!ds1624_init) { - memset(ds1624_sns, 0, sizeof(ds1624_sns)); - ds1624_init = true; - DS1624HotPlugScan(); - } - } - switch (function) { - case FUNC_HOTPLUG_SCAN: - DS1624HotPlugScan(); - break; - case FUNC_EVERY_SECOND: - DS1624EverySecond(); - break; - case FUNC_JSON_APPEND: - DS1624Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - DS1624Show(0); - break; -#endif - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_60_GPS.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_60_GPS.ino" -#ifdef USE_GPS -#if defined(ESP32) && defined(USE_FLOG) - #undef USE_FLOG - #warning FLOG deactivated on ESP32 -#endif -# 117 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_60_GPS.ino" -#define XSNS_60 60 - -#include "NTPServer.h" -#include "NTPPacket.h" - -#ifdef ESP32 -#include -#endif - - - - - -#define D_CMND_UBX "UBX" - -const char S_JSON_UBX_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_UBX "%s\":%d}"; - -const char kUBXTypes[] PROGMEM = "UBX"; - -#define UBX_LAT_LON_THRESHOLD 1000 - -#define UBX_SERIAL_BUFFER_SIZE 256 -#define UBX_TCP_PORT 1234 -#define NTP_MILLIS_OFFSET 50 - - - - - -const char UBLOX_INIT[] PROGMEM = { - - 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x24, - 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x2B, - 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x32, - 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x39, - 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x40, - 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x05,0x47, - - - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xDC, - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xB9, - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xC0, - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x92, - - - - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x13,0xBE, - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x14,0xC5, - 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x21,0x00,0x01,0x00,0x00,0x00,0x00,0x32,0x97, - - - - - - -}; - -char UBX_name[4]; - -struct UBX_t { - const char UBX_HEADER[2] = { 0xB5, 0x62 }; - const char NAV_POSLLH_HEADER[2] = { 0x01, 0x02 }; - const char NAV_STATUS_HEADER[2] = { 0x01, 0x03 }; - const char NAV_TIME_HEADER[2] = { 0x01, 0x21 }; - - struct entry_t { - int32_t lat; - int32_t lon; - uint32_t time; - }; - - union { - entry_t values; - uint8_t bytes[sizeof(entry_t)]; - } rec_buffer; - - struct POLL_MSG { - uint8_t cls; - uint8_t id; - uint16_t zero; - }; - - struct NAV_POSLLH { - uint8_t cls; - uint8_t id; - uint16_t len; - uint32_t iTOW; - int32_t lon; - int32_t lat; - int32_t alt; - int32_t hMSL; - uint32_t hAcc; - uint32_t vAcc; - }; - - struct NAV_STATUS { - uint8_t cls; - uint8_t id; - uint16_t len; - uint32_t iTOW; - uint8_t gpsFix; - uint8_t flags; - uint8_t fixStat; - uint8_t flags2; - uint32_t ttff; - uint32_t msss; - }; - - struct NAV_TIME_UTC { - uint8_t cls; - uint8_t id; - uint16_t len; - uint32_t iTOW; - uint32_t tAcc; - int32_t nano; - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t min; - uint8_t sec; - struct { - uint8_t UTC:1; - uint8_t WKN:1; - uint8_t TOW:1; - uint8_t padding:5; - } valid; - }; - - struct CFG_RATE { - uint8_t cls; - uint8_t id; - uint16_t len; - uint16_t measRate; - uint16_t navRate; - uint16_t timeRef; - char CK[2]; - }; - - struct { - uint32_t last_iTOW; - int32_t last_alt; - uint32_t last_hAcc; - uint32_t last_vAcc; - uint8_t gpsFix; - uint8_t non_empty_loops; - uint16_t log_interval; - int32_t timeOffset; - } state; - - struct { - uint32_t init:1; - uint32_t filter_noise:1; - uint32_t send_when_new:1; - uint32_t send_UI_only:1; - uint32_t runningNTP:1; - - uint32_t forceUTCupdate:1; - uint32_t runningVPort:1; - - } mode; - - union { - NAV_POSLLH navPosllh; - NAV_STATUS navStatus; - NAV_TIME_UTC navTime; - POLL_MSG pollMsg; - CFG_RATE cfgRate; - } Message; - - uint8_t TCPbuf[UBX_SERIAL_BUFFER_SIZE]; - size_t TCPbufSize; -} UBX; - -enum UBXMsgType { - MT_NONE, - MT_NAV_POSLLH, - MT_NAV_STATUS, - MT_NAV_TIME, - MT_POLL -}; - -#ifdef USE_FLOG -FLOG *Flog = nullptr; -#endif -#ifdef ESP8266 -TasmotaSerial *UBXSerial; -#else -HardwareSerial *UBXSerial; -#endif - -NtpServer timeServer(PortUdp); - -WiFiServer vPortServer(UBX_TCP_PORT); -WiFiClient vPortClient; - - - - - -void UBXcalcChecksum(char* CK, size_t msgSize) -{ - memset(CK, 0, 2); - for (int i = 0; i < msgSize; i++) { - CK[0] += ((char*)(&UBX.Message))[i]; - CK[1] += CK[0]; - } -} - -bool UBXcompareMsgHeader(const char* msgHeader) -{ - char* ptr = (char*)(&UBX.Message); - return ptr[0] == msgHeader[0] && ptr[1] == msgHeader[1]; -} - -void UBXinitCFG(void) -{ - for (uint32_t i = 0; i < sizeof(UBLOX_INIT); i++) { - UBXSerial->write( pgm_read_byte(UBLOX_INIT+i) ); - } - DEBUG_SENSOR_LOG(PSTR("UBX: turn off NMEA")); -} - -void UBXsendCFGLine(uint8_t _line) -{ - if (_line>sizeof(UBLOX_INIT)/16) return; - for (uint32_t i = 0; i < 16; i++) { - UBXSerial->write( pgm_read_byte(UBLOX_INIT+i+(_line*16)) ); - } - DEBUG_SENSOR_LOG(PSTR("UBX: send line %u of UBLOX_INIT"), _line); -} - -void UBXTriggerTele(void) -{ - mqtt_data[0] = '\0'; - if (MqttShowSensor()) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); -#ifdef USE_RULES - RulesTeleperiod(); -#endif - } -} - - - -void UBXDetect(void) -{ - UBX.mode.init = 0; - if ((pin[GPIO_GPS_RX] < 99) && (pin[GPIO_GPS_TX] < 99)) { -#ifdef ESP8266 - UBXSerial = new TasmotaSerial(pin[GPIO_GPS_RX], pin[GPIO_GPS_TX], 1, 0, UBX_SERIAL_BUFFER_SIZE); - if (UBXSerial->begin(9600)) { -#else - UBXSerial = new HardwareSerial(2); - UBXSerial->begin(9600,SERIAL_8N1,pin[GPIO_GPS_RX], pin[GPIO_GPS_TX]); - { -#endif - DEBUG_SENSOR_LOG(PSTR("UBX: started serial")); -#ifdef ESP8266 - if (UBXSerial->hardwareSerial()) { - ClaimSerial(); - DEBUG_SENSOR_LOG(PSTR("UBX: claim HW")); - } -#endif - } - } - else { - return; - } - - UBXinitCFG(); - UBX.mode.init = 1; - -#ifdef USE_FLOG - if (!Flog) { - Flog = new FLOG; - Flog->init(); - } -#endif - - UBX.state.log_interval = 10; - UBX.mode.send_UI_only = true; - UBXTriggerTele(); -} - -uint32_t UBXprocessGPS() -{ - static uint32_t fpos = 0; - static char checksum[2]; - static uint8_t currentMsgType = MT_NONE; - static size_t payloadSize = sizeof(UBX.Message); - - - uint32_t data_bytes = 0; - while ( UBXSerial->available() ) { - data_bytes++; - byte c = UBXSerial->read(); - if (UBX.mode.runningVPort){ - UBX.TCPbuf[data_bytes-1] = c; - UBX.TCPbufSize = data_bytes; - } - if ( fpos < 2 ) { - - if ( c == UBX.UBX_HEADER[fpos] ) { - fpos++; - } else { - fpos = 0; - } - } else { - - - - - - if ( (fpos-2) < payloadSize ) { - ((char*)(&UBX.Message))[fpos-2] = c; - } - fpos++; - - if ( fpos == 4 ) { - - - if ( UBXcompareMsgHeader(UBX.NAV_POSLLH_HEADER) ) { - currentMsgType = MT_NAV_POSLLH; - payloadSize = sizeof(UBX_t::NAV_POSLLH); - DEBUG_SENSOR_LOG(PSTR("UBX: got NAV_POSLLH")); - } - else if ( UBXcompareMsgHeader(UBX.NAV_STATUS_HEADER) ) { - currentMsgType = MT_NAV_STATUS; - payloadSize = sizeof(UBX_t::NAV_STATUS); - DEBUG_SENSOR_LOG(PSTR("UBX: got NAV_STATUS")); - } - else if ( UBXcompareMsgHeader(UBX.NAV_TIME_HEADER) ) { - currentMsgType = MT_NAV_TIME; - payloadSize = sizeof(UBX_t::NAV_TIME_UTC); - DEBUG_SENSOR_LOG(PSTR("UBX: got NAV_TIME_UTC")); - } - else { - - fpos = 0; - continue; - } - } - - if ( fpos == (payloadSize+2) ) { - - - UBXcalcChecksum(checksum, payloadSize); - } - else if ( fpos == (payloadSize+3) ) { - - - if ( c != checksum[0] ) { - - fpos = 0; - } - } - else if ( fpos == (payloadSize+4) ) { - - - fpos = 0; - if ( c == checksum[1] ) { - - return currentMsgType; - } - } - else if ( fpos > (payloadSize+4) ) { - - - fpos = 0; - } - } - } - - if (data_bytes!=0) { - UBX.state.non_empty_loops++; - DEBUG_SENSOR_LOG(PSTR("UBX: got %u bytes, non-empty-loop: %u"), data_bytes, UBX.state.non_empty_loops); - } else { - UBX.state.non_empty_loops = 0; - } - return MT_NONE; -} - - - - - -#ifdef USE_FLOG -void UBXsendHeader(void) -{ - Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); - Webserver->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx")); - WSSend(200, CT_STREAM, F( - "\r\n" - "\r\n" - "\r\n\r\n")); -} - -void UBXsendRecord(uint8_t *buf) -{ - char record[100]; - char stime[32]; - UBX_t::entry_t *entry = (UBX_t::entry_t*)buf; - snprintf_P(stime, sizeof(stime), GetDT(entry->time).c_str()); - char lat[12]; - char lon[12]; - dtostrfd((double)entry->lat/10000000.0f,7,lat); - dtostrfd((double)entry->lon/10000000.0f,7,lon); - snprintf_P(record, sizeof(record),PSTR("\n\t\n\n"),lat ,lon, stime); - - Webserver->sendContent_P(record); -} - -void UBXsendFooter(void) -{ - Webserver->sendContent(F("\n\n")); - Webserver->sendContent(""); - Rtc.user_time_entry = false; -} - - - -void UBXsendFile(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - Flog->startDownload(sizeof(UBX.rec_buffer),UBXsendHeader,UBXsendRecord,UBXsendFooter); -} -#endif - - - -void UBXSetRate(uint16_t interval) -{ - UBX.Message.cfgRate.cls = 0x06; - UBX.Message.cfgRate.id = 0x08; - UBX.Message.cfgRate.len = 6; - uint32_t measRate = (1000*(uint32_t)interval); - if (measRate > 0xffff) { - measRate = 0xffff; - } - UBX.Message.cfgRate.measRate = (uint16_t)measRate; - UBX.Message.cfgRate.navRate = 1; - UBX.Message.cfgRate.timeRef = 1; - UBXcalcChecksum(UBX.Message.cfgRate.CK, sizeof(UBX.Message.cfgRate)-sizeof(UBX.Message.cfgRate.CK)); - DEBUG_SENSOR_LOG(PSTR("UBX: requested interval: %u seconds measRate: %u ms"), interval, UBX.Message.cfgRate.measRate); - UBXSerial->write(UBX.UBX_HEADER[0]); - UBXSerial->write(UBX.UBX_HEADER[1]); - for (uint32_t i =0; iwrite(((uint8_t*)(&UBX.Message.cfgRate))[i]); - DEBUG_SENSOR_LOG(PSTR("UBX: cfgRate byte %u: %x"), i, ((uint8_t*)(&UBX.Message.cfgRate))[i]); - } - UBX.state.log_interval = 10*interval; -} - -void UBXSelectMode(uint16_t mode) -{ - DEBUG_SENSOR_LOG(PSTR("UBX: set mode to %u"),mode); - switch(mode){ -#ifdef USE_FLOG - case 0: - Flog->mode = 0; - break; - case 1: - Flog->mode = 1; - break; - case 2: - UBX.mode.filter_noise = true; - break; - case 3: - UBX.mode.filter_noise = false; - break; - case 4: - Flog->startRecording(true); - AddLog_P(LOG_LEVEL_INFO, PSTR("UBX: start recording - appending")); - break; - case 5: - Flog->startRecording(false); - AddLog_P(LOG_LEVEL_INFO, PSTR("UBX: start recording - new log")); - break; - case 6: - if(Flog->recording == true){ - Flog->stopRecording(); - } - AddLog_P(LOG_LEVEL_INFO, PSTR("UBX: stop recording")); - break; -#endif - case 7: - UBX.mode.send_when_new = 1; - break; - case 8: - UBX.mode.send_when_new = 0; - break; - case 9: - if (timeServer.beginListening()) { - UBX.mode.runningNTP = true; - } - break; - case 10: - UBX.mode.runningNTP = false; - UBXsendCFGLine(10); - UBXsendCFGLine(11); - break; - case 11: - UBX.mode.forceUTCupdate = true; - break; - case 12: - UBX.mode.forceUTCupdate = false; - break; - case 13: - Settings.latitude = UBX.rec_buffer.values.lat/10; - Settings.longitude = UBX.rec_buffer.values.lon/10; - break; - case 14: - vPortServer.begin(); - UBX.mode.runningVPort = 1; - break; - case 15: - - UBX.mode.runningVPort = 0; - break; - default: - if (mode>1000 && mode <1066) { - UBXSetRate(mode-1000); - } - break; - } - UBX.mode.send_UI_only = true; - UBXTriggerTele(); -} - - - -bool UBXHandlePOSLLH() -{ - DEBUG_SENSOR_LOG(PSTR("UBX: iTOW: %u"),UBX.Message.navPosllh.iTOW); - if (UBX.state.gpsFix>1) { - if (UBX.mode.filter_noise) { - if ((UBX.Message.navPosllh.lat-UBX.rec_buffer.values.lat6) { - if(UBX.mode.runningVPort) return; - UBXinitCFG(); - AddLog_P(LOG_LEVEL_ERROR, PSTR("UBX: possible device-reset, will re-init")); - UBXSerial->flush(); - UBX.state.non_empty_loops = 0; - } -} - - - -void UBXLoop50msec(void) -{ - - if (UBX.mode.runningVPort){ - if(!vPortClient.connected()) { - vPortClient = vPortServer.available(); - } - while(vPortClient.available()) { - byte _newByte = vPortClient.read(); - UBXSerial->write(_newByte); - } - - if (UBX.TCPbufSize!=0){ - vPortClient.write((char*)UBX.TCPbuf, UBX.TCPbufSize); - UBX.TCPbufSize = 0; - } - } - - if(UBX.mode.runningNTP){ - timeServer.processOneRequest(UBX.rec_buffer.values.time, UBX.state.timeOffset - NTP_MILLIS_OFFSET); - } -} - -void UBXLoop(void) -{ - static uint16_t counter; - static bool new_position; - - uint32_t msgType = UBXprocessGPS(); - - switch(msgType){ - case MT_NAV_POSLLH: - new_position = UBXHandlePOSLLH(); - break; - case MT_NAV_STATUS: - UBXHandleSTATUS(); - break; - case MT_NAV_TIME: - UBXHandleTIME(); - break; - default: - UBXHandleOther(); - break; - } - -#ifdef USE_FLOG - if (counter>UBX.state.log_interval) { - if (Flog->recording && new_position) { - UBX.rec_buffer.values.time = Rtc.local_time; - Flog->addToBuffer(UBX.rec_buffer.bytes, sizeof(UBX.rec_buffer.bytes)); - counter = 0; - } - } -#endif - - counter++; -} - - - - -#ifdef USE_WEBSERVER - - -#ifdef USE_FLOG -#ifdef DEBUG_TASMOTA_SENSOR - const char HTTP_SNS_FLOGVER[] PROGMEM = "{s}
{m}
{e}{s} FLOG with %u sectors: {m}%u bytes{e}" - "{s} FLOG next sector for REC: {m} %u {e}" - "{s} %u sector(s) with data at sector: {m} %u {e}"; - const char HTTP_SNS_FLOGREC[] PROGMEM = "{s} RECORDING (bytes in buffer) {m}%u{e}"; -#endif - - const char HTTP_SNS_FLOG[] PROGMEM = "{s}
{m}
{e}{s} Flash-Log {m} %s{e}"; - const char kFLOG_STATE0[] PROGMEM = "ready"; - const char kFLOG_STATE1[] PROGMEM = "recording"; - const char * kFLOG_STATE[] ={kFLOG_STATE0, kFLOG_STATE1}; - - const char HTTP_BTN_FLOG_DL[] PROGMEM = ""; - -#endif - const char HTTP_SNS_NTPSERVER[] PROGMEM = "{s} NTP server {m}active{e}"; - - const char HTTP_SNS_GPS[] PROGMEM = "{s} GPS latitude {m}%s{e}" - "{s} GPS longitude {m}%s{e}" - "{s} GPS altitude {m}%s m{e}" - "{s} GPS hor. Accuracy {m}%s m{e}" - "{s} GPS vert. Accuracy {m}%s m{e}" - "{s} GPS sat-fix status {m}%s{e}"; - - const char kGPSFix0[] PROGMEM = "no fix"; - const char kGPSFix1[] PROGMEM = "dead reckoning only"; - const char kGPSFix2[] PROGMEM = "2D-fix"; - const char kGPSFix3[] PROGMEM = "3D-fix"; - const char kGPSFix4[] PROGMEM = "GPS + dead reckoning combined"; - const char kGPSFix5[] PROGMEM = "Time only fix"; - const char * kGPSFix[] PROGMEM ={kGPSFix0, kGPSFix1, kGPSFix2, kGPSFix3, kGPSFix4, kGPSFix5}; - - - - -#endif - - - -void UBXShow(bool json) -{ - char lat[12]; - char lon[12]; - char alt[12]; - char hAcc[12]; - char vAcc[12]; - dtostrfd((double)UBX.rec_buffer.values.lat/10000000.0f,7,lat); - dtostrfd((double)UBX.rec_buffer.values.lon/10000000.0f,7,lon); - dtostrfd((double)UBX.state.last_alt/1000.0f,3,alt); - dtostrfd((double)UBX.state.last_vAcc/1000.0f,3,hAcc); - dtostrfd((double)UBX.state.last_hAcc/1000.0f,3,vAcc); - - if (json) { - ResponseAppend_P(PSTR(",\"GPS\":{")); - if (UBX.mode.send_UI_only) { - uint32_t i = UBX.state.log_interval / 10; - ResponseAppend_P(PSTR("\"fil\":%u,\"int\":%u}"), UBX.mode.filter_noise, i); - } else { - ResponseAppend_P(PSTR("\"lat\":%s,\"lon\":%s,\"alt\":%s,\"hAcc\":%s,\"vAcc\":%s}"), lat, lon, alt, hAcc, vAcc); - } -#ifdef USE_FLOG - ResponseAppend_P(PSTR(",\"FLOG\":{\"rec\":%u,\"mode\":%u,\"sec\":%u}"), Flog->recording, Flog->mode, Flog->sectors_left); -#endif - UBX.mode.send_UI_only = false; -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_GPS, lat, lon, alt, hAcc, vAcc, kGPSFix[UBX.state.gpsFix]); - -#ifdef DEBUG_TASMOTA_SENSOR -#ifdef USE_FLOG - WSContentSend_PD(HTTP_SNS_FLOGVER, Flog->num_sectors, Flog->size, Flog->current_sector, Flog->sectors_left, Flog->sector.header.physical_start_sector); - if (Flog->recording) { - WSContentSend_PD(HTTP_SNS_FLOGREC, Flog->sector.header.buf_pointer - 8); - } -#endif -#endif -#ifdef USE_FLOG - if (Flog->ready) { - WSContentSend_P(HTTP_SNS_FLOG,kFLOG_STATE[Flog->recording]); - } - if (!Flog->recording && Flog->found_saved_data) { - WSContentSend_P(HTTP_BTN_FLOG_DL); - } -#endif - if (UBX.mode.runningNTP) { - WSContentSend_P(HTTP_SNS_NTPSERVER); - } -#endif - } -} - - - - - -bool UBXCmd(void) -{ - bool serviced = true; - if (XdrvMailbox.data_len > 0) { - UBXSelectMode(XdrvMailbox.payload); - Response_P(S_JSON_UBX_COMMAND_NVALUE, XdrvMailbox.command, XdrvMailbox.payload); - } - return serviced; -} - - - - - -bool Xsns60(uint8_t function) -{ - bool result = false; - - if (FUNC_INIT == function) { - UBXDetect(); - } - - if (UBX.mode.init) { - switch (function) { - case FUNC_COMMAND_SENSOR: - if (XSNS_60 == XdrvMailbox.index) { - result = UBXCmd(); - } - break; - case FUNC_EVERY_50_MSECOND: - UBXLoop50msec(); - break; - case FUNC_EVERY_100_MSECOND: -#ifdef USE_FLOG - if (!Flog->running_download) -#endif - { - UBXLoop(); - } - break; -#ifdef USE_FLOG - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/UBX", UBXsendFile); - break; -#endif - case FUNC_JSON_APPEND: - UBXShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: -#ifdef USE_FLOG - if (!Flog->running_download) -#endif - { - UBXShow(0); - } - break; -#endif - } - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -# 44 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -#ifdef USE_SPI -#ifdef USE_NRF24 -#ifdef USE_MIBLE - -#ifdef DEBUG_TASMOTA_SENSOR - #define MINRF_LOG_BUFFER(x) MINRFshowBuffer(x); -#else - #define MINRF_LOG_BUFFER(x) -#endif -# 62 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -#define XSNS_61 61 - -#include - -#define FLORA 1 -#define MJ_HT_V1 2 -#define LYWSD02 3 -#define LYWSD03 4 -#define CGG1 5 -#define CGD1 6 - -#define D_CMND_NRF "NRF" - -const char S_JSON_NRF_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_NRF "%s\":%d}"; -const char S_JSON_NRF_COMMAND[] PROGMEM = "{\"" D_CMND_NRF "%s\":\"%s\"}"; -const char kNRF_Commands[] PROGMEM = "Ignore|Page|Scan|Beacon|Chan"; - -enum NRF_Commands { - CMND_NRF_IGNORE, - CMND_NRF_PAGE, - CMND_NRF_SCAN, - CMND_NRF_BEACON, - CMND_NRF_CHAN - }; - -const uint16_t kMINRFSlaveID[6]={ 0x0098, - 0x01aa, - 0x045b, - 0x055b, - 0x0347, - 0x0576 - }; - -const char kMINRFSlaveType1[] PROGMEM = "Flora"; -const char kMINRFSlaveType2[] PROGMEM = "MJ_HT_V1"; -const char kMINRFSlaveType3[] PROGMEM = "LYWSD02"; -const char kMINRFSlaveType4[] PROGMEM = "LYWSD03"; -const char kMINRFSlaveType5[] PROGMEM = "CGG1"; -const char kMINRFSlaveType6[] PROGMEM = "CGD1"; -const char * kMINRFSlaveType[] PROGMEM = {kMINRFSlaveType1,kMINRFSlaveType2,kMINRFSlaveType3,kMINRFSlaveType4,kMINRFSlaveType5,kMINRFSlaveType6}; - - -const uint32_t kMINRFFloPDU[3] = {0x3eaa857d,0xef3b8730,0x71da7b46}; -const uint32_t kMINRFMJPDU[3] = {0x4760cd66,0xdbcc0cd3,0x33048df5}; -const uint32_t kMINRFL2PDU[3] = {0x3eaa057d,0xef3b0730,0x71dafb46}; - -const uint32_t kMINRFL3PDU[3] = {0x4760cb78,0xdbcc0acd,0x33048beb}; -const uint32_t kMINRFCGGPDU[3] = {0x4760cd6e,0xdbcc0cdb,0x33048dfd}; -const uint32_t kMINRFCGDPDU[3] = {0x5da0d752,0xc10c16e7,0x29c497c1}; - - -const uint8_t kMINRFlsfrList_A[3] = {0x4b,0x17,0x23}; -const uint8_t kMINRFlsfrList_B[3] = {0x21,0x72,0x43}; - - -#pragma pack(1) -struct mi_beacon_t{ - uint16_t productID; - uint8_t counter; - uint8_t Mac[6]; - uint8_t spare; - uint8_t type; - uint8_t ten; - uint8_t size; - union { - struct{ - int16_t temp; - uint16_t hum; - }HT; - uint8_t bat; - uint16_t temp; - uint16_t hum; - uint32_t lux:24; - uint8_t moist; - uint16_t fert; - }; -}; - -struct CGDPacket_t { - uint8_t serial[6]; - uint16_t mode; - union { - struct { - int16_t temp; - uint16_t hum; - }; - uint8_t bat; - }; -}; - -struct bleAdvPacket_t { - uint8_t pduType; - uint8_t payloadSize; - uint8_t mac[6]; -}; - -union FIFO_t{ - bleAdvPacket_t bleAdv; - mi_beacon_t miBeacon; - CGDPacket_t CGDPacket; - uint8_t raw[32]; -}; - -#pragma pack(0) - -struct { - const uint8_t channel[3] = {37,38,39}; - const uint8_t frequency[3] = { 2,26,80}; - - uint16_t timer; - uint8_t currentChan=0; - uint8_t ignore = 0; - uint8_t channelIgnore = 0; - uint8_t confirmedSensors = 0; - uint8_t packetMode; - uint8_t perPage = 4; - uint8_t firstUsedPacketMode = 1; - - FIFO_t buffer; - - struct { - uint8_t mac[6]; - uint32_t time; - uint32_t PDU[3]; - bool active = false; - } beacon; - bool activeScan = false; - bool stopScan = false; - -#ifdef DEBUG_TASMOTA_SENSOR - uint8_t streamBuffer[sizeof(buffer)]; - uint8_t lsfrBuffer[sizeof(buffer)]; -#endif - -} MINRF; - -struct mi_sensor_t{ - uint8_t type; - uint8_t serial[6]; - uint8_t showedUp; - float temp; - union { - struct { - float moisture; - float fertility; - uint32_t lux; - }; - struct { - float hum; - uint8_t bat; - }; - }; -}; - -struct scan_entry_t { - uint8_t mac[6]; - uint16_t cid; - uint16_t svc; - uint16_t uuid; - uint8_t showedUp; -}; - -std::vector MIBLEsensors; -std::vector MINRFscanResult; - -static union{ - scan_entry_t MINRFdummyEntry; - uint8_t MINRFtempBuf[23]; -}; -# 241 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -bool MINRFinitBLE(uint8_t _mode) -{ - if (MINRF.timer%1000 == 0){ - NRF24radio.begin(pin[GPIO_SPI_CS],pin[GPIO_SPI_DC]); - NRF24radio.setAutoAck(false); - NRF24radio.setDataRate(RF24_1MBPS); - NRF24radio.disableCRC(); - NRF24radio.setChannel( MINRF.frequency[MINRF.currentChan] ); - NRF24radio.setRetries(0,0); - NRF24radio.setPALevel(RF24_PA_MIN); - NRF24radio.setAddressWidth(4); - - - NRF24radio.powerUp(); - } - if(NRF24radio.isChipConnected()){ - - MINRFchangePacketModeTo(_mode); - return true; - } - - return false; -} - - - - - -void MINRFhopChannel() -{ - for (uint32_t i = 0; i<3;i++){ - MINRF.currentChan++; - if(bitRead(MINRF.channelIgnore,MINRF.currentChan)) continue; - if(MINRF.currentChan >= sizeof(MINRF.channel)) { - MINRF.currentChan = 0; - if(bitRead(MINRF.channelIgnore,MINRF.currentChan)) continue; - } - break; - } - NRF24radio.setChannel( MINRF.frequency[MINRF.currentChan] ); -} - - - - - - - -bool MINRFreceivePacket(void) -{ - if(!NRF24radio.available()) { - return false; - } - while(NRF24radio.available()) { - - - NRF24radio.read( &MINRF.buffer, sizeof(MINRF.buffer) ); -#ifdef DEBUG_TASMOTA_SENSOR - memcpy(&MINRF.streamBuffer, &MINRF.buffer, sizeof(MINRF.buffer)); -#endif - MINRFswapbuf((uint8_t*)&MINRF.buffer, sizeof(MINRF.buffer) ); - - - - switch (MINRF.packetMode) { - case 0: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), MINRF.channel[MINRF.currentChan] | 0x40); - break; - case 1: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_A[MINRF.currentChan]); - break; - case 2: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); - break; - case 3: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_A[MINRF.currentChan]); - break; - case 4: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); - break; - case 5: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); - break; - case 6: - MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); - break; - } - - - } - - return true; -} - -#ifdef DEBUG_TASMOTA_SENSOR -void MINRFshowBuffer(uint8_t (&buf)[32]){ - - - - - DEBUG_SENSOR_LOG(PSTR("MINRF: Buffer: %02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x ") - ,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11], - buf[12],buf[13],buf[14],buf[15],buf[16],buf[17],buf[18],buf[19],buf[20],buf[21],buf[22],buf[23], - buf[24],buf[25],buf[26],buf[27],buf[28],buf[29],buf[30],buf[31] - ); -} -#endif - - - - - - -void MINRFswapbuf(uint8_t *buf, uint8_t len) -{ - - while(len--) { - uint8_t a = *buf; - uint8_t v = 0; - if (a & 0x80) v |= 0x01; - if (a & 0x40) v |= 0x02; - if (a & 0x20) v |= 0x04; - if (a & 0x10) v |= 0x08; - if (a & 0x08) v |= 0x10; - if (a & 0x04) v |= 0x20; - if (a & 0x02) v |= 0x40; - if (a & 0x01) v |= 0x80; - *(buf++) = v; - } -} -# 382 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -void MINRFwhiten(uint8_t *buf, uint8_t len, uint8_t lfsr) -{ - while(len--) { - uint8_t res = 0; - - for (uint8_t i = 1; i; i <<= 1) { - if (lfsr & 0x01) { - lfsr ^= 0x88; - res |= i; - } - lfsr >>= 1; - } - *(buf++) ^= res; -#ifdef DEBUG_TASMOTA_SENSOR - MINRF.lsfrBuffer[31-len] = lfsr; -#endif - } -} - - - - -bool MINRFhandleBeacon(scan_entry_t * entry, uint32_t offset); - - - - - -void MINRFhandleScan(void){ - if(MINRFscanResult.size()>20 || MINRF.stopScan) { - MINRF.activeScan=false; - MINRFcomputefirstUsedPacketMode(); - uint32_t i = 0; - MINRFscanResult.erase(std::remove_if(MINRFscanResult.begin(), - MINRFscanResult.end(), - [&i](scan_entry_t e) { - if(e.showedUp>2) AddLog_P2(LOG_LEVEL_INFO,PSTR("MINRF: Beacon %02u: %02X%02X%02X%02X%02X%02X Cid: %04X Svc: %04X UUID: %04X"),i,e.mac[0],e.mac[1],e.mac[2],e.mac[3],e.mac[4],e.mac[5],e.cid,e.svc,e.uuid); - i++; - return ((e.showedUp < 3)); - }), - MINRFscanResult.end()); - MINRF.stopScan=false; - return; - } - - MINRFreverseMAC(MINRF.buffer.bleAdv.mac); - for(uint32_t i=0; i30) break; - uint32_t ADtype = _buf[i+1]; - - if (size+i>32+offset) size=32-i+offset-2; - if (size>30) break; - char _stemp[(size*2)]; - uint32_t backupSize; - switch(ADtype){ - case 0x01: - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MINRF: Flags: %02x"), _buf[i+2]); - break; - case 0x02: case 0x03: - entry->uuid = _buf[i+3]*256 + _buf[i+2]; - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MINRF: UUID: %04x"), entry->uuid); - success = true; - break; - case 0x08: case 0x09: - backupSize = _buf[i+size+1]; - _buf[i+size+1] = 0; - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MINRF: Name: %s"), (char*)&_buf[i+2]); - success = true; - _buf[i+size+1] = backupSize; - break; - case 0x0a: - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MINRF: TxPow: %02u"), _buf[i+2]); - break; - case 0xff: - entry->cid = _buf[i+3]*256 + _buf[i+2]; - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MINRF: Cid: %04x"), entry->cid); - ToHex_P((unsigned char*)&_buf+i+4,size-3,_stemp,(size*2)); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s"),_stemp); - success = true; - break; - case 0x16: - entry->svc = _buf[i+3]*256 + _buf[i+2]; - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MINRF: Svc: %04x"), entry->svc); - ToHex_P((unsigned char*)&_buf+i+4,size-3,_stemp,(size*2)); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s"),_stemp); - success = true; - break; - default: - ToHex_P((unsigned char*)&_buf+i+2,size-1,_stemp,(size*2)); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s"),_stemp); - } - i+=size; - } - MINRF.beacon.time = 0; - } - return success; -} - - - - - -void MINRFbeaconCounter(void){ - if(MINRF.beacon.active) { - MINRF.beacon.time++; - char stemp[20]; - snprintf_P(stemp, sizeof(stemp),PSTR("{%s:{\"Beacon\": %u}}"),D_CMND_NRF, MINRF.beacon.time); - AddLog_P2(LOG_LEVEL_DEBUG, stemp); - RulesProcessEvent(stemp); - } -} - - - - - -void MINRFcomputeBeaconPDU(void){ - for (uint32_t i = 0; i<3; i++){ - bleAdvPacket_t packet; - memcpy((uint8_t *)&packet.mac, (uint8_t *)&MINRF.beacon.mac, sizeof(packet.mac)); - MINRFreverseMAC(packet.mac); - MINRFwhiten((uint8_t *)&packet, sizeof(packet), MINRF.channel[i] | 0x40); - MINRFswapbuf((uint8_t*)&packet,sizeof(packet)); - uint32_t pdu = packet.mac[0]<<24 | packet.mac[1]<<16 | packet.mac[2]<<8 | packet.mac[3]; - MINRF.beacon.PDU[i] = pdu; - } -} -# 576 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -void MINRFreverseMAC(uint8_t _mac[]){ - uint8_t _reversedMAC[6]; - for (uint8_t i=0; i<6; i++){ - _reversedMAC[5-i] = _mac[i]; - } - memcpy(_mac,_reversedMAC, sizeof(_reversedMAC)); -} - - - - - - - -void MINRFMACStringToBytes(char* _string, uint8_t _mac[]) { - uint32_t index = 0; - while (index < 12) { - char c = _string[index]; - uint8_t value = 0; - if(c >= '0' && c <= '9') - value = (c - '0'); - else if (c >= 'A' && c <= 'F') - value = (10 + (c - 'A')); - _mac[(index/2)] += value << (((index + 1) % 2) * 4); - index++; - } - -} - - - - - -void MINRFcomputefirstUsedPacketMode(void){ - for (uint32_t i = 0; iCGD1) MINRF.firstUsedPacketMode=0; - break; - } - } -} - - - - - - -void MINRFchangePacketModeTo(uint8_t _mode) { - uint32_t (_nextchannel) = MINRF.currentChan+1; - if (_nextchannel>2) _nextchannel=0; - - switch(_mode){ - case 0: - NRF24radio.openReadingPipe(0,0x6B7D9171); - break; - case 1: - NRF24radio.openReadingPipe(0,kMINRFFloPDU[_nextchannel]); - break; - case 2: - NRF24radio.openReadingPipe(0,kMINRFMJPDU[_nextchannel]); - break; - case 3: - NRF24radio.openReadingPipe(0,kMINRFL2PDU[_nextchannel]); - break; - case 4: - NRF24radio.openReadingPipe(0,kMINRFL3PDU[_nextchannel]); - break; - case 5: - NRF24radio.openReadingPipe(0,kMINRFCGGPDU[_nextchannel]); - break; - case 6: - NRF24radio.openReadingPipe(0,kMINRFCGDPDU[_nextchannel]); - break; - } - - MINRF.packetMode = _mode; -} -# 663 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_61_MI_NRF24.ino" -uint32_t MINRFgetSensorSlot(uint8_t (&_serial)[6], uint16_t _type){ - - DEBUG_SENSOR_LOG(PSTR("MINRF: will test ID-type: %x"), _type); - bool _success = false; - for (uint32_t i=0;i<6;i++){ - if(_type == kMINRFSlaveID[i]){ - DEBUG_SENSOR_LOG(PSTR("MINRF: ID is type %u"), i); - _type = i+1; - _success = true; - } - else { - DEBUG_SENSOR_LOG(PSTR("MINRF: ID-type is not: %x"),kMINRFSlaveID[i]); - } - } - if(!_success) return 0xff; - - DEBUG_SENSOR_LOG(PSTR("MINRF: vector size %u"), MIBLEsensors.size()); - for(uint32_t i=0; i 2){ - MINRF.confirmedSensors++; - } - } -} - - - - - -void MINRFhandleMiBeaconPacket(void){ - MINRFreverseMAC(MINRF.buffer.miBeacon.Mac); - uint32_t _slot = MINRFgetSensorSlot(MINRF.buffer.miBeacon.Mac, MINRF.buffer.miBeacon.productID); - if(_slot==0xff) return; - DEBUG_SENSOR_LOG(PSTR("MINRF: slot %u, size vector: %u %u"),_slot,MIBLEsensors.size()); - - mi_sensor_t *_sensorVec = &MIBLEsensors.at(_slot); - float _tempFloat; - - if (_sensorVec->type==MJ_HT_V1 || _sensorVec->type==CGG1){ - memcpy(MINRFtempBuf,(uint8_t*)&MINRF.buffer.miBeacon.spare, 32-9); - memcpy((uint8_t*)&MINRF.buffer.miBeacon.type,MINRFtempBuf, 32-9); - } - - DEBUG_SENSOR_LOG(PSTR("%s at slot %u"), kNRFSlaveType[_sensorVec->type-1],_slot); - switch(MINRF.buffer.miBeacon.type){ - case 0x04: - _tempFloat=(float)(MINRF.buffer.miBeacon.temp)/10.0f; - if(_tempFloat<60){ - _sensorVec->temp=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 4: temp updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 4: U16: %u Temp"), MINRF.buffer.miBeacon.temp ); - break; - case 0x06: - _tempFloat=(float)(MINRF.buffer.miBeacon.hum)/10.0f; - if(_tempFloat<101){ - _sensorVec->hum=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 6: hum updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 6: U16: %u Hum"), MINRF.buffer.miBeacon.hum); - break; - case 0x07: - _sensorVec->lux=MINRF.buffer.miBeacon.lux & 0x00ffffff; - DEBUG_SENSOR_LOG(PSTR("Mode 7: U24: %u Lux"), MINRF.buffer.miBeacon.lux & 0x00ffffff); - break; - case 0x08: - _tempFloat =(float)MINRF.buffer.miBeacon.moist; - if(_tempFloat<100){ - _sensorVec->moisture=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 8: moisture updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 8: U8: %u Moisture"), MINRF.buffer.miBeacon.moist); - break; - case 0x09: - _tempFloat=(float)(MINRF.buffer.miBeacon.fert); - if(_tempFloat<65535){ - _sensorVec->fertility=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 9: fertility updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 9: U16: %u Fertility"), MINRF.buffer.miBeacon.fert); - break; - case 0x0a: - if(MINRF.buffer.miBeacon.bat<101){ - _sensorVec->bat = MINRF.buffer.miBeacon.bat; - DEBUG_SENSOR_LOG(PSTR("Mode a: bat updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode a: U8: %u %%"), MINRF.buffer.miBeacon.bat); - break; - case 0x0d: - _tempFloat=(float)(MINRF.buffer.miBeacon.HT.temp)/10.0f; - if(_tempFloat<60){ - _sensorVec->temp = _tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode d: temp updated")); - } - _tempFloat=(float)(MINRF.buffer.miBeacon.HT.hum)/10.0f; - if(_tempFloat<100){ - _sensorVec->hum = _tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode d: hum updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode d: U16: %x Temp U16: %x Hum"), MINRF.buffer.miBeacon.HT.temp, MINRF.buffer.miBeacon.HT.hum); - break; - } -} - - - - -void MINRFhandleLYWSD03Packet(void){ - - MINRFreverseMAC(MINRF.buffer.miBeacon.Mac); - uint32_t _slot = MINRFgetSensorSlot(MINRF.buffer.miBeacon.Mac, MINRF.buffer.miBeacon.productID); - DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); - if(_slot==0xff) return; - - MINRF_LOG_BUFFER(MINRF.streamBuffer); - MINRF_LOG_BUFFER(MINRF.lsfrBuffer); - MINRF_LOG_BUFFER(MINRF.buffer.raw); -} - - - - - -void MINRFhandleCGD1Packet(void){ - MINRFreverseMAC(MINRF.buffer.CGDPacket.serial); - uint32_t _slot = MINRFgetSensorSlot(MINRF.buffer.CGDPacket.serial, 0x0576); - DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); - if(_slot==0xff) return; - - switch (MINRF.buffer.CGDPacket.mode){ - case 0x0401: - float _tempFloat; - _tempFloat=(float)(MINRF.buffer.CGDPacket.temp)/10.0f; - if(_tempFloat<60){ - MIBLEsensors.at(_slot).temp = _tempFloat; - DEBUG_SENSOR_LOG(PSTR("CGD1: temp updated")); - } - _tempFloat=(float)(MINRF.buffer.CGDPacket.hum)/10.0f; - if(_tempFloat<100){ - MIBLEsensors.at(_slot).hum = _tempFloat; - DEBUG_SENSOR_LOG(PSTR("CGD1: hum updated")); - } - DEBUG_SENSOR_LOG(PSTR("CGD1: U16: %x Temp U16: %x Hum"), MINRF.buffer.CGDPacket.temp, MINRF.buffer.CGDPacket.hum); - break; - case 0x0102: - if(MINRF.buffer.CGDPacket.bat<101){ - MIBLEsensors.at(_slot).bat = MINRF.buffer.CGDPacket.bat; - DEBUG_SENSOR_LOG(PSTR("Mode a: bat updated")); - } - break; - default: - DEBUG_SENSOR_LOG(PSTR("MINRF: unexpected CGD1-packet")); - MINRF_LOG_BUFFER(MINRF.buffer.raw); - } -} - - - - - -void MINRF_EVERY_50_MSECOND() { - - if(MINRF.timer>6000){ - DEBUG_SENSOR_LOG(PSTR("MINRF: check for FAKE sensors")); - MINRFpurgeFakeSensors(); - MINRF.timer=0; - } - MINRF.timer++; - - if (!MINRFreceivePacket()){ - - } - - else { - switch (MINRF.packetMode) { - case 0: - if (MINRF.beacon.active){ - MINRFhandleBeacon(&MINRFdummyEntry,6); - } - else MINRFhandleScan(); - break; - case FLORA: case MJ_HT_V1: case LYWSD02: case CGG1: - MINRFhandleMiBeaconPacket(); - break; - case LYWSD03: - MINRFhandleLYWSD03Packet(); - break; - case CGD1: - MINRFhandleCGD1Packet(); - break; - default: - break; - } - } - if (MINRF.beacon.active || MINRF.activeScan) { - MINRF.firstUsedPacketMode=0; - } - - MINRF.packetMode = (MINRF.packetMode+1>CGD1) ? MINRF.firstUsedPacketMode : MINRF.packetMode+1; - for (uint32_t i = MINRF.packetMode; i 0) { - if (XdrvMailbox.payload == 0) XdrvMailbox.payload = MINRF.perPage; - MINRF.perPage = XdrvMailbox.payload; - } - else XdrvMailbox.payload = MINRF.perPage; - Response_P(S_JSON_NRF_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_NRF_IGNORE: - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload == 0){ - MINRF.ignore = 0; - } - else if (XdrvMailbox.payload < CGD1+1) { - bitSet(MINRF.ignore,XdrvMailbox.payload); - MINRFcomputefirstUsedPacketMode(); - MINRF.timer = 5900; - Response_P(S_JSON_NRF_COMMAND, command, kMINRFSlaveType[XdrvMailbox.payload-1]); - } - else if (XdrvMailbox.payload == 255) { - MINRF.ignore = 255; - } - } - Response_P(S_JSON_NRF_COMMAND_NVALUE, command, MINRF.ignore); - break; - case CMND_NRF_SCAN: - if (XdrvMailbox.data_len > 0) { - MINRF.beacon.active = false; - switch(XdrvMailbox.payload){ - case 0: - MINRF.activeScan = true; - MINRF.stopScan = false; - MINRFscanResult.erase(std::remove_if(MINRFscanResult.begin(), - MINRFscanResult.end(), - [](scan_entry_t&) { return true; }), - MINRFscanResult.end()); - break; - case 1: - MINRF.activeScan = true; - MINRF.stopScan = false; - break; - case 2: - MINRF.stopScan = true; - break; - } - Response_P(S_JSON_NRF_COMMAND_NVALUE, command, XdrvMailbox.payload); - } - break; - case CMND_NRF_BEACON: - if (XdrvMailbox.data_len > 0) { - if(XdrvMailbox.data_len<3){ - if (XdrvMailbox.payload < MINRFscanResult.size()) { - MINRFstartBeacon(XdrvMailbox.payload); - Response_P(S_JSON_NRF_COMMAND_NVALUE, command, XdrvMailbox.payload); - } - } - if (XdrvMailbox.data_len==12){ - memset(MINRF.beacon.mac,0,sizeof(MINRF.beacon.mac)); - MINRFMACStringToBytes(XdrvMailbox.data, MINRF.beacon.mac); - MINRF.beacon.time=0; - MINRF.beacon.active=true; - Response_P(S_JSON_NRF_COMMAND, command, XdrvMailbox.data); - } - MINRFcomputeBeaconPDU(); - } - break; - case CMND_NRF_CHAN: - if (XdrvMailbox.data_len == 1) { - switch(XdrvMailbox.payload){ - case 0: case 1: case 2: - bitRead(MINRF.channelIgnore,XdrvMailbox.payload) == 0 ? bitSet(MINRF.channelIgnore,XdrvMailbox.payload) : bitClear(MINRF.channelIgnore,XdrvMailbox.payload); - break; - } - } - Response_P(S_JSON_NRF_COMMAND_NVALUE, command, MINRF.channelIgnore); - break; - default: - - serviced = false; - break; - } - } else { - return false; - } - return serviced; -} - - - - - -const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u%%{e}"; -const char HTTP_MINRF_MAC[] PROGMEM = "{s}%s %s{m}%02x:%02x:%02x:%02x:%02x:%02x%{e}"; -const char HTTP_MINRF_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%dus/cm{e}"; -const char HTTP_MINRF_HL[] PROGMEM = "{s}
{m}
{e}"; -const char HTTP_NRF24NEW[] PROGMEM = "{s}%sL01%c{m}%u%s / %u{e}"; - -void MINRFShow(bool json) -{ - if (json) { - for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { - if(MIBLEsensors[i].showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MINRF: sensor not fully registered yet")); - break; - } - ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"),kMINRFSlaveType[MIBLEsensors[i].type-1],MIBLEsensors[i].serial[3],MIBLEsensors[i].serial[4],MIBLEsensors[i].serial[5]); - if (MIBLEsensors[i].type==FLORA && !isnan(MIBLEsensors[i].temp)){ - char stemp[FLOATSZ]; - dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, stemp); - ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), stemp); - - if(MIBLEsensors[i].lux!=0xffffffff){ - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); - } - if(!isnan(MIBLEsensors[i].moisture)){ - dtostrfd(MIBLEsensors[i].moisture, 0, stemp); - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%s"), stemp); - } - if(!isnan(MIBLEsensors[i].fertility)){ - dtostrfd(MIBLEsensors[i].fertility, 0, stemp); - ResponseAppend_P(PSTR(",\"Fertility\":%s"), stemp); - } - ResponseJsonEnd(); - } - if (MIBLEsensors[i].type>FLORA){ - if(!isnan(MIBLEsensors[i].temp) && !isnan(MIBLEsensors[i].hum)){ - ResponseAppendTHD(MIBLEsensors[i].temp,MIBLEsensors[i].hum); - } - if(MIBLEsensors[i].bat!=0x00){ - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); - } - ResponseJsonEnd(); - } - } - if(MINRF.beacon.active){ - ResponseAppend_P(PSTR(",\"Beacon\":{\"Timer\":%u}"),MINRF.beacon.time); - } - -#ifdef USE_WEBSERVER - } else { - static uint32_t _page = 0; - static uint32_t counter = 0; - int32_t i = _page * MINRF.perPage; - uint32_t j = i + MINRF.perPage; - - if (j+1>MINRF.confirmedSensors){ - j = MINRF.confirmedSensors; - } - char stemp[5] ={0}; - if (MINRF.confirmedSensors-(_page*MINRF.perPage)>1 && MINRF.perPage!=1) { - sprintf_P(stemp,"-%u",j); - } - if (MINRF.confirmedSensors==0) i=-1; - - WSContentSend_PD(HTTP_NRF24NEW, NRF24type, NRF24.chipType, i+1,stemp,MINRF.confirmedSensors); - for (i ; iFLORA){ - WSContentSend_THD(kMINRFSlaveType[MIBLEsensors[i].type-1], MIBLEsensors[i].temp, MIBLEsensors[i].hum); - if(MIBLEsensors[i].bat!=0x00){ - WSContentSend_PD(HTTP_BATTERY, kMINRFSlaveType[MIBLEsensors[i].type-1], MIBLEsensors[i].bat); - } - } - } - if(MINRF.beacon.active){ - WSContentSend_PD(HTTP_MINRF_HL); - WSContentSend_PD(HTTP_MINRF_HL); - WSContentSend_PD(HTTP_MINRF_MAC, F("Beacon"), D_MAC_ADDRESS, MINRF.beacon.mac[0], MINRF.beacon.mac[1],MINRF.beacon.mac[2],MINRF.beacon.mac[3],MINRF.beacon.mac[4],MINRF.beacon.mac[5]); - WSContentSend_PD(PSTR("{s}Beacon Time{m}%u seconds{e}"),MINRF.beacon.time); - } - if(counter>3) { - _page++; - counter = 0; - } - counter++; - if(MINRF.confirmedSensors%MINRF.perPage==0 && _page==MINRF.confirmedSensors/MINRF.perPage) _page=0; - if(_page>MINRF.confirmedSensors/MINRF.perPage) _page=0; -#endif - } -} - - - - - -bool Xsns61(uint8_t function) -{ - bool result = false; - if (NRF24.chipType) { - switch (function) { - case FUNC_INIT: - MINRFinitBLE(1); - AddLog_P2(LOG_LEVEL_INFO,PSTR("MINRF: started")); - break; - case FUNC_EVERY_50_MSECOND: - MINRF_EVERY_50_MSECOND(); - break; - case FUNC_EVERY_SECOND: - MINRFbeaconCounter(); - break; - case FUNC_COMMAND: - result = NRFCmd(); - break; - case FUNC_JSON_APPEND: - MINRFShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MINRFShow(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_62_MI_HM10.ino" -# 37 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_62_MI_HM10.ino" -#ifdef USE_HM10 - -#define XSNS_62 62 - -#include -#include - -TasmotaSerial *HM10Serial; -#define HM10_BAUDRATE 115200 - -#define HM10_MAX_TASK_NUMBER 12 -uint8_t HM10_TASK_LIST[HM10_MAX_TASK_NUMBER+1][2]; - -#define HM10_MAX_RX_BUF 64 - -struct { - uint8_t current_task_delay; - uint8_t last_command; - uint16_t perPage = 4; - uint16_t firmware; - uint32_t period; - uint32_t serialSpeed; - union { - uint32_t time; - uint8_t timebuf[4]; - }; - uint16_t autoScanInterval; - struct { - uint32_t awaiting:8; - uint32_t init:1; - uint32_t pending_task:1; - uint32_t connected:1; - uint32_t subscribed:1; - uint32_t autoScan:1; - - } mode; - struct { - uint8_t sensor; - - } state; -} HM10; - -#pragma pack(1) - - struct { - uint16_t temp; - uint8_t hum; - } LYWSD0x_HT; - struct { - uint8_t spare; - uint16_t temp; - uint16_t hum; - } CGD1_HT; - struct { - uint16_t temp; - uint8_t spare; - uint32_t lux; - uint8_t moist; - uint16_t fert; - } Flora_TLMF; - - -struct mi_beacon_t{ - uint16_t frame; - uint16_t productID; - uint8_t counter; - uint8_t Mac[6]; - uint8_t spare; - uint8_t type; - uint8_t ten; - uint8_t size; - union { - struct{ - uint16_t temp; - uint16_t hum; - }HT; - uint8_t bat; - uint16_t temp; - uint16_t hum; - uint32_t lux; - uint8_t moist; - uint16_t fert; - }; -}; -#pragma pack(0) - -struct mi_sensor_t{ - uint8_t type; - uint8_t serial[6]; - uint8_t showedUp; - float temp; - union { - struct { - float moisture; - float fertility; - uint32_t lux; - }; - struct { - float hum; - }; - }; - uint8_t bat; -}; - -std::vector MIBLEsensors; - - - - - -#define D_CMND_HM10 "HM10" - -const char S_JSON_HM10_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_HM10 "%s\":%d}"; -const char S_JSON_HM10_COMMAND[] PROGMEM = "{\"" D_CMND_HM10 "%s%s\"}"; -const char kHM10_Commands[] PROGMEM = "Scan|AT|Period|Baud|Time|Auto|Page"; - -#define FLORA 1 -#define MJ_HT_V1 2 -#define LYWSD02 3 -#define LYWSD03MMC 4 -#define CGG1 5 -#define CGD1 6 - -const uint16_t kHM10SlaveID[6]={ 0x0098, - 0x01aa, - 0x045b, - 0x055b, - 0x0347, - 0x0576 - }; - -const char kHM10SlaveType1[] PROGMEM = "Flora"; -const char kHM10SlaveType2[] PROGMEM = "MJ_HT_V1"; -const char kHM10SlaveType3[] PROGMEM = "LYWSD02"; -const char kHM10SlaveType4[] PROGMEM = "LYWSD03"; -const char kHM10SlaveType5[] PROGMEM = "CGG1"; -const char kHM10SlaveType6[] PROGMEM = "CGD1"; -const char * kHM10SlaveType[] PROGMEM = {kHM10SlaveType1,kHM10SlaveType2,kHM10SlaveType3,kHM10SlaveType4,kHM10SlaveType5,kHM10SlaveType6}; - - - - - -enum HM10_Commands { - CMND_HM10_DISC_SCAN, - CMND_HM10_AT, - CMND_HM10_PERIOD, - CMND_HM10_BAUD, - CMND_HM10_TIME, - CMND_HM10_AUTO, - CMND_HM10_PAGE - }; - -enum HM10_awaitData: uint8_t { - none = 0, - tempHumLY = 1, - TLMF = 2, - bat = 3, - tempHumCGD1 = 4, - discScan = 5, - tempHumMJ = 6 - }; - - - - - -#define TASK_HM10_NOTASK 0 -#define TASK_HM10_ROLE1 1 -#define TASK_HM10_IMME1 2 -#define TASK_HM10_RENEW 3 -#define TASK_HM10_RESET 4 -#define TASK_HM10_DISC 5 -#define TASK_HM10_CONN 6 -#define TASK_HM10_VERSION 7 -#define TASK_HM10_NAME 8 -#define TASK_HM10_FEEDBACK 9 -#define TASK_HM10_DISCONN 10 -#define TASK_HM10_SUB_L3 11 - -#define TASK_HM10_SCAN9 13 -#define TASK_HM10_UN_L3 14 - -#define TASK_HM10_READ_BT_L3 16 -#define TASK_HM10_SUB_L2 17 -#define TASK_HM10_UN_L2 18 -#define TASK_HM10_READ_BT_L2 19 -#define TASK_HM10_TIME_L2 20 -#define TASK_HM10_SHOW0 21 -#define TASK_HM10_READ_BF_FL 22 -#define TASK_HM10_CALL_TLMF_FL 23 -#define TASK_HM10_READ_TLMF_FL 24 -#define TASK_HM10_SUB_HT_CGD1 25 -#define TASK_HM10_UN_HT_CGD1 26 -#define TASK_HM10_READ_B_CGD1 27 - -#define TASK_HM10_READ_B_MJ 29 -#define TASK_HM10_SUB_HT_MJ 30 - -#define TASK_HM10_STATUS_EVENT 32 - -#define TASK_HM10_DONE 99 - - - - - -void HM10_Launchtask(uint8_t task, uint8_t slot, uint8_t delay){ - HM10_TASK_LIST[slot][0] = task; - HM10_TASK_LIST[slot][1] = delay; - HM10_TASK_LIST[slot+1][0] = TASK_HM10_NOTASK; - HM10.current_task_delay = HM10_TASK_LIST[0][1]; -} - -void HM10_TaskReplaceInSlot(uint8_t task, uint8_t slot){ - HM10.last_command = HM10_TASK_LIST[slot][0]; - HM10_TASK_LIST[slot][0] = task; -} - -void HM10_ReverseMAC(uint8_t _mac[]){ - uint8_t _reversedMAC[6]; - for (uint8_t i=0; i<6; i++){ - _reversedMAC[5-i] = _mac[i]; - } - memcpy(_mac,_reversedMAC, sizeof(_reversedMAC)); -} - - - - - -void HM10_Reset(void) { HM10_Launchtask(TASK_HM10_DISCONN,0,1); - HM10_Launchtask(TASK_HM10_ROLE1,1,1); - HM10_Launchtask(TASK_HM10_IMME1,2,1); - HM10_Launchtask(TASK_HM10_RESET,3,1); - HM10_Launchtask(TASK_HM10_VERSION,4,10); - HM10_Launchtask(TASK_HM10_SCAN9,5,2); - HM10_Launchtask(TASK_HM10_DISC,6,2); - HM10_Launchtask(TASK_HM10_STATUS_EVENT,7,2); - } - -void HM10_Discovery_Scan(void) { - HM10_Launchtask(TASK_HM10_DISCONN,0,1); - HM10_Launchtask(TASK_HM10_DISC,1,5); - HM10_Launchtask(TASK_HM10_STATUS_EVENT,2,2); - } - -void HM10_Read_LYWSD03(void) { - HM10_Launchtask(TASK_HM10_CONN,0,1); - HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); - HM10_Launchtask(TASK_HM10_SUB_L3,2,20); - HM10_Launchtask(TASK_HM10_UN_L3,3,80); - HM10_Launchtask(TASK_HM10_READ_BT_L3,4,5); - HM10_Launchtask(TASK_HM10_DISCONN,5,5); - } - -void HM10_Read_LYWSD02(void) { - HM10_Launchtask(TASK_HM10_CONN,0,1); - HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); - HM10_Launchtask(TASK_HM10_SUB_L2,2,20); - HM10_Launchtask(TASK_HM10_UN_L2,3,80); - HM10_Launchtask(TASK_HM10_READ_BT_L2,4,5); - HM10_Launchtask(TASK_HM10_DISCONN,5,5); - } - -void HM10_Time_LYWSD02(void) { - HM10_Launchtask(TASK_HM10_DISCONN,0,0); - HM10_Launchtask(TASK_HM10_CONN,1,5); - HM10_Launchtask(TASK_HM10_FEEDBACK,2,35); - HM10_Launchtask(TASK_HM10_TIME_L2,3,20); - HM10_Launchtask(TASK_HM10_DISCONN,4,5); - } - -void HM10_Read_Flora(void) { - HM10_Launchtask(TASK_HM10_DISCONN,0,0); - HM10_Launchtask(TASK_HM10_CONN,1,1); - HM10_Launchtask(TASK_HM10_FEEDBACK,2,5); - HM10_Launchtask(TASK_HM10_READ_BF_FL,3,20); - HM10_Launchtask(TASK_HM10_CALL_TLMF_FL,4,30); - HM10_Launchtask(TASK_HM10_DISCONN,5,10); - } - -void HM10_Read_CGD1(void) { - HM10_Launchtask(TASK_HM10_CONN,0,1); - HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); - HM10_Launchtask(TASK_HM10_SUB_HT_CGD1,2,20); - HM10_Launchtask(TASK_HM10_UN_HT_CGD1,3,10); - HM10_Launchtask(TASK_HM10_READ_B_CGD1,4,5); - HM10_Launchtask(TASK_HM10_DISCONN,5,5); - } - -void HM10_Read_MJ_HT_V1(void) { - HM10_Launchtask(TASK_HM10_CONN,0,1); - HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); - HM10_Launchtask(TASK_HM10_READ_B_MJ,2,20); - HM10_Launchtask(TASK_HM10_SUB_HT_MJ,3,10); - HM10_Launchtask(TASK_HM10_DISCONN,4,5); - } -# 343 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_62_MI_HM10.ino" -uint32_t MIBLEgetSensorSlot(uint8_t (&_serial)[6], uint16_t _type){ - - DEBUG_SENSOR_LOG(PSTR("%s: will test ID-type: %x"),D_CMND_HM10, _type); - bool _success = false; - for (uint32_t i=0;i<6;i++){ - if(_type == kHM10SlaveID[i]){ - DEBUG_SENSOR_LOG(PSTR("HM10: ID is type %u"), i); - _type = i+1; - _success = true; - } - else { - DEBUG_SENSOR_LOG(PSTR("%s: ID-type is not: %x"),D_CMND_HM10,kHM10SlaveID[i]); - } - } - if(!_success) return 0xff; - - DEBUG_SENSOR_LOG(PSTR("%s: vector size %u"),D_CMND_HM10, MIBLEsensors.size()); - for(uint32_t i=0; ibegin(HM10.serialSpeed)) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s start serial communication fixed to 115200 baud"),D_CMND_HM10); - if (HM10Serial->hardwareSerial()) { - ClaimSerial(); - DEBUG_SENSOR_LOG(PSTR("%s: claim HW"),D_CMND_HM10); - } - HM10_Reset(); - HM10.mode.pending_task = 1; - HM10.mode.init = 1; - HM10.period = Settings.tele_period; - DEBUG_SENSOR_LOG(PSTR("%s_TASK_LIST initialized, now return to main loop"),D_CMND_HM10); - } - return; -} - - - - - -void HM10parseMiBeacon(char * _buf, uint32_t _slot){ - float _tempFloat; - mi_beacon_t _beacon; - if (MIBLEsensors[_slot].type==MJ_HT_V1 || MIBLEsensors[_slot].type==CGG1){ - memcpy((uint8_t*)&_beacon+1,(uint8_t*)_buf, sizeof(_beacon)); - memcpy((uint8_t*)&_beacon.Mac,(uint8_t*)&_beacon.Mac+1,6); - } - else{ - memcpy((void*)&_beacon,(void*)_buf, sizeof(_beacon)); - } - HM10_ReverseMAC(_beacon.Mac); - if(memcmp(_beacon.Mac,MIBLEsensors[_slot].serial,sizeof(_beacon.Mac))!=0){ - if (MIBLEsensors[_slot].showedUp>3) return; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: remove garbage sensor"),D_CMND_HM10); - DEBUG_SENSOR_LOG(PSTR("%s i: %x %x %x %x %x %x"),D_CMND_HM10, MIBLEsensors[_slot].serial[5], MIBLEsensors[_slot].serial[4],MIBLEsensors[_slot].serial[3],MIBLEsensors[_slot].serial[2],MIBLEsensors[_slot].serial[1],MIBLEsensors[_slot].serial[0]); - DEBUG_SENSOR_LOG(PSTR("%s n: %x %x %x %x %x %x"),D_CMND_HM10, _beacon.Mac[5], _beacon.Mac[4], _beacon.Mac[3],_beacon.Mac[2],_beacon.Mac[1],_beacon.Mac[0]); - MIBLEsensors.erase(MIBLEsensors.begin()+_slot); - return; - } - if (MIBLEsensors[_slot].showedUp<4) MIBLEsensors[_slot].showedUp++; - - DEBUG_SENSOR_LOG(PSTR("MiBeacon type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]); - DEBUG_SENSOR_LOG(PSTR(" type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[8],(uint8_t)_buf[9],(uint8_t)_buf[10],(uint8_t)_buf[11],(uint8_t)_buf[12],(uint8_t)_buf[13],(uint8_t)_buf[14],(uint8_t)_buf[15]); - - if(MIBLEsensors[_slot].type==4 || MIBLEsensors[_slot].type==6){ - DEBUG_SENSOR_LOG(PSTR("LYWSD03 and CGD1 no support for MiBeacon, type %u"),MIBLEsensors[_slot].type); - return; - } - DEBUG_SENSOR_LOG(PSTR("%s at slot %u"), kHM10SlaveType[MIBLEsensors[_slot].type-1],_slot); - switch(_beacon.type){ - case 0x04: - _tempFloat=(float)(_beacon.temp)/10.0f; - if(_tempFloat<60){ - MIBLEsensors[_slot].temp=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 4: temp updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 4: U16: %u Temp"), _beacon.temp ); - break; - case 0x06: - _tempFloat=(float)(_beacon.hum)/10.0f; - if(_tempFloat<101){ - MIBLEsensors[_slot].hum=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 6: hum updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 6: U16: %u Hum"), _beacon.hum); - break; - case 0x07: - MIBLEsensors[_slot].lux=_beacon.lux & 0x00ffffff; - DEBUG_SENSOR_LOG(PSTR("Mode 7: U24: %u Lux"), _beacon.lux & 0x00ffffff); - break; - case 0x08: - _tempFloat =(float)_beacon.moist; - if(_tempFloat<100){ - MIBLEsensors[_slot].moisture=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 8: moisture updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 8: U8: %u Moisture"), _beacon.moist); - break; - case 0x09: - _tempFloat=(float)(_beacon.fert); - if(_tempFloat<65535){ - MIBLEsensors[_slot].fertility=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 9: fertility updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode 9: U16: %u Fertility"), _beacon.fert); - break; - case 0x0a: - if(_beacon.bat<101){ - MIBLEsensors[_slot].bat = _beacon.bat; - DEBUG_SENSOR_LOG(PSTR("Mode a: bat updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode a: U8: %u %%"), _beacon.bat); - break; - case 0x0d: - _tempFloat=(float)(_beacon.HT.temp)/10.0f; - if(_tempFloat<60){ - MIBLEsensors[_slot].temp = _tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode d: temp updated")); - } - _tempFloat=(float)(_beacon.HT.hum)/10.0f; - if(_tempFloat<100){ - MIBLEsensors[_slot].hum = _tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode d: hum updated")); - } - DEBUG_SENSOR_LOG(PSTR("Mode d: U16: %x Temp U16: %x Hum"), _beacon.HT.temp, _beacon.HT.hum); - break; - } -} - -void HM10ParseResponse(char *buf, uint16_t bufsize) { - if (!strncmp(buf,"OK",2)) { - DEBUG_SENSOR_LOG(PSTR("%s: got OK"),D_CMND_HM10); - } - if (!strncmp(buf,"HMSoft",6)) { - const char* _fw = "000"; - memcpy((void *)_fw,(void *)(buf+8),3); - HM10.firmware = atoi(_fw); - DEBUG_SENSOR_LOG(PSTR("%s: Firmware: %d"),D_CMND_HM10, HM10.firmware); - return; - } - char * _pos = strstr(buf, "ISA:"); - if(_pos) { - uint8_t _newMacArray[6] = {0}; - memcpy((void *)_newMacArray,(void *)(_pos+4),6); - HM10_ReverseMAC(_newMacArray); - DEBUG_SENSOR_LOG(PSTR("%s: MAC-array: %02x%02x%02x%02x%02x%02x"),D_CMND_HM10,_newMacArray[0],_newMacArray[1],_newMacArray[2],_newMacArray[3],_newMacArray[4],_newMacArray[5]); - uint16_t _type=0xffff; - - for (uint32_t idx =10;idxavailable()) { - - if(iread(); - } - i++; - success = true; - } - - if(i==0) return success; - - switch (HM10.mode.awaiting){ - case bat: - if (HM10.mode.connected) { - if (HM10readBat(ret)){ - HM10.mode.awaiting = none; - HM10.current_task_delay = 0; - } - } - break; - case tempHumLY: - if (HM10.mode.connected) HM10readHT_LY(ret); - break; - case tempHumCGD1: - if (HM10.mode.connected) HM10readHT_CGD1(ret); - break; - case TLMF: - if (HM10.mode.connected) HM10readTLMF(ret); - break; - case discScan: - if(success) { - HM10ParseResponse(ret,i); - } - break; - case tempHumMJ: - if (HM10.mode.connected) HM10readHT_MJ_HT_V1(ret); - break; - case none: - if(success) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: response: %s"),D_CMND_HM10, (char *)ret); - - - - HM10ParseResponse(ret,i); - } - break; - } - memset(ret,0,i); - return success; -} - - - - - -void HM10_TaskEvery100ms(){ - if (HM10.current_task_delay == 0) { - uint8_t i = 0; - bool runningTaskLoop = true; - while (runningTaskLoop) { - switch(HM10_TASK_LIST[i][0]) { - case TASK_HM10_ROLE1: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: set role to 1"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+ROLE1"); - break; - case TASK_HM10_IMME1: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: set imme to 1"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+IMME1"); - break; - case TASK_HM10_DISC: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: start discovery"),D_CMND_HM10); - HM10.current_task_delay = 100; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10.mode.awaiting = discScan; - HM10Serial->write("AT+DISA?"); - break; - case TASK_HM10_VERSION: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read version"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+VERR?"); - break; - case TASK_HM10_NAME: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read name"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+NAME?"); - break; - case TASK_HM10_CONN: - char _con[20]; - sprintf_P(_con,"AT+CON%02x%02x%02x%02x%02x%02x",MIBLEsensors[HM10.state.sensor].serial[0],MIBLEsensors[HM10.state.sensor].serial[1],MIBLEsensors[HM10.state.sensor].serial[2],MIBLEsensors[HM10.state.sensor].serial[3],MIBLEsensors[HM10.state.sensor].serial[4],MIBLEsensors[HM10.state.sensor].serial[5]); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: connect %s"),D_CMND_HM10, _con); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write(_con); - HM10.mode.awaiting = none; - HM10.mode.connected = true; - break; - case TASK_HM10_DISCONN: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: disconnect"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT"); - break; - case TASK_HM10_RESET: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: Reset Device"),D_CMND_HM10); - HM10Serial->write("AT+RESET"); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - break; - case TASK_HM10_SUB_L3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe"),D_CMND_HM10); - HM10.current_task_delay = 25; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - HM10.mode.awaiting = tempHumLY; - runningTaskLoop = false; - HM10Serial->write("AT+NOTIFY_ON0037"); - break; - case TASK_HM10_UN_L3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: un-subscribe"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10.mode.awaiting = none; - HM10Serial->write("AT+NOTIFYOFF0037"); - break; - case TASK_HM10_SUB_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe"),D_CMND_HM10); - HM10.current_task_delay = 25; - HM10.mode.awaiting = tempHumLY; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+NOTIFY_ON003C"); - break; - case TASK_HM10_UN_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: un-subscribe"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10.mode.awaiting = none; - HM10Serial->write("AT+NOTIFYOFF003C"); - break; - case TASK_HM10_TIME_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: set time"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10.time = Rtc.utc_time; - HM10Serial->write("AT+SEND_DATAWR002F"); - HM10Serial->write(HM10.timebuf,4); - HM10Serial->write(Rtc.time_timezone / 60); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s Time-string: %x%x%x%x%x"),D_CMND_HM10, HM10.timebuf[0],HM10.timebuf[1],HM10.timebuf[2],HM10.timebuf[3],(Rtc.time_timezone /60)); - break; - case TASK_HM10_READ_BT_L3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 003A"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+READDATA003A?"); - HM10.mode.awaiting = bat; - break; - case TASK_HM10_READ_BT_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0043"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+READDATA0043?"); - HM10.mode.awaiting = bat; - break; - case TASK_HM10_READ_BF_FL: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0038"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+READDATA0038?"); - HM10.mode.awaiting = bat; - break; - case TASK_HM10_CALL_TLMF_FL: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: write to handle 0033"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_READ_TLMF_FL,i); - runningTaskLoop = false; - HM10Serial->write("AT+SEND_DATAWR0033"); - HM10Serial->write(0xa0); - HM10Serial->write(0x1f); - HM10.mode.awaiting = none; - break; - case TASK_HM10_READ_TLMF_FL: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0035"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+READDATA0035?"); - HM10.mode.awaiting = TLMF; - break; - case TASK_HM10_READ_B_CGD1: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0011"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+READDATA0011?"); - HM10.mode.awaiting = bat; - break; - case TASK_HM10_SUB_HT_CGD1: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe 4b"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10.mode.awaiting = tempHumCGD1; - HM10Serial->write("AT+NOTIFY_ON004b"); - break; - case TASK_HM10_UN_HT_CGD1: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: un-subscribe 4b"),D_CMND_HM10); - HM10.current_task_delay = 5; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10.mode.awaiting = none; - HM10Serial->write("AT+NOTIFYOFF004b"); - break; - case TASK_HM10_SCAN9: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: scan time to 9"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+SCAN9"); - break; - case TASK_HM10_READ_B_MJ: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0x18"),D_CMND_HM10); - HM10.current_task_delay = 2; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+READDATA0018?"); - HM10.mode.awaiting = bat; - break; - case TASK_HM10_SUB_HT_MJ: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe to 0x0f"),D_CMND_HM10); - HM10.current_task_delay = 10; - HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - runningTaskLoop = false; - HM10Serial->write("AT+NOTIFY_ON000F"); - HM10.mode.awaiting = tempHumMJ; - break; - case TASK_HM10_FEEDBACK: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: get response"),D_CMND_HM10); - HM10SerialHandleFeedback(); - HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; - HM10_TASK_LIST[i][0] = TASK_HM10_DONE; - runningTaskLoop = false; - break; - case TASK_HM10_STATUS_EVENT: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: show status"),D_CMND_HM10); - HM10StatusInfo(); - HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; - HM10_TASK_LIST[i][0] = TASK_HM10_DONE; - runningTaskLoop = false; - break; - case TASK_HM10_DONE: - - - if(HM10_TASK_LIST[i+1][0] == TASK_HM10_NOTASK) { - DEBUG_SENSOR_LOG(PSTR("%sno Tasks left"),D_CMND_HM10); - DEBUG_SENSOR_LOG(PSTR("%sHM10_TASK_DONE current slot %u"),D_CMND_HM10, i); - for (uint8_t j = 0; j < HM10_MAX_TASK_NUMBER+1; j++) { - DEBUG_SENSOR_LOG(PSTR("%sHM10_TASK cleanup slot %u"),D_CMND_HM10, j); - HM10_TASK_LIST[j][0] = TASK_HM10_NOTASK; - HM10_TASK_LIST[j][1] = 0; - } - runningTaskLoop = false; - HM10.mode.pending_task = 0; - break; - } - } - i++; - } - } - else { - HM10.current_task_delay--; - } -} - -void HM10StatusInfo(){ - char stemp[20]; - snprintf_P(stemp, sizeof(stemp),PSTR("{%s:{\"found\": %u}}"),D_CMND_HM10, MIBLEsensors.size()); - AddLog_P2(LOG_LEVEL_INFO, stemp); - RulesProcessEvent(stemp); -} - - - - - - -void HM10EverySecond(bool restart){ - static uint32_t _counter = 0; - static uint32_t _nextSensorSlot = 0; - static uint32_t _lastDiscovery = 0; - - if(restart){ - _counter = 0; - _lastDiscovery = 0; - return; - } - - if(HM10.firmware == 0) return; - if(HM10.mode.pending_task == 1) return; - if(MIBLEsensors.size()==0 && !HM10.mode.autoScan) return; - - if((HM10.period-_counter)>15 && HM10.mode.autoScan) { - if(_counter-_lastDiscovery>HM10.autoScanInterval){ - HM10_Discovery_Scan(); - HM10.mode.pending_task = 1; - _counter+=12; - _lastDiscovery = _counter; - return; - } - } - - if(_counter==0) { - HM10.state.sensor = _nextSensorSlot; - _nextSensorSlot++; - HM10.mode.pending_task = 1; - switch(MIBLEsensors[HM10.state.sensor].type){ - case FLORA: - HM10_Read_Flora(); - break; - case MJ_HT_V1: case CGG1: - HM10_Read_MJ_HT_V1(); - break; - case LYWSD02: - HM10_Read_LYWSD02(); - break; - case LYWSD03MMC: - HM10_Read_LYWSD03(); - break; - case CGD1: - HM10_Read_CGD1(); - break; - default: - HM10.mode.pending_task = 0; - } - if (HM10.state.sensor==MIBLEsensors.size()-1) { - _nextSensorSlot= 0; - _counter++; - } - DEBUG_SENSOR_LOG(PSTR("%s: active sensor now: %u"),D_CMND_HM10, HM10.state.sensor); - } - else _counter++; - if (_counter>HM10.period) { - _counter = 0; - _lastDiscovery = 0; - } -} - - - - - -bool HM10Cmd(void) { - char command[CMDSZ]; - bool serviced = true; - uint8_t disp_len = strlen(D_CMND_HM10); - - if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_HM10), disp_len)) { - uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kHM10_Commands); - switch (command_code) { - case CMND_HM10_PERIOD: - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload==1) { - HM10EverySecond(true); - XdrvMailbox.payload = HM10.period; - } - else { - HM10.period = XdrvMailbox.payload; - } - } - else { - XdrvMailbox.payload = HM10.period; - } - Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_HM10_AUTO: - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload>0) { - HM10.mode.autoScan = 1; - HM10.autoScanInterval = XdrvMailbox.payload; - } - else { - HM10.mode.autoScan = 0; - HM10.autoScanInterval = 0; - } - } - else { - XdrvMailbox.payload = HM10.autoScanInterval; - } - Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_HM10_BAUD: - if (XdrvMailbox.data_len > 0) { - HM10.serialSpeed = XdrvMailbox.payload; - HM10Serial->begin(HM10.serialSpeed); - } - else { - XdrvMailbox.payload = HM10.serialSpeed; - } - Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_HM10_TIME: - if (XdrvMailbox.data_len > 0) { - if(MIBLEsensors.size()>XdrvMailbox.payload){ - if(MIBLEsensors[XdrvMailbox.payload].type == LYWSD02){ - HM10.state.sensor = XdrvMailbox.payload; - HM10_Time_LYWSD02(); - } - } - } - Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_HM10_PAGE: - if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload == 0) XdrvMailbox.payload = HM10.perPage; - HM10.perPage = XdrvMailbox.payload; - } - else XdrvMailbox.payload = HM10.perPage; - Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); - break; - case CMND_HM10_AT: - HM10Serial->write("AT"); - if (strlen(XdrvMailbox.data)!=0) { - HM10Serial->write("+"); - HM10Serial->write(XdrvMailbox.data); - Response_P(S_JSON_HM10_COMMAND, ":AT+",XdrvMailbox.data); - } - else Response_P(S_JSON_HM10_COMMAND, ":AT",XdrvMailbox.data); - break; - case CMND_HM10_DISC_SCAN: - HM10_Discovery_Scan(); - Response_P(S_JSON_HM10_COMMAND, command, ""); - break; - default: - - serviced = false; - break; - } - } else { - return false; - } - return serviced; -} - - - - - - -const char HTTP_HM10[] PROGMEM = "{s}HM10 V%u{m}%u%s / %u{e}"; -const char HTTP_HM10_SERIAL[] PROGMEM = "{s}%s %s{m}%02x:%02x:%02x:%02x:%02x:%02x%{e}"; -const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u%%{e}"; -const char HTTP_HM10_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%uus/cm{e}"; -const char HTTP_HM10_HL[] PROGMEM = "{s}
{m}
{e}"; - -void HM10Show(bool json) -{ - if (json) { - for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { - char slave[33]; - sprintf_P(slave,"%s-%02x%02x%02x",kHM10SlaveType[MIBLEsensors[i].type-1],MIBLEsensors[i].serial[3],MIBLEsensors[i].serial[4],MIBLEsensors[i].serial[5]); - ResponseAppend_P(PSTR(",\"%s\":{"),slave); - if (MIBLEsensors[i].type==FLORA){ - if(!isnan(MIBLEsensors[i].temp)){ - char temperature[FLOATSZ]; - dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature); - ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); - } - else { - ResponseAppend_P(PSTR("}")); - continue; - } - if(MIBLEsensors[i].lux!=0x0ffffff){ - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); - } - if(!isnan(MIBLEsensors[i].moisture)){ - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%d"), MIBLEsensors[i].moisture); - } - if(!isnan(MIBLEsensors[i].fertility)){ - ResponseAppend_P(PSTR(",\"Fertility\":%d"), MIBLEsensors[i].fertility); - } - } - if (MIBLEsensors[i].type>FLORA){ - if(!isnan(MIBLEsensors[i].hum) && !isnan(MIBLEsensors[i].temp)){ - ResponseAppendTHD(MIBLEsensors[i].temp, MIBLEsensors[i].hum); - } - } - if(MIBLEsensors[i].bat!=0x00){ - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); - } - ResponseAppend_P(PSTR("}")); - } -#ifdef USE_WEBSERVER - } else { - static uint16_t _page = 0; - static uint16_t _counter = 0; - int32_t i = _page * HM10.perPage; - uint32_t j = i + HM10.perPage; - if (j+1>MIBLEsensors.size()){ - j = MIBLEsensors.size(); - } - char stemp[5] ={0}; - if (MIBLEsensors.size()-(_page*HM10.perPage)>1 && HM10.perPage!=1) { - sprintf_P(stemp,"-%u",j); - } - if (MIBLEsensors.size()==0) i=-1; - - WSContentSend_PD(HTTP_HM10, HM10.firmware, i+1,stemp,MIBLEsensors.size()); - for (i; iFLORA){ - if(!isnan(MIBLEsensors[i].hum) && !isnan(MIBLEsensors[i].temp)){ - WSContentSend_THD(kHM10SlaveType[MIBLEsensors[i].type-1], MIBLEsensors[i].temp, MIBLEsensors[i].hum); - } - } - if(MIBLEsensors[i].bat!=0x00){ - WSContentSend_PD(HTTP_BATTERY, kHM10SlaveType[MIBLEsensors[i].type-1], MIBLEsensors[i].bat); - } - } - _counter++; - if(_counter>3) { - _page++; - _counter=0; - } - if(MIBLEsensors.size()%HM10.perPage==0 && _page==MIBLEsensors.size()/HM10.perPage) _page=0; - if(_page>MIBLEsensors.size()/HM10.perPage) _page=0; -#endif - } -} - - - - - -bool Xsns62(uint8_t function) -{ - bool result = false; - - if ((pin[GPIO_HM10_RX] < 99) && (pin[GPIO_HM10_TX] < 99)) { - switch (function) { - case FUNC_INIT: - HM10SerialInit(); - break; - case FUNC_EVERY_50_MSECOND: - HM10SerialHandleFeedback(); - break; - case FUNC_EVERY_100_MSECOND: - if (HM10_TASK_LIST[0][0] != TASK_HM10_NOTASK) { - HM10_TaskEvery100ms(); - } - break; - case FUNC_EVERY_SECOND: - HM10EverySecond(false); - break; - case FUNC_COMMAND: - result = HM10Cmd(); - break; - case FUNC_JSON_APPEND: - HM10Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HM10Show(0); - break; -#endif - } - } - return result; -} -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_63_aht1x.ino" -# 21 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_63_aht1x.ino" -#ifdef USE_I2C -#ifdef USE_AHT1x -# 38 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_63_aht1x.ino" -#define XSNS_63 63 -#define XI2C_43 43 - -#define AHT1X_ADDR1 0x38 -#define AHT1X_ADDR2 0x39 - -#define AHT1X_MAX_SENSORS 2 - -#define AHT_HUMIDITY_CONST 100 -#define AHT_TEMPERATURE_CONST 200 -#define AHT_TEMPERATURE_OFFSET 50 -#define KILOBYTE_CONST 1048576.0f - -#define AHT1X_CMD_DELAY 40 -#define AHT1X_RST_DELAY 30 -#define AHT1X_MEAS_DELAY 80 - -uint8_t AHTSetCalCmd[3] = {0xE1, 0x08, 00}; -uint8_t AHTSetCycleCmd[3] = {0xE1, 0x28, 00}; -uint8_t AHTMeasureCmd[3] = {0xAC, 0x33, 00}; -uint8_t AHTResetCmd = 0xBA; - -const char ahtTypes[] PROGMEM = "AHT1X|AHT1X"; -uint8_t aht1x_addresses[] = { AHT1X_ADDR1, AHT1X_ADDR2 }; -uint8_t aht1x_count = 0; -uint8_t aht1x_Pcount = 0; - -struct AHT1XSTRUCT -{ - float humidity = NAN; - float temperature = NAN; - uint8_t address; - char types[6]; -} aht1x_sensors[AHT1X_MAX_SENSORS]; - -bool AHT1XWrite(uint8_t aht1x_idx) -{ - Wire.beginTransmission(aht1x_sensors[aht1x_idx].address); - Wire.write(AHTMeasureCmd, 3); - if (Wire.endTransmission() != 0) - return false; -} - -bool AHT1XRead(uint8_t aht1x_idx) -{ - uint8_t data[6]; - Wire.requestFrom(aht1x_sensors[aht1x_idx].address, (uint8_t) 6); - for(uint8_t i = 0; Wire.available() > 0; i++){ - data[i] = Wire.read(); - } - if ((data[0] & 0x80) == 0x80) return false; - - aht1x_sensors[aht1x_idx].humidity = (((data[1] << 12)| (data[2] << 4) | data[3] >> 4) * AHT_HUMIDITY_CONST / KILOBYTE_CONST); - aht1x_sensors[aht1x_idx].temperature = ((AHT_TEMPERATURE_CONST * (((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]) / KILOBYTE_CONST) - AHT_TEMPERATURE_OFFSET); - - return (!isnan(aht1x_sensors[aht1x_idx].temperature) && !isnan(aht1x_sensors[aht1x_idx].humidity) && (aht1x_sensors[aht1x_idx].humidity != 0)); -} - - - - - -void AHT1XPoll(void) -{ - aht1x_Pcount++; - switch (aht1x_Pcount) { - case 10: - AHT1XWrite(0); - break; - case 11: - AHT1XRead(0); - aht1x_Pcount = 0; - break; - } -} - -unsigned char AHT1XReadStatus(uint8_t aht1x_address) -{ - uint8_t result = 0; - Wire.requestFrom(aht1x_address, (uint8_t) 1); - result = Wire.read(); - return result; -} - -void AHT1XReset(uint8_t aht1x_address) -{ - Wire.beginTransmission(aht1x_address); - Wire.write(AHTResetCmd); - Wire.endTransmission(); - delay(AHT1X_RST_DELAY); -} - - -bool AHT1XInit(uint8_t aht1x_address) -{ - Wire.beginTransmission(aht1x_address); - Wire.write(AHTSetCalCmd, 3); - if (Wire.endTransmission() != 0) return false; - delay(AHT1X_CMD_DELAY); - if((AHT1XReadStatus(aht1x_address) & 0x68) == 0x08) - return true; - return false; -} - -void AHT1XDetect(void) -{ - for (uint8_t i = 0; i < AHT1X_MAX_SENSORS; i++) { - if (I2cActive(aht1x_addresses[i])) { continue; } - if (AHT1XInit(aht1x_addresses[i])) - { - aht1x_sensors[aht1x_count].address = aht1x_addresses[i]; - GetTextIndexed(aht1x_sensors[aht1x_count].types, sizeof(aht1x_sensors[aht1x_count].types), i, ahtTypes); - I2cSetActiveFound(aht1x_sensors[aht1x_count].address, aht1x_sensors[aht1x_count].types); - aht1x_count = 1; - break; - } - } -} - -void AHT1XShow(bool json) -{ - for (uint32_t i = 0; i < aht1x_count; i++) { - float tem = ConvertTemp(aht1x_sensors[i].temperature); - float hum = ConvertHumidity(aht1x_sensors[i].humidity); - char types[11]; - snprintf_P(types, sizeof(types), PSTR("%s%c0x%02X"), aht1x_sensors[i].types, IndexSeparator(), aht1x_sensors[i].address); - TempHumDewShow(json, ((0 == tele_period) && (0 == i)), types, tem, hum); - } -} - - - - - -bool Xsns63(uint8_t function) -{ - if (!I2cEnabled(XI2C_43)) { return false; } - bool result = false; - - if (FUNC_INIT == function) { - AHT1XDetect(); - } - else if (aht1x_count){ - switch (function) { - case FUNC_EVERY_100_MSECOND: - AHT1XPoll(); - break; - case FUNC_JSON_APPEND: - AHT1XShow(1); - break; - #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - AHT1XShow(0); - break; - #endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_64_hrxl.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_64_hrxl.ino" -#ifdef USE_HRXL - - - - - - - -#define XSNS_64 64 - -#include - -#define HRXL_READ_TIMEOUT 400 - -TasmotaSerial *HRXLSerial = nullptr; - -uint32_t hrxl_distance_mm = 0; -bool hrxl_found = false; - - - -void HRXLInit(void) -{ - hrxl_found = false; - if ((pin[GPIO_HRXL_RX] < 99)) - { - HRXLSerial = new TasmotaSerial(pin[GPIO_HRXL_RX], -1, 1); - if (HRXLSerial->begin(9600)) - { - if (HRXLSerial->hardwareSerial()) - ClaimSerial(); - hrxl_found = true; - HRXLSerial->setTimeout(HRXL_READ_TIMEOUT); - } - } -} - -void HRXLEverySecond(void) -{ - if (!hrxl_found) - return; - - int num_read=0; - int sum=0; - while (HRXLSerial->available()>5) - { - if (HRXLSerial->read() != 'R') - continue; - - int d = HRXLSerial->parseInt(); - if (d >= 30 && d<=5000) - { - sum += d; - num_read++; - } - } - if (num_read>1) - hrxl_distance_mm = int(sum / num_read); - -} - - -void HRXLShow(bool json) -{ - char types[5] = "HRXL"; - if (json) - { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_DISTANCE "\":%d}"), types, hrxl_distance_mm); -#ifdef USE_WEBSERVER - } - else - { - WSContentSend_PD(HTTP_SNS_RANGE, types, hrxl_distance_mm); -#endif - } -} - - - - - -bool Xsns64(uint8_t function) -{ - if (pin[GPIO_HRXL_RX] >= 99) - return false; - - switch (function) - { - case FUNC_INIT: - HRXLInit(); - break; - case FUNC_EVERY_SECOND: - HRXLEverySecond(); - break; - case FUNC_JSON_APPEND: - HRXLShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HRXLShow(0); - break; -#endif - } - return false; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_65_hdc1080.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_65_hdc1080.ino" -#ifdef USE_I2C -#ifdef USE_HDC1080 -# 31 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_65_hdc1080.ino" -#define XSNS_65 65 -#define XI2C_45 45 - -#define HDC1080_ADDR 0x40 - - - -#define HDC_REG_TEMP 0x00 -#define HDC_REG_RH 0x01 -#define HDC_REG_CONFIG 0x02 -#define HDC_REG_SERIAL1 0xFB -#define HDC_REG_SERIAL2 0xFC -#define HDC_REG_SERIAL3 0xFD -#define HDC_REG_MAN_ID 0xFE -#define HDC_REG_DEV_ID 0xFF - - - -#define HDC1080_MAN_ID 0x5449 -#define HDC1080_DEV_ID 0x1050 - - - -#define HDC1080_RST_ON 0x8000 -#define HDC1080_HEAT_ON 0x2000 -#define HDC1080_MODE_ON 0x1000 -#define HDC1080_TRES_11 0x400 -#define HDC1080_HRES_11 0x100 -#define HDC1080_HRES_8 0x80 - - - -#define HDC1080_CONV_TIME 15 -#define HDC1080_TEMP_MULT 0.0025177 -#define HDC1080_RH_MULT 0.0025177 -#define HDC1080_TEMP_OFFSET 40.0 - -const char* hdc_type_name = "HDC1080"; -uint16_t hdc_manufacturer_id = 0; -uint16_t hdc_device_id = 0; - -float hdc_temperature = 0.0; -float hdc_humidity = 0.0; - -uint8_t hdc_valid = 0; - -bool is_reading = false; -uint32_t hdc_next_read; - - - - - -uint16_t HdcReadDeviceId(void) { - return I2cRead16(HDC1080_ADDR, HDC_REG_DEV_ID); -} - - - - - -uint16_t HdcReadManufacturerId(void) { - return I2cRead16(HDC1080_ADDR, HDC_REG_MAN_ID); -} - - - - -void HdcConfig(uint16_t config) { - I2cWrite16(HDC1080_ADDR, HDC_REG_CONFIG, config); -} - - - - - - - -void HdcReset(void) { - uint16_t current = I2cRead16(HDC1080_ADDR, HDC_REG_CONFIG); - - - - - current |= 0x8000; - - I2cWrite16(HDC1080_ADDR, HDC_REG_CONFIG, current); - - delay(HDC1080_CONV_TIME); -} -# 132 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_65_hdc1080.ino" -int8_t HdcTransactionOpen(uint8_t addr, uint8_t reg) { - Wire.beginTransmission((uint8_t) addr); - Wire.write((uint8_t) reg); - return Wire.endTransmission(); -} -# 147 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_65_hdc1080.ino" -int8_t HdcTransactionClose(uint8_t addr, uint8_t *reg_data, uint16_t len) { - if (len != Wire.requestFrom((uint8_t) addr, (uint8_t) len)) { - return 1; - } - - while (len--) { - *reg_data = (uint8_t)Wire.read(); - reg_data++; - } - - return 0; -} - - - - - -void HdcInit(void) { - HdcReset(); - HdcConfig(HDC1080_MODE_ON); -} - - - - - -bool HdcTriggerRead(void) { - int8_t status = HdcTransactionOpen(HDC1080_ADDR, HDC_REG_TEMP); - - hdc_next_read = millis() + HDC1080_CONV_TIME; - - if(status) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcTriggerRead: failed to open the transaction for HDC_REG_TEMP. Status = %d"), status); - - return false; - } - - is_reading = true; - - return true; -} -# 197 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_65_hdc1080.ino" -bool HdcRead(void) { - int8_t status = 0; - uint8_t sensor_data[4]; - uint16_t temp_data = 0; - uint16_t rh_data = 0; - - is_reading = false; - - status = HdcTransactionClose(HDC1080_ADDR, sensor_data, 4); - - if(status) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcRead: failed to read HDC_REG_TEMP. Status = %d"), status); - - return false; - } - - temp_data = (uint16_t) ((sensor_data[0] << 8) | sensor_data[1]); - rh_data = (uint16_t) ((sensor_data[2] << 8) | sensor_data[3]); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature raw data: 0x%04x; humidity raw data: 0x%04x"), temp_data, rh_data); - - - - hdc_temperature = ConvertTemp(HDC1080_TEMP_MULT * (float) (temp_data) - HDC1080_TEMP_OFFSET); - - hdc_humidity = HDC1080_RH_MULT * (float) (rh_data); - - if (hdc_humidity > 100) { hdc_humidity = 100.0; } - if (hdc_humidity < 0) { hdc_humidity = 0.01; } - hdc_humidity = ConvertHumidity(hdc_humidity); - - hdc_valid = SENSOR_MAX_MISS; - - return true; -} - - - - - - -void HdcDetect(void) { - if (I2cActive(HDC1080_ADDR)) { - - - return; - } - - hdc_manufacturer_id = HdcReadManufacturerId(); - hdc_device_id = HdcReadDeviceId(); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("HdcDetect: detected device with manufacturerId = 0x%04X and deviceId = 0x%04X"), hdc_manufacturer_id, hdc_device_id); - - if (hdc_device_id == HDC1080_DEV_ID) { - HdcInit(); - I2cSetActiveFound(HDC1080_ADDR, hdc_type_name); - } -} - - - - - - -void HdcEverySecond(void) { - if (uptime &1) { - if (!HdcTriggerRead()) { - AddLogMissed((char*) hdc_type_name, hdc_valid); - } - } -} - - - - - - -void HdcShow(bool json) { - if (hdc_valid) { - TempHumDewShow(json, (0 == tele_period), hdc_type_name, hdc_temperature, hdc_humidity); - } -} - - - - - -bool Xsns65(uint8_t function) -{ - if (!I2cEnabled(XI2C_45)) { - - - return false; - } - - bool result = false; - - if (FUNC_INIT == function) { - HdcDetect(); - } - else if (hdc_device_id) { - switch (function) { - case FUNC_EVERY_50_MSECOND: - if(is_reading && TimeReached(hdc_next_read)) { - if(!HdcRead()) { - AddLogMissed((char*) hdc_type_name, hdc_valid); - } - } - break; - case FUNC_EVERY_SECOND: - HdcEverySecond(); - break; - case FUNC_JSON_APPEND: - HdcShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HdcShow(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_66_iAQ.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_66_iAQ.ino" -#ifdef USE_I2C -#ifdef USE_IAQ - -#define XSNS_66 66 -#define XI2C_46 46 - -#define I2_ADR_IAQ 0x5a - -#define IAQ_STATUS_OK 0x00 -#define IAQ_STATUS_BUSY 0x01 -#define IAQ_STATUS_WARM 0x10 -#define IAQ_STATUS_ERR 0x80 -#define IAQ_STATUS_I2C_ERR 0xFF - -struct { - int32_t resistance; - uint16_t pred; - uint16_t Tvoc; - uint8_t status; - bool ready; -} iAQ; - -void IAQ_Init(void) -{ - if (!I2cSetDevice(I2_ADR_IAQ)) { return; } - I2cSetActiveFound(I2_ADR_IAQ, "IAQ"); - iAQ.ready = true; -} - -void IAQ_Read(void) -{ - uint8_t buf[9]; - buf[2] = IAQ_STATUS_I2C_ERR; - Wire.requestFrom((uint8_t)I2_ADR_IAQ,sizeof(buf)); - for( uint32_t i=0; i<9; i++ ) { - buf[i]= Wire.read(); - } - - iAQ.pred = (buf[0]<<8) + buf[1]; - iAQ.status = buf[2]; - iAQ.resistance = ((uint32_t)buf[3]<<24) + ((uint32_t)buf[4]<<16) + ((uint32_t)buf[5]<<8) + (uint32_t)buf[6]; - iAQ.Tvoc = (buf[7]<<8) + buf[8]; -} - - - - - -#ifdef USE_WEBSERVER -const char HTTP_SNS_IAQ[] PROGMEM = - "{s}iAQ-Core " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" - "{s}iAQ-Core " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; - -const char HTTP_SNS_IAQ_ERROR[] PROGMEM = - "{s}iAQ-Core {m} %s {e}"; -#endif - -void IAQ_Show(uint8_t json) -{ - IAQ_Read(); - - if (json) { - if (iAQ.status!=IAQ_STATUS_OK){ - AddLog_P2(LOG_LEVEL_INFO, PSTR("iAQ: " D_ERROR " %x" ),iAQ.status); - return; - } - else { - ResponseAppend_P(PSTR(",\"IAQ\":{\"" D_JSON_ECO2 "\":%u,\"" D_JSON_TVOC "\":%u,\"" D_JSON_RESISTANCE "\":%u}"), iAQ.pred, iAQ.Tvoc, iAQ.resistance); -#ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, iAQ.pred); -#endif - } -#ifdef USE_WEBSERVER - } else { - switch(iAQ.status){ - case IAQ_STATUS_OK: - WSContentSend_PD(HTTP_SNS_IAQ, iAQ.pred, iAQ.Tvoc); - break; - case IAQ_STATUS_WARM: - WSContentSend_PD(HTTP_SNS_IAQ_ERROR, D_START); - break; - default: - WSContentSend_PD(HTTP_SNS_IAQ_ERROR, D_ERROR); - } -#endif - } -} - - - - - -bool Xsns66(byte function) -{ - if (!I2cEnabled(XI2C_46)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - IAQ_Init(); - } - else if (iAQ.ready) { - switch (function) { - case FUNC_JSON_APPEND: - IAQ_Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - IAQ_Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_67_as3935.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_67_as3935.ino" -#ifdef USE_I2C -#ifdef USE_AS3935 - - - - - - -#define XSNS_67 67 -#define XI2C_48 48 - -#define D_NAME_AS3935 "AS3935" -#define AS3935_ADDR 0x03 - - -#define IRQ_TBL 0x03, 0x0F, 0 -#define ENERGY_RAW_1 0x04, 0xFF, 0 -#define ENERGY_RAW_2 0x05, 0xFF, 0 -#define ENERGY_RAW_3 0x06, 0x1F, 0 -#define LGHT_DIST 0x07, 0x3F, 0 -#define DISP_TRCO 0x08, 0x20, 5 -#define DISP_LCO 0x08, 0x80, 7 -#define TUNE_CAPS 0x08, 0x0F, 0 -#define AFE_GB 0x00, 0x3E, 0 -#define WDTH 0x01, 0x0F, 0 -#define NF_LEVEL 0x01, 0x70, 4 -#define SPIKE_REJECT 0x02, 0x0F, 0 -#define MIN_NUM_LIGH 0x02, 0x30, 4 -#define DISTURBER 0x03, 0x20, 5 -#define LCO_FDIV 0x03, 0xC0, 6 - -#define INDOORS 0x24 -#define OUTDOORS 0x1C - - - -#define D_AS3935_GAIN "gain:" -#define D_AS3935_ENERGY "energy:" -#define D_AS3935_DISTANCE "distance:" -#define D_AS3935_DISTURBER "disturber:" -#define D_AS3935_VRMS "µVrms:" - -#define D_AS3935_APRX "aprx.:" -#define D_AS3935_AWAY "away" -#define D_AS3935_LIGHT "lightning" -#define D_AS3935_OUT "lightning out of range" -#define D_AS3935_NOT "distance not determined" -#define D_AS3935_ABOVE "lightning overhead" -#define D_AS3935_NOISE "noise detected" -#define D_AS3935_DISTDET "disturber detected" -#define D_AS3935_INTNOEV "Interrupt with no Event!" -#define D_AS3935_NOMESS "listening..." - -#define D_AS3935_ON "On" -#define D_AS3935_OFF "Off" -#define D_AS3935_INDOORS "Indoors" -#define D_AS3935_OUTDOORS "Outdoors" -#define D_AS3935_CAL_FAIL "calibration failed" -#define D_AS3935_CAL_OK "calibration set to:" - - -const char HTTP_SNS_UNIT_KILOMETER[] PROGMEM = D_UNIT_KILOMETER; - -const char HTTP_SNS_AS3935_ENERGY[] PROGMEM = "{s}" D_NAME_AS3935 " " D_AS3935_ENERGY " {m}%d{e}"; -const char HTTP_SNS_AS3935_DISTANZ[] PROGMEM = "{s}" D_NAME_AS3935 " " D_AS3935_DISTANCE " {m}%u " D_UNIT_KILOMETER "{e}"; -const char HTTP_SNS_AS3935_VRMS[] PROGMEM = "{s}" D_NAME_AS3935 " " D_AS3935_VRMS "{m}%#4u (%d){e}"; - -const char HTTP_SNS_AS3935_OUTDOORS[] PROGMEM = "{s}%s " D_AS3935_GAIN " {m}" D_AS3935_OUTDOORS " {e}"; -const char HTTP_SNS_AS3935_INDOORS[] PROGMEM = "{s}%s " D_AS3935_GAIN " {m}" D_AS3935_INDOORS " {e}"; -const char* const HTTP_SNS_AS3935_GAIN[] PROGMEM = {HTTP_SNS_AS3935_INDOORS, HTTP_SNS_AS3935_OUTDOORS}; - -const char HTTP_SNS_AS3935_DIST_ON[] PROGMEM = "{s}%s " D_AS3935_DISTURBER " {m}" D_AS3935_ON " {e}"; -const char HTTP_SNS_AS3935_DIST_OFF[] PROGMEM = "{s}%s " D_AS3935_DISTURBER " {m}" D_AS3935_OFF " {e}"; -const char* const HTTP_SNS_AS3935_DISTURBER[] PROGMEM = {HTTP_SNS_AS3935_DIST_OFF, HTTP_SNS_AS3935_DIST_ON}; - -const char HTTP_SNS_AS3935_EMPTY[] PROGMEM = "{s}%s: " D_AS3935_NOMESS "{e}"; -const char HTTP_SNS_AS3935_OUT[] PROGMEM = "{s}%s: " D_AS3935_OUT "{e}"; -const char HTTP_SNS_AS3935_NOT[] PROGMEM = "{s}%s: " D_AS3935_NOT "{e}"; -const char HTTP_SNS_AS3935_ABOVE[] PROGMEM = "{s}%s: " D_AS3935_ABOVE "{e}"; -const char HTTP_SNS_AS3935_NOISE[] PROGMEM = "{s}%s: " D_AS3935_NOISE "{e}"; -const char HTTP_SNS_AS3935_DISTURB[] PROGMEM = "{s}%s: " D_AS3935_DISTDET "{e}"; -const char HTTP_SNS_AS3935_INTNOEV[] PROGMEM = "{s}%s: " D_AS3935_INTNOEV "{e}"; -const char HTTP_SNS_AS3935_MSG[] PROGMEM = "{s}%s: " D_AS3935_LIGHT " " D_AS3935_APRX " %d " D_UNIT_KILOMETER " " D_AS3935_AWAY "{e}"; -const char* const HTTP_SNS_AS3935_TABLE_1[] PROGMEM = { HTTP_SNS_AS3935_EMPTY, HTTP_SNS_AS3935_MSG, HTTP_SNS_AS3935_OUT, HTTP_SNS_AS3935_NOT, HTTP_SNS_AS3935_ABOVE, HTTP_SNS_AS3935_NOISE, HTTP_SNS_AS3935_DISTURB, HTTP_SNS_AS3935_INTNOEV }; - -const char JSON_SNS_AS3935_EVENTS[] PROGMEM = ",\"%s\":{\"" D_JSON_EVENT "\":%d,\"" D_JSON_DISTANCE "\":%d,\"" D_JSON_ENERGY "\":%u}"; - -const char* const S_JSON_AS3935_COMMAND_ONOFF[] PROGMEM = {"\"" D_AS3935_OFF "\"","\"" D_AS3935_ON"\""}; -const char* const S_JSON_AS3935_COMMAND_GAIN[] PROGMEM = {"\"" D_AS3935_INDOORS "\"", "\"" D_AS3935_OUTDOORS "\""}; -const char* const S_JSON_AS3935_COMMAND_CAL[] PROGMEM = {"" D_AS3935_CAL_FAIL "","" D_AS3935_CAL_OK ""}; - -const char S_JSON_AS3935_COMMAND_STRING[] PROGMEM = "{\"" D_NAME_AS3935 "\":{\"%s\":%s}}"; -const char S_JSON_AS3935_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_AS3935 "\":{\"%s\":%d}}"; -const char S_JSON_AS3935_COMMAND_SETTINGS[] PROGMEM = "{\"" D_NAME_AS3935 "\":{\"Gain\":%s,\"NFfloor\":%d,\"uVrms\":%d,\"Tunecaps\":%d,\"MinNumLight\":%d,\"Rejektion\":%d,\"Wdthreshold\":%d,\"MinNFstage\":%d,\"NFAutoTime\":%d,\"DisturberAutoTime\":%d,\"Disturber\":%s,\"NFauto\":%s,\"Disturberauto\":%s,\"NFautomax\":%s,\"Mqttlightevent\":%s}}"; - -const char kAS3935_Commands[] PROGMEM = "setnf|setminstage|setml|default|setgain|settunecaps|setrej|setwdth|disttime|nftime|disturber|autonf|autodisturber|autonfmax|mqttevent|settings|calibrate"; - -enum AS3935_Commands { - CMND_AS3935_SET_NF, - CMND_AS3935_SET_MINNF, - CMND_AS3935_SET_MINLIGHT, - CMND_AS3935_SET_DEF, - CMND_AS3935_SET_GAIN, - CMND_AS3935_SET_TUNE, - CMND_AS3935_SET_REJ, - CMND_AS3935_SET_WDTH, - CMND_AS3935_DISTTIME, - CMND_AS3935_NFTIME, - CMND_AS3935_SET_DISTURBER, - CMND_AS3935_NF_AUTOTUNE, - CMND_AS3935_DIST_AUTOTUNE, - CMND_AS3935_NF_ATUNE_BOTH, - CMND_AS3935_MQTT_LIGHT_EVT, - CMND_AS3935_SETTINGS, - CMND_AS3935_CALIBRATE - }; - -struct AS3935STRUCT -{ - bool autodist_activ = false; - volatile bool detected = false; - volatile bool dispLCO = 0; - uint8_t icount = 0; - uint8_t irq = 0; - uint8_t mqtt_irq = 0; - uint8_t http_irq = 0; - uint8_t http_count_start = 0; - int16_t http_distance = 0; - int16_t distance = 0; - uint16_t http_timer = 0; - uint16_t http_count = 0; - uint16_t nftimer = 0; - uint16_t disttimer = 0; - uint32_t intensity = 0; - uint32_t http_intensity = 0; - volatile uint32_t pulse = 0; -} as3935_sensor; - -uint8_t as3935_active = 0; - -void ICACHE_RAM_ATTR AS3935Isr() { - as3935_sensor.detected = true; -} - -uint8_t AS3935ReadRegister(uint8_t reg, uint8_t mask, uint8_t shift) { - uint8_t data = I2cRead8(AS3935_ADDR, reg); - if (reg == 0x08) Settings.as3935_sensor_cfg[4] = data; - if (reg < 0x04) Settings.as3935_sensor_cfg[reg] = data; - return ((data & mask) >> shift); -} - -void AS3935WriteRegister(uint8_t reg, uint8_t mask, uint8_t shift, uint8_t data) { - uint8_t currentReg = I2cRead8(AS3935_ADDR, reg); - currentReg &= (~mask); - data <<= shift; - data &= mask; - data |= currentReg; - I2cWrite8(AS3935_ADDR, reg, data); - if (reg == 0x08) Settings.as3935_sensor_cfg[4] = I2cRead8(AS3935_ADDR, reg); - if (reg < 0x04) Settings.as3935_sensor_cfg[reg] = I2cRead8(AS3935_ADDR, reg); -} - - - -void ICACHE_RAM_ATTR AS3935CountFreq() { - if (as3935_sensor.dispLCO) - as3935_sensor.pulse++; -} - -bool AS3935AutoTuneCaps(uint8_t irqpin) { - int32_t maxtune = 17500; - uint8_t besttune; - AS3935WriteRegister(LCO_FDIV, 0); - delay(2); - for (uint8_t tune = 0; tune < 16; tune++) { - AS3935WriteRegister(TUNE_CAPS, tune); - delay(2); - AS3935WriteRegister(DISP_LCO,1); - delay(1); - as3935_sensor.dispLCO = true; - as3935_sensor.pulse = 0; - attachInterrupt(digitalPinToInterrupt(irqpin), AS3935CountFreq, RISING); - delay(200); - as3935_sensor.dispLCO = false; - detachInterrupt(irqpin); - AS3935WriteRegister(DISP_LCO,0); - int32_t currentfreq = 500000 - ((as3935_sensor.pulse * 5) * 16); - if(currentfreq < 0) currentfreq = -currentfreq; - if(maxtune > currentfreq) { - maxtune = currentfreq; - besttune = tune; - } - } - if (maxtune >= 17500) - return false; - AS3935SetTuneCaps(besttune); - return true; -} - - - -void AS3935CalibrateRCO() { - I2cWrite8(AS3935_ADDR, 0x3D, 0x96); - AS3935WriteRegister(DISP_TRCO, 1); - delay(2); - AS3935WriteRegister(DISP_TRCO, 0); -} - -uint8_t AS3935TransMinLights(uint8_t min_lights) { - if (5 > min_lights) { - return 0; - } else if (9 > min_lights) { - return 1; - } else if (16 > min_lights) { - return 2; - } else { - return 3; - } -} - -uint8_t AS3935TranslMinLightsInt(uint8_t min_lights) { - switch (min_lights) { - case 0: return 1; - case 1: return 5; - case 2: return 9; - case 3: return 16; - } -} - -uint8_t AS3935TranslIrq(uint8_t irq, uint8_t distance) { - switch(irq) { - case 0: return 7; - case 1: return 5; - case 4: return 6; - case 8: - if (distance == -1) return 2; - else if (distance == 0) return 3; - else if (distance == 1) return 4; - else return 1; - } -} - -void AS3935CalcVrmsLevel(uint16_t &vrms, uint8_t &stage) -{ - uint8_t room = AS3935GetGain(); - uint8_t nflev = AS3935GetNoiseFloor(); - if (room == 0x24) - { - switch (nflev){ - case 0x00: - vrms = 28; - break; - case 0x01: - vrms = 45; - break; - case 0x02: - vrms = 62; - break; - case 0x03: - vrms = 78; - break; - case 0x04: - vrms = 95; - break; - case 0x05: - vrms = 112; - break; - case 0x06: - vrms = 130; - break; - case 0x07: - vrms = 146; - break; - } - stage = nflev; - } - else - { - switch (nflev) - { - case 0x00: - vrms = 390; - break; - case 0x01: - vrms = 630; - break; - case 0x02: - vrms = 860; - break; - case 0x03: - vrms = 1100; - break; - case 0x04: - vrms = 1140; - break; - case 0x05: - vrms = 1570; - break; - case 0x06: - vrms = 1800; - break; - case 0x07: - vrms = 2000; - break; - } - stage = nflev + 8; - } -} - - -uint8_t AS3935GetIRQ() { - delay(2); - return AS3935ReadRegister(IRQ_TBL); -} - -uint8_t AS3935GetDistance() { - return AS3935ReadRegister(LGHT_DIST); -} - -int16_t AS3935CalcDistance() { - uint8_t dist = AS3935GetDistance(); - switch (dist) { - case 0x3F: return -1; - case 0x01: return 1; - case 0x00: return 0; - default: - if (40 < dist){ - return 40; - } - return dist; - } -} - -uint32_t AS3935GetIntensity() { - uint32_t nrgy_raw = (AS3935ReadRegister(ENERGY_RAW_3) << 8); - nrgy_raw |= AS3935ReadRegister(ENERGY_RAW_2); - nrgy_raw <<= 8; - nrgy_raw |= AS3935ReadRegister(ENERGY_RAW_1); - return nrgy_raw; -} - -uint8_t AS3935GetTuneCaps() { - return AS3935ReadRegister(TUNE_CAPS); -} - -void AS3935SetTuneCaps(uint8_t tune) { - AS3935WriteRegister(TUNE_CAPS, tune); - delay(2); - AS3935CalibrateRCO(); -} - -uint8_t AS3935GetDisturber() { - return AS3935ReadRegister(DISTURBER); -} - -uint8_t AS3935SetDisturber(uint8_t stat) { - AS3935WriteRegister(DISTURBER, stat); -} - -uint8_t AS3935GetMinLights() { - return AS3935ReadRegister(MIN_NUM_LIGH); -} - -uint8_t AS3935SetMinLights(uint8_t stat) { - AS3935WriteRegister(MIN_NUM_LIGH, stat); -} - -uint8_t AS3935GetNoiseFloor() { - return AS3935ReadRegister(NF_LEVEL); -} - -uint8_t AS3935SetNoiseFloor(uint8_t noise) { - AS3935WriteRegister(NF_LEVEL , noise); -} - -uint8_t AS3935GetGain() { - if (AS3935ReadRegister(AFE_GB) == OUTDOORS) - return OUTDOORS; - return INDOORS; -} - -uint8_t AS3935SetGain(uint8_t room) { - AS3935WriteRegister(AFE_GB, room); -} - -uint8_t AS3935GetGainInt() { - if (AS3935ReadRegister(AFE_GB) == OUTDOORS) - return 1; -return 0; -} - -uint8_t AS3935GetSpikeRejection() { - return AS3935ReadRegister(SPIKE_REJECT); -} - -void AS3935SetSpikeRejection(uint8_t rej) { - AS3935WriteRegister(SPIKE_REJECT, rej); -} - -uint8_t AS3935GetWdth() { - return AS3935ReadRegister(WDTH); -} - -void AS3935SetWdth(uint8_t wdth) { - AS3935WriteRegister(WDTH, wdth); -} - -bool AS3935AutoTune(){ - detachInterrupt(pin[GPIO_AS3935]); - bool result = AS3935AutoTuneCaps(pin[GPIO_AS3935]); - attachInterrupt(digitalPinToInterrupt(pin[GPIO_AS3935]), AS3935Isr, RISING); - return result; -} - - - -bool AS3935LowerNoiseFloor() { - uint8_t noise = AS3935GetNoiseFloor(); - uint16_t vrms; - uint8_t stage; - AS3935CalcVrmsLevel(vrms, stage); - if (Settings.as3935_functions.nf_autotune_both) { - if (stage == 8 && stage > Settings.as3935_parameter.nf_autotune_min) { - AS3935SetGain(INDOORS); - AS3935SetNoiseFloor(7); - return true; - } - } - if (0 < noise && stage > Settings.as3935_parameter.nf_autotune_min) { - noise--; - AS3935SetNoiseFloor(noise); - return true; - } - return false; -} - -bool AS3935RaiseNoiseFloor() { - uint8_t noise = AS3935GetNoiseFloor(); - uint8_t room = AS3935GetGain(); - if (Settings.as3935_functions.nf_autotune_both) { - if (7 == noise && room == INDOORS) { - AS3935SetGain(OUTDOORS); - AS3935SetNoiseFloor(0); - return true; - } - } - if (7 > noise) { - noise++; - AS3935SetNoiseFloor(noise); - return true; - } - return false; -} - - - -bool AS3935SetDefault() { - I2cWrite8(AS3935_ADDR, 0x3C, 0x96); - delay(2); - Settings.as3935_sensor_cfg[0] = I2cRead8(AS3935_ADDR, 0x00); - Settings.as3935_sensor_cfg[1] = I2cRead8(AS3935_ADDR, 0x01); - Settings.as3935_sensor_cfg[2] = I2cRead8(AS3935_ADDR, 0x02); - Settings.as3935_sensor_cfg[3] = I2cRead8(AS3935_ADDR, 0x03); - Settings.as3935_sensor_cfg[4] = I2cRead8(AS3935_ADDR, 0x08); - Settings.as3935_parameter.nf_autotune_min = 0x00; - Settings.as3935_parameter.nf_autotune_time = 4; - Settings.as3935_parameter.dist_autotune_time = 1; - return true; -} - -void AS3935InitSettings() { - if(Settings.as3935_functions.nf_autotune){ - AS3935SetGain(INDOORS); - AS3935SetNoiseFloor(0); - } - I2cWrite8(AS3935_ADDR, 0x00, Settings.as3935_sensor_cfg[0]); - I2cWrite8(AS3935_ADDR, 0x01, Settings.as3935_sensor_cfg[1]); - I2cWrite8(AS3935_ADDR, 0x02, Settings.as3935_sensor_cfg[2]); - I2cWrite8(AS3935_ADDR, 0x03, Settings.as3935_sensor_cfg[3]); - I2cWrite8(AS3935_ADDR, 0x08, Settings.as3935_sensor_cfg[4]); - delay(2); -} - -void AS3935Setup(void) { - if (Settings.as3935_sensor_cfg[0] == 0x00) { - AS3935SetDefault(); - } else { - AS3935InitSettings(); - } - AS3935CalibrateRCO(); -} - -bool AS3935init() { - uint8_t ret = I2cRead8(AS3935_ADDR, 0x00); - if(INDOORS == ret || OUTDOORS == ret) - return true; - return false; -} - -void AS3935Detect(void) { - if (I2cActive(AS3935_ADDR)) return; - if (AS3935init()) - { - I2cSetActiveFound(AS3935_ADDR, D_NAME_AS3935); - pinMode(pin[GPIO_AS3935], INPUT); - attachInterrupt(digitalPinToInterrupt(pin[GPIO_AS3935]), AS3935Isr, RISING); - AS3935Setup(); - as3935_active = 1; - } -} - -void AS3935EverySecond() { - if (as3935_sensor.detected) { - as3935_sensor.irq = AS3935GetIRQ(); - switch (as3935_sensor.irq) { - case 1: - if (Settings.as3935_functions.nf_autotune) { - if (AS3935RaiseNoiseFloor()) as3935_sensor.nftimer = 0; - } - break; - case 4: - if (Settings.as3935_functions.dist_autotune) { - AS3935SetDisturber(1); - as3935_sensor.autodist_activ = true; - } - break; - case 8: - as3935_sensor.intensity = AS3935GetIntensity(); - as3935_sensor.distance = AS3935CalcDistance(); - as3935_sensor.http_intensity = as3935_sensor.intensity; - as3935_sensor.http_distance = as3935_sensor.distance; - break; - } - - as3935_sensor.http_irq = AS3935TranslIrq(as3935_sensor.irq, as3935_sensor.distance); - - as3935_sensor.mqtt_irq = as3935_sensor.http_irq; - switch (as3935_sensor.mqtt_irq) { - case 5: - case 6: - if (!Settings.as3935_functions.mqtt_only_Light_Event) { - MqttPublishSensor(); - as3935_sensor.http_timer = 10; - } - break; - default: - as3935_sensor.http_timer = 60; - MqttPublishSensor(); - } - - as3935_sensor.intensity = 0; - as3935_sensor.distance = 0; - as3935_sensor.mqtt_irq = 0; - - as3935_sensor.http_count_start = 1; - as3935_sensor.icount++; - as3935_sensor.detected = false; - } - - if (as3935_sensor.http_count_start) as3935_sensor.http_count++; - - if (as3935_sensor.http_count == as3935_sensor.http_timer) { - as3935_sensor.http_count = 0; - as3935_sensor.http_count_start = 0; - as3935_sensor.http_intensity = 0; - as3935_sensor.http_distance = 0; - as3935_sensor.http_irq = 0; - } - - if (Settings.as3935_functions.nf_autotune) { - as3935_sensor.nftimer++; - if (as3935_sensor.nftimer > Settings.as3935_parameter.nf_autotune_time * 60) { - AS3935LowerNoiseFloor(); - as3935_sensor.nftimer = 0; - } - } - - if (Settings.as3935_functions.dist_autotune) { - if (as3935_sensor.autodist_activ) as3935_sensor.disttimer++; - if (as3935_sensor.disttimer >= Settings.as3935_parameter.dist_autotune_time * 60) { - AS3935SetDisturber(0); - as3935_sensor.disttimer = 0; - as3935_sensor.autodist_activ = false; - } - } -} - -bool AS3935Cmd(void) { - char command[CMDSZ]; - uint8_t name_len = strlen(D_NAME_AS3935); - if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_NAME_AS3935), name_len)) { - uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + name_len, kAS3935_Commands); - switch (command_code) { - case CMND_AS3935_SET_NF: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - AS3935SetNoiseFloor(XdrvMailbox.payload); - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, AS3935GetNoiseFloor()); - break; - case CMND_AS3935_SET_MINNF: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - Settings.as3935_parameter.nf_autotune_min = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, Settings.as3935_parameter.nf_autotune_min); - break; - case CMND_AS3935_SET_MINLIGHT: - if (XdrvMailbox.data_len) { - AS3935SetMinLights(AS3935TransMinLights(XdrvMailbox.payload)); - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, AS3935TranslMinLightsInt(AS3935GetMinLights())); - break; - case CMND_AS3935_SET_DEF: - if (!XdrvMailbox.data_len) { - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, AS3935SetDefault()); - } - break; - case CMND_AS3935_SET_GAIN: - if (XdrvMailbox.data_len > 6) { - uint8_t data_len = strlen(D_AS3935_OUTDOORS); - if (!strncasecmp_P(XdrvMailbox.data, PSTR(D_AS3935_OUTDOORS), data_len)) { - AS3935SetGain(OUTDOORS); - } else { - AS3935SetGain(INDOORS); - } - } - Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_GAIN[AS3935GetGainInt()]); - break; - case CMND_AS3935_SET_TUNE: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - AS3935SetTuneCaps(XdrvMailbox.payload); - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, AS3935GetTuneCaps()); - break; - case CMND_AS3935_SET_REJ: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - AS3935SetSpikeRejection(XdrvMailbox.payload); - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, AS3935GetSpikeRejection()); - break; - case CMND_AS3935_SET_WDTH: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - AS3935SetWdth(XdrvMailbox.payload); - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, AS3935GetWdth()); - break; - case CMND_AS3935_DISTTIME: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - Settings.as3935_parameter.dist_autotune_time = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, Settings.as3935_parameter.dist_autotune_time); - break; - case CMND_AS3935_NFTIME: - if (XdrvMailbox.data_len) { - if (15 >= XdrvMailbox.payload) { - Settings.as3935_parameter.nf_autotune_time = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_NVALUE, command, Settings.as3935_parameter.nf_autotune_time); - break; - case CMND_AS3935_SET_DISTURBER: - if (XdrvMailbox.data_len) { - if (2 > XdrvMailbox.payload) { - AS3935SetDisturber(XdrvMailbox.payload); - if (!XdrvMailbox.payload) Settings.as3935_functions.dist_autotune = 0; - } - } - Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[AS3935GetDisturber()]); - break; - case CMND_AS3935_NF_AUTOTUNE: - if (XdrvMailbox.data_len) { - if (2 > XdrvMailbox.payload) { - Settings.as3935_functions.nf_autotune = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[Settings.as3935_functions.nf_autotune]); - break; - case CMND_AS3935_DIST_AUTOTUNE: - if (XdrvMailbox.data_len) { - if (2 > XdrvMailbox.payload) { - Settings.as3935_functions.dist_autotune = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[Settings.as3935_functions.dist_autotune]); - break; - case CMND_AS3935_NF_ATUNE_BOTH: - if (XdrvMailbox.data_len) { - if (2 > XdrvMailbox.payload) { - Settings.as3935_functions.nf_autotune_both = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[Settings.as3935_functions.nf_autotune_both]); - break; - case CMND_AS3935_MQTT_LIGHT_EVT: - if (XdrvMailbox.data_len) { - if (2 > XdrvMailbox.payload) { - Settings.as3935_functions.mqtt_only_Light_Event = XdrvMailbox.payload; - } - } - Response_P(S_JSON_AS3935_COMMAND_STRING, command, S_JSON_AS3935_COMMAND_ONOFF[Settings.as3935_functions.mqtt_only_Light_Event]); - break; - case CMND_AS3935_SETTINGS: { - if (!XdrvMailbox.data_len) { - uint8_t gain = AS3935GetGainInt(); - uint16_t vrms; - uint8_t stage; - AS3935CalcVrmsLevel(vrms, stage); - uint8_t nf_floor = AS3935GetNoiseFloor(); - uint8_t min_nf = Settings.as3935_parameter.nf_autotune_min; - uint8_t tunecaps = AS3935GetTuneCaps(); - uint8_t minnumlight = AS3935TranslMinLightsInt(AS3935GetMinLights()); - uint8_t disturber = AS3935GetDisturber(); - uint8_t reinj = AS3935GetSpikeRejection(); - uint8_t wdth = AS3935GetWdth(); - uint8_t nfauto = Settings.as3935_functions.nf_autotune; - uint8_t distauto = Settings.as3935_functions.dist_autotune; - uint8_t nfautomax = Settings.as3935_functions.nf_autotune_both; - uint8_t jsonlight = Settings.as3935_functions.mqtt_only_Light_Event; - uint8_t nf_time = Settings.as3935_parameter.nf_autotune_time; - uint8_t dist_time =Settings.as3935_parameter.dist_autotune_time; - Response_P(S_JSON_AS3935_COMMAND_SETTINGS, S_JSON_AS3935_COMMAND_GAIN[gain], nf_floor, vrms, tunecaps, minnumlight, reinj, wdth, min_nf, nf_time, dist_time, S_JSON_AS3935_COMMAND_ONOFF[disturber], S_JSON_AS3935_COMMAND_ONOFF[nfauto], S_JSON_AS3935_COMMAND_ONOFF[distauto], S_JSON_AS3935_COMMAND_ONOFF[nfautomax], S_JSON_AS3935_COMMAND_ONOFF[jsonlight]); - } - } - break; - case CMND_AS3935_CALIBRATE: { - bool calreslt; - if (!XdrvMailbox.data_len) calreslt = AS3935AutoTune(); - Response_P(S_JSON_AS3935_COMMAND_NVALUE, S_JSON_AS3935_COMMAND_CAL[calreslt], AS3935GetTuneCaps()); - } - break; - default: - return false; - } - return true; - } else { - return false; - } -} - -void AH3935Show(bool json) -{ - if (json) { - ResponseAppend_P(JSON_SNS_AS3935_EVENTS, D_SENSOR_AS3935, as3935_sensor.mqtt_irq, as3935_sensor.distance, as3935_sensor.intensity ); - -#ifdef USE_WEBSERVER - } else { - uint8_t gain = AS3935GetGainInt(); - uint8_t disturber = AS3935GetDisturber(); - uint16_t vrms; - uint8_t stage; - AS3935CalcVrmsLevel(vrms, stage); - - WSContentSend_PD(HTTP_SNS_AS3935_TABLE_1[as3935_sensor.http_irq], D_NAME_AS3935, as3935_sensor.http_distance); - WSContentSend_PD(HTTP_SNS_AS3935_DISTANZ, as3935_sensor.http_distance); - WSContentSend_PD(HTTP_SNS_AS3935_ENERGY, as3935_sensor.http_intensity); - WSContentSend_PD(HTTP_SNS_AS3935_GAIN[gain], D_NAME_AS3935); - WSContentSend_PD(HTTP_SNS_AS3935_DISTURBER[disturber], D_NAME_AS3935); - WSContentSend_PD(HTTP_SNS_AS3935_VRMS, vrms, stage); -#endif - } -} - - - - - -bool Xsns67(uint8_t function) -{ - if (!I2cEnabled(XI2C_48)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - AS3935Detect(); - } - else if (as3935_active) { - switch (function) { - case FUNC_EVERY_SECOND: - AS3935EverySecond(); - break; - case FUNC_COMMAND: - result = AS3935Cmd(); - break; - case FUNC_JSON_APPEND: - AH3935Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - AH3935Show(0); - break; -#endif - } - } - return result; -} - -#endif -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_91_prometheus.ino" -# 22 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_91_prometheus.ino" -#ifdef USE_PROMETHEUS - - - - -#define XSNS_91 91 - -void HandleMetrics(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR("Prometheus")); - - WSContentBegin(200, CT_PLAIN); - - - char parameter[FLOATSZ]; - - if (global_temperature != 9999) { - dtostrfd(global_temperature, Settings.flag2.temperature_resolution, parameter); - WSContentSend_P(PSTR("# TYPE global_temperature gauge\nglobal_temperature %s\n"), parameter); - } - if (global_humidity != 0) { - dtostrfd(global_humidity, Settings.flag2.humidity_resolution, parameter); - WSContentSend_P(PSTR("# TYPE global_humidity gauge\nglobal_humidity %s\n"), parameter); - } - if (global_pressure != 0) { - dtostrfd(global_pressure, Settings.flag2.pressure_resolution, parameter); - WSContentSend_P(PSTR("# TYPE global_pressure gauge\nglobal_pressure %s\n"), parameter); - } - -#ifdef USE_ENERGY_SENSOR - dtostrfd(Energy.voltage[0], Settings.flag2.voltage_resolution, parameter); - WSContentSend_P(PSTR("# TYPE voltage gauge\nvoltage %s\n"), parameter); - dtostrfd(Energy.current[0], Settings.flag2.current_resolution, parameter); - WSContentSend_P(PSTR("# TYPE current gauge\ncurrent %s\n"), parameter); - dtostrfd(Energy.active_power[0], Settings.flag2.wattage_resolution, parameter); - WSContentSend_P(PSTR("# TYPE active_power gauge\nactive_power %s\n"), parameter); - dtostrfd(Energy.daily, Settings.flag2.energy_resolution, parameter); - WSContentSend_P(PSTR("# TYPE energy_daily gauge\nenergy_daily %s\n"), parameter); - dtostrfd(Energy.total, Settings.flag2.energy_resolution, parameter); - WSContentSend_P(PSTR("# TYPE energy_total counter\nenergy_total %s\n"), parameter); -#endif -# 80 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_91_prometheus.ino" - WSContentEnd(); -} - - - - - -bool Xsns91(uint8_t function) -{ - bool result = false; - - switch (function) { - case FUNC_WEB_ADD_HANDLER: - Webserver->on("/metrics", HandleMetrics); - break; - } - return result; -} - -#endif -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_interface.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xsns_interface.ino" -#ifdef XFUNC_PTR_IN_ROM -bool (* const xsns_func_ptr[])(uint8_t) PROGMEM = { -#else -bool (* const xsns_func_ptr[])(uint8_t) = { -#endif - -#ifdef XSNS_01 - &Xsns01, -#endif - -#ifdef XSNS_02 - &Xsns02, -#endif - -#ifdef XSNS_03 - &Xsns03, -#endif - -#ifdef XSNS_04 - &Xsns04, -#endif - -#ifdef XSNS_05 - &Xsns05, -#endif - -#ifdef XSNS_06 - &Xsns06, -#endif - -#ifdef XSNS_07 - &Xsns07, -#endif - -#ifdef XSNS_08 - &Xsns08, -#endif - -#ifdef XSNS_09 - &Xsns09, -#endif - -#ifdef XSNS_10 - &Xsns10, -#endif - -#ifdef XSNS_11 - &Xsns11, -#endif - -#ifdef XSNS_12 - &Xsns12, -#endif - -#ifdef XSNS_13 - &Xsns13, -#endif - -#ifdef XSNS_14 - &Xsns14, -#endif - -#ifdef XSNS_15 - &Xsns15, -#endif - -#ifdef XSNS_16 - &Xsns16, -#endif - -#ifdef XSNS_17 - &Xsns17, -#endif - -#ifdef XSNS_18 - &Xsns18, -#endif - -#ifdef XSNS_19 - &Xsns19, -#endif - -#ifdef XSNS_20 - &Xsns20, -#endif - -#ifdef XSNS_21 - &Xsns21, -#endif - -#ifdef XSNS_22 - &Xsns22, -#endif - -#ifdef XSNS_23 - &Xsns23, -#endif - -#ifdef XSNS_24 - &Xsns24, -#endif - -#ifdef XSNS_25 - &Xsns25, -#endif - -#ifdef XSNS_26 - &Xsns26, -#endif - -#ifdef XSNS_27 - &Xsns27, -#endif - -#ifdef XSNS_28 - &Xsns28, -#endif - -#ifdef XSNS_29 - &Xsns29, -#endif - -#ifdef XSNS_30 - &Xsns30, -#endif - -#ifdef XSNS_31 - &Xsns31, -#endif - -#ifdef XSNS_32 - &Xsns32, -#endif - -#ifdef XSNS_33 - &Xsns33, -#endif - -#ifdef XSNS_34 - &Xsns34, -#endif - -#ifdef XSNS_35 - &Xsns35, -#endif - -#ifdef XSNS_36 - &Xsns36, -#endif - -#ifdef XSNS_37 - &Xsns37, -#endif - -#ifdef XSNS_38 - &Xsns38, -#endif - -#ifdef XSNS_39 - &Xsns39, -#endif - -#ifdef XSNS_40 - &Xsns40, -#endif - -#ifdef XSNS_41 - &Xsns41, -#endif - -#ifdef XSNS_42 - &Xsns42, -#endif - -#ifdef XSNS_43 - &Xsns43, -#endif - -#ifdef XSNS_44 - &Xsns44, -#endif - -#ifdef XSNS_45 - &Xsns45, -#endif - -#ifdef XSNS_46 - &Xsns46, -#endif - -#ifdef XSNS_47 - &Xsns47, -#endif - -#ifdef XSNS_48 - &Xsns48, -#endif - -#ifdef XSNS_49 - &Xsns49, -#endif - -#ifdef XSNS_50 - &Xsns50, -#endif - -#ifdef XSNS_51 - &Xsns51, -#endif - -#ifdef XSNS_52 - &Xsns52, -#endif - -#ifdef XSNS_53 - &Xsns53, -#endif - -#ifdef XSNS_54 - &Xsns54, -#endif - -#ifdef XSNS_55 - &Xsns55, -#endif - -#ifdef XSNS_56 - &Xsns56, -#endif - -#ifdef XSNS_57 - &Xsns57, -#endif - -#ifdef XSNS_58 - &Xsns58, -#endif - -#ifdef XSNS_59 - &Xsns59, -#endif - -#ifdef XSNS_60 - &Xsns60, -#endif - -#ifdef XSNS_61 - &Xsns61, -#endif - -#ifdef XSNS_62 - &Xsns62, -#endif - -#ifdef XSNS_63 - &Xsns63, -#endif - -#ifdef XSNS_64 - &Xsns64, -#endif - -#ifdef XSNS_65 - &Xsns65, -#endif - -#ifdef XSNS_66 - &Xsns66, -#endif - -#ifdef XSNS_67 - &Xsns67, -#endif - -#ifdef XSNS_68 - &Xsns68, -#endif - -#ifdef XSNS_69 - &Xsns69, -#endif - -#ifdef XSNS_70 - &Xsns70, -#endif - -#ifdef XSNS_71 - &Xsns71, -#endif - -#ifdef XSNS_72 - &Xsns72, -#endif - -#ifdef XSNS_73 - &Xsns73, -#endif - -#ifdef XSNS_74 - &Xsns74, -#endif - -#ifdef XSNS_75 - &Xsns75, -#endif - -#ifdef XSNS_76 - &Xsns76, -#endif - -#ifdef XSNS_77 - &Xsns77, -#endif - -#ifdef XSNS_78 - &Xsns78, -#endif - -#ifdef XSNS_79 - &Xsns79, -#endif - -#ifdef XSNS_80 - &Xsns80, -#endif - -#ifdef XSNS_81 - &Xsns81, -#endif - -#ifdef XSNS_82 - &Xsns82, -#endif - -#ifdef XSNS_83 - &Xsns83, -#endif - -#ifdef XSNS_84 - &Xsns84, -#endif - -#ifdef XSNS_85 - &Xsns85, -#endif - -#ifdef XSNS_86 - &Xsns86, -#endif - -#ifdef XSNS_87 - &Xsns87, -#endif - -#ifdef XSNS_88 - &Xsns88, -#endif - -#ifdef XSNS_89 - &Xsns89, -#endif - -#ifdef XSNS_90 - &Xsns90, -#endif - -#ifdef XSNS_91 - &Xsns91, -#endif - -#ifdef XSNS_92 - &Xsns92, -#endif - -#ifdef XSNS_93 - &Xsns93, -#endif - -#ifdef XSNS_94 - &Xsns94, -#endif - -#ifdef XSNS_95 - &Xsns95, -#endif - -#ifdef XSNS_96 - &Xsns96, -#endif - -#ifdef XSNS_97 - &Xsns97, -#endif - -#ifdef XSNS_98 - &Xsns98, -#endif - -#ifdef XSNS_99 - &Xsns99 -#endif -}; - -const uint8_t xsns_present = sizeof(xsns_func_ptr) / sizeof(xsns_func_ptr[0]); - - - - - -#ifdef XFUNC_PTR_IN_ROM -const uint8_t kXsnsList[] PROGMEM = { -#else -const uint8_t kXsnsList[] = { -#endif - -#ifdef XSNS_01 - XSNS_01, -#endif - -#ifdef XSNS_02 - XSNS_02, -#endif - -#ifdef XSNS_03 - XSNS_03, -#endif - -#ifdef XSNS_04 - XSNS_04, -#endif - -#ifdef XSNS_05 - XSNS_05, -#endif - -#ifdef XSNS_06 - XSNS_06, -#endif - -#ifdef XSNS_07 - XSNS_07, -#endif - -#ifdef XSNS_08 - XSNS_08, -#endif - -#ifdef XSNS_09 - XSNS_09, -#endif - -#ifdef XSNS_10 - XSNS_10, -#endif - -#ifdef XSNS_11 - XSNS_11, -#endif - -#ifdef XSNS_12 - XSNS_12, -#endif - -#ifdef XSNS_13 - XSNS_13, -#endif - -#ifdef XSNS_14 - XSNS_14, -#endif - -#ifdef XSNS_15 - XSNS_15, -#endif - -#ifdef XSNS_16 - XSNS_16, -#endif - -#ifdef XSNS_17 - XSNS_17, -#endif - -#ifdef XSNS_18 - XSNS_18, -#endif - -#ifdef XSNS_19 - XSNS_19, -#endif - -#ifdef XSNS_20 - XSNS_20, -#endif - -#ifdef XSNS_21 - XSNS_21, -#endif - -#ifdef XSNS_22 - XSNS_22, -#endif - -#ifdef XSNS_23 - XSNS_23, -#endif - -#ifdef XSNS_24 - XSNS_24, -#endif - -#ifdef XSNS_25 - XSNS_25, -#endif - -#ifdef XSNS_26 - XSNS_26, -#endif - -#ifdef XSNS_27 - XSNS_27, -#endif - -#ifdef XSNS_28 - XSNS_28, -#endif - -#ifdef XSNS_29 - XSNS_29, -#endif - -#ifdef XSNS_30 - XSNS_30, -#endif - -#ifdef XSNS_31 - XSNS_31, -#endif - -#ifdef XSNS_32 - XSNS_32, -#endif - -#ifdef XSNS_33 - XSNS_33, -#endif - -#ifdef XSNS_34 - XSNS_34, -#endif - -#ifdef XSNS_35 - XSNS_35, -#endif - -#ifdef XSNS_36 - XSNS_36, -#endif - -#ifdef XSNS_37 - XSNS_37, -#endif - -#ifdef XSNS_38 - XSNS_38, -#endif - -#ifdef XSNS_39 - XSNS_39, -#endif - -#ifdef XSNS_40 - XSNS_40, -#endif - -#ifdef XSNS_41 - XSNS_41, -#endif - -#ifdef XSNS_42 - XSNS_42, -#endif - -#ifdef XSNS_43 - XSNS_43, -#endif - -#ifdef XSNS_44 - XSNS_44, -#endif - -#ifdef XSNS_45 - XSNS_45, -#endif - -#ifdef XSNS_46 - XSNS_46, -#endif - -#ifdef XSNS_47 - XSNS_47, -#endif - -#ifdef XSNS_48 - XSNS_48, -#endif - -#ifdef XSNS_49 - XSNS_49, -#endif - -#ifdef XSNS_50 - XSNS_50, -#endif - -#ifdef XSNS_51 - XSNS_51, -#endif - -#ifdef XSNS_52 - XSNS_52, -#endif - -#ifdef XSNS_53 - XSNS_53, -#endif - -#ifdef XSNS_54 - XSNS_54, -#endif - -#ifdef XSNS_55 - XSNS_55, -#endif - -#ifdef XSNS_56 - XSNS_56, -#endif - -#ifdef XSNS_57 - XSNS_57, -#endif - -#ifdef XSNS_58 - XSNS_58, -#endif - -#ifdef XSNS_59 - XSNS_59, -#endif - -#ifdef XSNS_60 - XSNS_60, -#endif - -#ifdef XSNS_61 - XSNS_61, -#endif - -#ifdef XSNS_62 - XSNS_62, -#endif - -#ifdef XSNS_63 - XSNS_63, -#endif - -#ifdef XSNS_64 - XSNS_64, -#endif - -#ifdef XSNS_65 - XSNS_65, -#endif - -#ifdef XSNS_66 - XSNS_66, -#endif - -#ifdef XSNS_67 - XSNS_67, -#endif - -#ifdef XSNS_68 - XSNS_68, -#endif - -#ifdef XSNS_69 - XSNS_69, -#endif - -#ifdef XSNS_70 - XSNS_70, -#endif - -#ifdef XSNS_71 - XSNS_71, -#endif - -#ifdef XSNS_72 - XSNS_72, -#endif - -#ifdef XSNS_73 - XSNS_73, -#endif - -#ifdef XSNS_74 - XSNS_74, -#endif - -#ifdef XSNS_75 - XSNS_75, -#endif - -#ifdef XSNS_76 - XSNS_76, -#endif - -#ifdef XSNS_77 - XSNS_77, -#endif - -#ifdef XSNS_78 - XSNS_78, -#endif - -#ifdef XSNS_79 - XSNS_79, -#endif - -#ifdef XSNS_80 - XSNS_80, -#endif - -#ifdef XSNS_81 - XSNS_81, -#endif - -#ifdef XSNS_82 - XSNS_82, -#endif - -#ifdef XSNS_83 - XSNS_83, -#endif - -#ifdef XSNS_84 - XSNS_84, -#endif - -#ifdef XSNS_85 - XSNS_85, -#endif - -#ifdef XSNS_86 - XSNS_86, -#endif - -#ifdef XSNS_87 - XSNS_87, -#endif - -#ifdef XSNS_88 - XSNS_88, -#endif - -#ifdef XSNS_89 - XSNS_89, -#endif - -#ifdef XSNS_90 - XSNS_90, -#endif - -#ifdef XSNS_91 - XSNS_91, -#endif - -#ifdef XSNS_92 - XSNS_92, -#endif - -#ifdef XSNS_93 - XSNS_93, -#endif - -#ifdef XSNS_94 - XSNS_94, -#endif - -#ifdef XSNS_95 - XSNS_95, -#endif - -#ifdef XSNS_96 - XSNS_96, -#endif - -#ifdef XSNS_97 - XSNS_97, -#endif - -#ifdef XSNS_98 - XSNS_98, -#endif - -#ifdef XSNS_99 - XSNS_99 -#endif -}; - - - -bool XsnsEnabled(uint32_t sns_index) -{ - if (sns_index < sizeof(kXsnsList)) { -#ifdef XFUNC_PTR_IN_ROM - uint32_t index = pgm_read_byte(kXsnsList + sns_index); -#else - uint32_t index = kXsnsList[sns_index]; -#endif - return bitRead(Settings.sensors[index / 32], index % 32); - } - return true; -} - -void XsnsSensorState(void) -{ - ResponseAppend_P(PSTR("\"")); - for (uint32_t i = 0; i < sizeof(kXsnsList); i++) { -#ifdef XFUNC_PTR_IN_ROM - uint32_t sensorid = pgm_read_byte(kXsnsList + i); -#else - uint32_t sensorid = kXsnsList[i]; -#endif - bool disabled = false; - if (sensorid < MAX_XSNS_DRIVERS) { - disabled = !bitRead(Settings.sensors[sensorid / 32], sensorid % 32); - } - ResponseAppend_P(PSTR("%s%s%d"), (i) ? "," : "", (disabled) ? "!" : "", sensorid); - } - ResponseAppend_P(PSTR("\"")); -} - - - - - -bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index) -{ - xsns_index++; - if (xsns_index == xsns_present) { xsns_index = 0; } - -#ifndef USE_DEBUG_DRIVER - if (FUNC_WEB_SENSOR == Function) { -#endif - uint32_t max_disabled = xsns_present; - while (!XsnsEnabled(xsns_index) && max_disabled--) { - xsns_index++; - if (xsns_index == xsns_present) { xsns_index = 0; } - } -#ifndef USE_DEBUG_DRIVER - } -#endif - - return xsns_func_ptr[xsns_index](Function); -} - -bool XsnsCall(uint8_t Function) -{ - bool result = false; - - DEBUG_TRACE_LOG(PSTR("SNS: %d"), Function); - -#ifdef PROFILE_XSNS_EVERY_SECOND - uint32_t profile_start_millis = millis(); -#endif - - for (uint32_t x = 0; x < xsns_present; x++) { -#ifdef USE_DEBUG_DRIVER - if (XsnsEnabled(x)) { -#endif - - if ((FUNC_WEB_SENSOR == Function) && !XsnsEnabled(x)) { continue; } - -#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND - uint32_t profile_start_millis = millis(); -#endif - result = xsns_func_ptr[x](Function); - -#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND - uint32_t profile_millis = millis() - profile_start_millis; - if (profile_millis) { - if (FUNC_EVERY_SECOND == Function) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PRF: At %08u XsnsCall %d to Sensor %d took %u mS"), uptime, Function, x, profile_millis); - } - } -#endif - - if (result && ((FUNC_COMMAND == Function) || - (FUNC_PIN_STATE == Function) || - (FUNC_COMMAND_SENSOR == Function) - )) { - break; - } -#ifdef USE_DEBUG_DRIVER - } -#endif - } - -#ifdef PROFILE_XSNS_EVERY_SECOND - uint32_t profile_millis = millis() - profile_start_millis; - if (profile_millis) { - if (FUNC_EVERY_SECOND == Function) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PRF: At %08u XsnsCall %d took %u mS"), uptime, Function, profile_millis); - } - } -#endif - - return result; -} -# 1 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xx2c_interface.ino" -# 20 "/Users/javierarigitalopez/WorkSpace/Github/Tasmota/tasmota/xx2c_interface.ino" -#ifdef USE_I2C - -#ifdef XFUNC_PTR_IN_ROM -const uint8_t kI2cList[] PROGMEM = { -#else -const uint8_t kI2cList[] = { -#endif - -#ifdef XI2C_01 - XI2C_01, -#endif - -#ifdef XI2C_02 - XI2C_02, -#endif - -#ifdef XI2C_03 - XI2C_03, -#endif - -#ifdef XI2C_04 - XI2C_04, -#endif - -#ifdef XI2C_05 - XI2C_05, -#endif - -#ifdef XI2C_06 - XI2C_06, -#endif - -#ifdef XI2C_07 - XI2C_07, -#endif - -#ifdef XI2C_08 - XI2C_08, -#endif - -#ifdef XI2C_09 - XI2C_09, -#endif - -#ifdef XI2C_10 - XI2C_10, -#endif - -#ifdef XI2C_11 - XI2C_11, -#endif - -#ifdef XI2C_12 - XI2C_12, -#endif - -#ifdef XI2C_13 - XI2C_13, -#endif - -#ifdef XI2C_14 - XI2C_14, -#endif - -#ifdef XI2C_15 - XI2C_15, -#endif - -#ifdef XI2C_16 - XI2C_16, -#endif - -#ifdef XI2C_17 - XI2C_17, -#endif - -#ifdef XI2C_18 - XI2C_18, -#endif - -#ifdef XI2C_19 - XI2C_19, -#endif - -#ifdef XI2C_20 - XI2C_20, -#endif - -#ifdef XI2C_21 - XI2C_21, -#endif - -#ifdef XI2C_22 - XI2C_22, -#endif - -#ifdef XI2C_23 - XI2C_23, -#endif - -#ifdef XI2C_24 - XI2C_24, -#endif - -#ifdef XI2C_25 - XI2C_25, -#endif - -#ifdef XI2C_26 - XI2C_26, -#endif - -#ifdef XI2C_27 - XI2C_27, -#endif - -#ifdef XI2C_28 - XI2C_28, -#endif - -#ifdef XI2C_29 - XI2C_29, -#endif - -#ifdef XI2C_30 - XI2C_30, -#endif - -#ifdef XI2C_31 - XI2C_31, -#endif - -#ifdef XI2C_32 - XI2C_32, -#endif - -#ifdef XI2C_33 - XI2C_33, -#endif - -#ifdef XI2C_34 - XI2C_34, -#endif - -#ifdef XI2C_35 - XI2C_35, -#endif - -#ifdef XI2C_36 - XI2C_36, -#endif - -#ifdef XI2C_37 - XI2C_37, -#endif - -#ifdef XI2C_38 - XI2C_38, -#endif - -#ifdef XI2C_39 - XI2C_39, -#endif - -#ifdef XI2C_40 - XI2C_40, -#endif - -#ifdef XI2C_41 - XI2C_41, -#endif - -#ifdef XI2C_42 - XI2C_42, -#endif - -#ifdef XI2C_43 - XI2C_43, -#endif - -#ifdef XI2C_44 - XI2C_44, -#endif - -#ifdef XI2C_45 - XI2C_45, -#endif - -#ifdef XI2C_46 - XI2C_46, -#endif - -#ifdef XI2C_47 - XI2C_47, -#endif - -#ifdef XI2C_48 - XI2C_48, -#endif - -#ifdef XI2C_49 - XI2C_49, -#endif - -#ifdef XI2C_50 - XI2C_50, -#endif - -#ifdef XI2C_51 - XI2C_51, -#endif - -#ifdef XI2C_52 - XI2C_52, -#endif - -#ifdef XI2C_53 - XI2C_53, -#endif - -#ifdef XI2C_54 - XI2C_54, -#endif - -#ifdef XI2C_55 - XI2C_55, -#endif - -#ifdef XI2C_56 - XI2C_56, -#endif - -#ifdef XI2C_57 - XI2C_57, -#endif - -#ifdef XI2C_58 - XI2C_58, -#endif - -#ifdef XI2C_59 - XI2C_59, -#endif - -#ifdef XI2C_60 - XI2C_60, -#endif - -#ifdef XI2C_61 - XI2C_61, -#endif - -#ifdef XI2C_62 - XI2C_62, -#endif - -#ifdef XI2C_63 - XI2C_63, -#endif - -#ifdef XI2C_64 - XI2C_64, -#endif - -#ifdef XI2C_65 - XI2C_65, -#endif - -#ifdef XI2C_66 - XI2C_66, -#endif - -#ifdef XI2C_67 - XI2C_67, -#endif - -#ifdef XI2C_68 - XI2C_68, -#endif - -#ifdef XI2C_69 - XI2C_69, -#endif - -#ifdef XI2C_70 - XI2C_70, -#endif - -#ifdef XI2C_71 - XI2C_71, -#endif - -#ifdef XI2C_72 - XI2C_72, -#endif - -#ifdef XI2C_73 - XI2C_73, -#endif - -#ifdef XI2C_74 - XI2C_74, -#endif - -#ifdef XI2C_75 - XI2C_75, -#endif - -#ifdef XI2C_76 - XI2C_76, -#endif - -#ifdef XI2C_77 - XI2C_77, -#endif - -#ifdef XI2C_78 - XI2C_78, -#endif - -#ifdef XI2C_79 - XI2C_79, -#endif - -#ifdef XI2C_80 - XI2C_80, -#endif - -#ifdef XI2C_81 - XI2C_81, -#endif - -#ifdef XI2C_82 - XI2C_82, -#endif - -#ifdef XI2C_83 - XI2C_83, -#endif - -#ifdef XI2C_84 - XI2C_84, -#endif - -#ifdef XI2C_85 - XI2C_85, -#endif - -#ifdef XI2C_86 - XI2C_86, -#endif - -#ifdef XI2C_87 - XI2C_87, -#endif - -#ifdef XI2C_88 - XI2C_88, -#endif - -#ifdef XI2C_89 - XI2C_89, -#endif - -#ifdef XI2C_90 - XI2C_90, -#endif - -#ifdef XI2C_91 - XI2C_91, -#endif - -#ifdef XI2C_92 - XI2C_92, -#endif - -#ifdef XI2C_93 - XI2C_93, -#endif - -#ifdef XI2C_94 - XI2C_94, -#endif - -#ifdef XI2C_95 - XI2C_95, -#endif - -#ifdef XI2C_96 - XI2C_96 -#endif -}; - - - -bool I2cEnabled(uint32_t i2c_index) -{ - return (i2c_flg && bitRead(Settings.i2c_drivers[i2c_index / 32], i2c_index % 32)); -} - -void I2cDriverState(void) -{ - ResponseAppend_P(PSTR("\"")); - for (uint32_t i = 0; i < sizeof(kI2cList); i++) { -#ifdef XFUNC_PTR_IN_ROM - uint32_t i2c_driver_id = pgm_read_byte(kI2cList + i); -#else - uint32_t i2c_driver_id = kI2cList[i]; -#endif - bool disabled = false; - if (i2c_driver_id < MAX_I2C_DRIVERS) { - disabled = !bitRead(Settings.i2c_drivers[i2c_driver_id / 32], i2c_driver_id % 32); - } - ResponseAppend_P(PSTR("%s%s%d"), (i) ? "," : "", (disabled) ? "!" : "", i2c_driver_id); - } - ResponseAppend_P(PSTR("\"")); -} - -#endif \ No newline at end of file diff --git a/tasmota/xdrv_39_thermostat.ino b/tasmota/xdrv_39_thermostat.ino index 85a1b245b..88f460e8b 100644 --- a/tasmota/xdrv_39_thermostat.ino +++ b/tasmota/xdrv_39_thermostat.ino @@ -22,7 +22,7 @@ #define XDRV_39 39 // Enable/disable debugging -#define DEBUG_THERMOSTAT +//#define DEBUG_THERMOSTAT #ifdef DEBUG_THERMOSTAT #define DOMOTICZ_IDX1 791