From af96b9726d4dfa5f57de0beb81f856707d9f5296 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sat, 7 Apr 2018 01:03:59 -0300 Subject: [PATCH] Update xdrv_10_KNX.ino --- sonoff/xdrv_10_KNX.ino | 390 ++++++++++++++++++++++++++++++++++------- 1 file changed, 322 insertions(+), 68 deletions(-) diff --git a/sonoff/xdrv_10_KNX.ino b/sonoff/xdrv_10_KNX.ino index 8289a96ad..186ab8356 100644 --- a/sonoff/xdrv_10_KNX.ino +++ b/sonoff/xdrv_10_KNX.ino @@ -1,11 +1,7 @@ /* - xdrv_08_KNX.ino - KNX IP Protocol support for Sonoff-Tasmota + xdrv_10_KNX.ino - KNX IP Protocol support for Sonoff-Tasmota - Copyright (C) 2018 Adrian Scillato - - Based on esp-knx-ip library for KNX/IP communication on an ESP8266 - Author: Nico Weichbrodt - Web: https://github.com/envy/esp-knx-ip + Copyright (C) 2018 Adrian Scillato (https://github.com/ascillato) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,13 +20,54 @@ #ifdef USE_KNX -#include // Include KNX IP library +#include // Include ESP KNX IP library (https://github.com/envy/esp-knx-ip) + // use the async-udp branch (https://github.com/envy/esp-knx-ip/tree/async-udp) + // change on esp-knx-ip.h file the following: + // #define MAX_CALLBACK_ASSIGNMENTS 20 + // #define MAX_CALLBACKS 20 + // #define ALLOW_MULTIPLE_CALLBACKS_PER_ADDRESS 1 + // //#define ESP_KNX_DEBUG <-- comment this line + // The ESP KNX IP library calls ESPAsyncUDP library (https://github.com/me-no-dev/ESPAsyncUDP) + // use ESPAsyncUDP library patched with the PR #21 (https://github.com/me-no-dev/ESPAsyncUDP/pull/21) + +/* Variables in settings.h + +bool Settings.flag.knx_enabled Enable/Disable KNX Protocol +uint16_t Settings.knx_physsical_addr Physical KNX address of this device +byte Settings.knx_GA_registered Number of group address to read +byte Settings.knx_CB_registered Number of group address to write +uint16_t Settings.knx_GA_addr[MAX_KNX_GA] Group address to read +uint16_t Settings.knx_CB_addr[MAX_KNX_CB] Group address to write +byte Settings.knx_GA_param[MAX_KNX_GA] Type of Input (relay changed, button pressed, sensor read) +byte Settings.knx_CB_param[MAX_KNX_CB] Type of Output (set relay, toggle relay, reply sensor value) + +Constants in sonoff.h + +#define MAX_KNX_GA 10 // Max number of KNX Group Addresses to read that can be set +#define MAX_KNX_CB 10 // Max number of KNX Group Addresses to write that can be set +*/ + +void KNX_CB_Action(message_t const &msg, void *arg); // Define function (action callback) to be called by the KNX_IP Library + // when an action is requested by another KNX Device + +address_t KNX_physs_addr; // Physical KNX address of this device +address_t KNX_addr; // KNX Address converter variable + +#define KNX_Empty 255 +#define KNX_temperature 17 +#define KNX_humidity 18 +#define KNX_MAX_device_param 18 + +//float last_temp; +//float last_hum; + -#define KNX_Empty_ID 255 void relay_cb(message_t const &msg, void *arg); void temp_cb(message_t const &msg, void *arg); +#define KNX_Empty_ID 255 + address_t physaddr; config_id_t enable_knx_id; config_id_t disable_knx_id; @@ -50,17 +87,17 @@ typedef struct __device_parameters device_parameters_t device_param[] = { { D_SENSOR_RELAY " 1",1 , 255, true}, // device_param[0] = Relay 1 { D_SENSOR_RELAY " 2",2 , 255, true}, // device_param[1] = Relay 2 - { D_SENSOR_RELAY " 3",3 , 255, true}, - { D_SENSOR_RELAY " 4",4 , 255, true}, + { D_SENSOR_RELAY " 3",3 , 255, false}, + { D_SENSOR_RELAY " 4",4 , 255, false}, { D_SENSOR_RELAY " 5",5 , 255, false}, { D_SENSOR_RELAY " 6",6 , 255, false}, { D_SENSOR_RELAY " 7",7 , 255, false}, // device_param[6] = Relay 7 { D_SENSOR_RELAY " 8",8 , 255, false}, // device_param[7] = Relay 8 { D_SENSOR_BUTTON " 1",9 , 255, true}, // device_param[8] = Button 1 { D_SENSOR_BUTTON " 2",10 , 255, true}, // device_param[9] = Button 2 - { D_SENSOR_BUTTON " 3",11 , 255, true}, // device_param[10] = Button 3 - { D_SENSOR_BUTTON " 4",12 , 255, true}, // device_param[11] = Button 4 - { D_TEMPERATURE ,13 , 255, true}, // device_param[12] = Temperature + { D_SENSOR_BUTTON " 3",11 , 255, false}, // device_param[10] = Button 3 + { D_SENSOR_BUTTON " 4",12 , 255, false}, // device_param[11] = Button 4 + { D_TEMPERATURE ,13 , 255, false}, // device_param[12] = Temperature {nullptr,0 , 255, false} }; @@ -80,16 +117,16 @@ const char *device_param_cb[] = { D_REPLY " " D_TEMPERATURE, nullptr }; - +/* // Translations config_webUI_t config_webUI = { D_CONFIGURE_KNX, D_KNX_PHYSICAL_ADDRESS, - D_KNX_SET, + "SET", D_KNX_ADD, D_DELETE }; - +*/ bool flag_knx_enabled = true; float last_temp = 25.0; int knx_update_rate = 5; @@ -133,7 +170,7 @@ for (byte j = 0; j < GPIO_SENSOR_END; j++) { // The order of the knx.***_register_*** code, is the order that is going to be shown on the web page. // Translations -knx.config_web_UI(config_webUI); +//knx.config_web_UI(config_webUI); //knx.config_register_Title( D_KNX_PARAMETERS ); @@ -142,7 +179,7 @@ knx.config_web_UI(config_webUI); //knx.config_register_SubTitle( D_KNX_GENERAL_CONFIG ); //Set Physical KNX Address of the device -knx.config_register_pa(); +//knx.config_register_pa(); //knx.physical_address_set(Settings.knx_physs_addr); //knx.physical_address_set(knx.PA_to_address(1, 1, 1)); @@ -150,8 +187,8 @@ knx.config_register_pa(); //knx.config_register_blankspace(); -knx.feedback_register_action("KNX: " D_ON, knx_toggle_flag_enabled, D_STOP, nullptr, knx_status_enabled); -knx.feedback_register_action("KNX: " D_OFF, knx_toggle_flag_enabled, D_START, nullptr, knx_status_disabled); +//knx.feedback_register_action("KNX: " D_ON, knx_toggle_flag_enabled, D_STOP, nullptr, knx_status_enabled); +//knx.feedback_register_action("KNX: " D_OFF, knx_toggle_flag_enabled, D_START, nullptr, knx_status_disabled); //knx.config_register_line(); @@ -173,13 +210,13 @@ for (int i = 0; i < 13; ++i) //knx.config_set_ga(device_param[i].id, knx.GA_to_address(2,2,1)); } -//knx.config_set_ga(device_param[0].id, knx.GA_to_address(2,2,1)); +knx.config_set_ga(device_param[0].id, knx.GA_to_address(2,2,1)); //knx.config_set_ga(device_param[12].id, knx.GA_to_address(4,1,1)); //knx.config_register_blankspace(); //update_rate_id = knx.config_register_int( D_KNX_UPDATE_INTERVAL , Settings.knx_update_rate); -update_rate_id = knx.config_register_int( D_KNX_UPDATE_INTERVAL , knx_update_rate); +update_rate_id = knx.config_register_int( "UPDATE INTERVAL" , knx_update_rate); //knx.config_register_line(); @@ -196,7 +233,7 @@ for (int i = 0; i < 12; ++i) //knx.callback_assign(ga_conf, Settings.knx_CB_addr(i)); if (i==0) { - //knx.callback_assign(cb_conf_id, knx.GA_to_address(2,2,1)); + knx.callback_assign(cb_conf_id, knx.GA_to_address(2,2,1)); } } } @@ -211,42 +248,25 @@ if (device_param[j].show) //knx.config_register_line(); -knx.feedback_register_action("", KNXSaveSettings, D_SAVE); // Save Button +//knx.feedback_register_action("", KNXSaveSettings, D_SAVE); // Save Button -knx.feedback_register_action("", KNX_Return_button, D_CONFIGURATION); // Save Button +//knx.feedback_register_action("", KNX_Return_button, D_CONFIGURATION); // Save Button // END KNX WebPage Configuration -} -void KNXLoop() -{ - knx.loop(); // Process knx events -} +// Start KNX +//knx.start(nullptr); -void KNX_EVERY_SECOND() -{ - if (!flag_knx_enabled) { return; } - - if ( knx.config_get_int(update_rate_id) > 0 ) - { - unsigned long now = millis(); - - if (next_change < now) - { - next_change = now + 1000 * knx.config_get_int(update_rate_id); - - knx.write_2byte_float(knx.config_get_ga(device_param[12].id), last_temp); - - } - } } void relay_cb(message_t const &msg, void *arg) { device_parameters_t *chan = (device_parameters_t *)arg; + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX " RELAY CB")); + AddLog(LOG_LEVEL_INFO); if (!flag_knx_enabled) { return; } switch (msg.ct) { @@ -267,17 +287,23 @@ void relay_cb(message_t const &msg, void *arg) } } -void KNXUpdatePowerState(byte device, power_t state) +void KNX_Update_Power_State(byte device, power_t state) { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX " 1")); + AddLog(LOG_LEVEL_INFO); if (!flag_knx_enabled) { return; } + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX " 2")); + AddLog(LOG_LEVEL_INFO); if ( device_param[device -1].id != KNX_Empty_ID ) // Group Address configured? 255 = empty { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX " 3")); + AddLog(LOG_LEVEL_INFO); bool power = bitRead(state, device -1); knx.write_1bit(knx.config_get_ga(device_param[device -1].id), power); } } -void knx_send_button_power(byte key, byte device, byte state) +void KNX_Send_Button_Power(byte key, byte device, byte state) { // key 0 = button_topic // key 1 = switch_topic @@ -309,36 +335,257 @@ void temp_cb(message_t const &msg, void *arg) } } -void knx_toggle_flag_enabled(void *arg) -{ - flag_knx_enabled = !flag_knx_enabled; - /*if (Settings.flag.knx_enabled) + + + + + + + +byte KNX_GA_Search( byte param, byte sequence = KNX_Empty ) +{/* + for (byte i = 0; i < Settings.knx_GA_registered; ++i) { - knx.pause(); + if ( Settings.knx_GA_param[i] == param ) + { + if ( Settings.knx_GA_addr[i] ) // Relay has group address set? GA=0/0/0 can not be used as KNX address, so it is used here as a: not set value + { + if ( i != sequence ) { return i; } + } + } } - else + return 0;*/ +} + + +void KNX_CB_Action(message_t const &msg, void *arg) +{ +/* + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX " 1")); + AddLog(LOG_LEVEL_INFO); + + device_parameters_t *chan = (device_parameters_t *)arg; + if (!(Settings.flag.knx_enabled)) { return; } + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX " 2")); + AddLog(LOG_LEVEL_INFO); + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_RECEIVED_FROM " %d.%d.%d " D_COMMAND " %s: %d " 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, + msg.data[0], + device_param_cb[chan->type]); + AddLog(LOG_LEVEL_DEBUG); + + switch (msg.ct) { - knx.continue(); + case KNX_CT_WRITE: + if (chan->type < 9) // Set Relays + { + ExecuteCommandPower(chan->type, msg.data[0]); + } + else if (chan->type < 17) // Toggle Relays + { + ExecuteCommandPower((chan->type) -8, 2); + } + break; + case KNX_CT_READ: + if (chan->type < 9) // reply Relays status + { + knx.answer_1bit(msg.received_on, chan->last_state); + } + else if (chan->type = KNX_temperature) // Reply Temperature + { + knx.answer_2byte_float(msg.received_on, last_temp); + } + else if (chan->type = KNX_humidity) // Reply Humidity + { + knx.answer_2byte_float(msg.received_on, last_hum); + } + break; + } + */ +} + + + +void KNX_Sensor(byte 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; } + + byte i = KNX_GA_Search(sensor_type); + while ( i > 0 ) { + KNX_addr.value = Settings.knx_GA_addr[i]; + knx.write_2byte_float(KNX_addr, value); + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "%s " D_SENT_TO " %d.%d.%d "), + device_param_ga[i], + KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); + AddLog(LOG_LEVEL_DEBUG); + + i = KNX_GA_Search(sensor_type, i); }*/ } -bool knx_status_enabled() { return flag_knx_enabled; } -bool knx_status_disabled() { return !flag_knx_enabled; } +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ -void KNX_Return_button(void *arg) -{ - WebServer->sendHeader(F("Location"),F("/cn")); - WebServer->send(302); +#ifdef USE_WEBSERVER +const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; + +const char HTTP_FORM_KNX[] PROGMEM = + "
 " D_KNX_PARAMETERS " 
" + "" + "
" + "" D_KNX_PHYSICAL_ADDRESS " " + " . " + " . " + "" + "

" D_KNX_PHYSICAL_ADDRESS_NOTE "

" + "" D_KNX_ENABLE "

" + + "
" + "" 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 = + "
{optex} -> GAfnum / GAarea / GAfdef

" + "
" + "" D_KNX_GROUP_ADDRESS_TO_READ "
"; + +const char HTTP_FORM_KNX4[] PROGMEM = + "-> -> "); + page += FPSTR(HTTP_FORM_KNX_GA); + page += FPSTR(HTTP_FORM_KNX_ADD_BTN); + page.replace(F("{btnval}"), String(1)); + for (byte i = 0; i < Settings.knx_GA_registered ; i++) + { + if ( Settings.knx_GA_param[i] ) + { + page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW); + page.replace(F("{opval}"), String(Settings.knx_GA_param[i])); + page.replace(F("{optex}"), String(device_param_ga[Settings.knx_GA_param[i]-1])); + KNX_addr.value = Settings.knx_GA_addr[i]; + page.replace(F("GAfnum"), String(KNX_addr.ga.area)); + page.replace(F("GAarea"), String(KNX_addr.ga.line)); + page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + } + } + page += FPSTR(HTTP_FORM_KNX3); + page += FPSTR(HTTP_FORM_KNX_GA); + page.replace(F("GAfnum"), F("CBfnum")); + page.replace(F("GAarea"), F("CBarea")); + page.replace(F("GAfdef"), F("CBfdef")); + page += FPSTR(HTTP_FORM_KNX4); + for (byte i = 0; i < KNX_MAX_device_param ; i++) + { + if ( device_param[i].show ) + { + page += FPSTR(HTTP_FORM_KNX_OPT); + page.replace(F("{vop}"), String(device_param[i].type)); + page.replace(F("{nop}"), String(device_param_cb[i])); + } + } + page += F(" "); + page += FPSTR(HTTP_FORM_KNX_ADD_BTN); + page.replace(F("{btnval}"), String(2)); + for (byte i = 0; i < Settings.knx_CB_registered ; i++) + { + if ( Settings.knx_CB_param[i] ) + { + page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW2); + page.replace(F("{opval}"), String(Settings.knx_CB_param[i])); + page.replace(F("{optex}"), String(device_param_cb[Settings.knx_CB_param[i]-1])); + KNX_addr.value = Settings.knx_CB_addr[i]; + page.replace(F("GAfnum"), String(KNX_addr.ga.area)); + page.replace(F("GAarea"), String(KNX_addr.ga.line)); + page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + } + } + page += F("
"); + page += FPSTR(HTTP_FORM_END); + page += FPSTR(HTTP_BTN_CONF); + ShowPage(page); + */ } -void KNXSaveSettings(void *arg) + +void KNX_Save_Settings() { + // Read all data from the webpage + // Write to settings.knx + // Write to ESP_KNX_IP library /* /////config Settings.knx.physs_addr = physical_address_get(); - Settings.knx.flag_knx_enabled + Settings.flag.knx_enabled k = 0 for j = 0 to max cant items (relay1,2,3,etc) @@ -406,7 +653,17 @@ void KNXSaveSettings(void *arg) ssensor_indices, Settings.domoticz_update_timer); AddLog(LOG_LEVEL_INFO); */ + + //snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX D_SAVE_CONFIGURATION)); + //AddLog(LOG_LEVEL_INFO); } +#endif // USE_WEBSERVER + + + + + + /*********************************************************************************************\ * Interface @@ -422,13 +679,10 @@ boolean Xdrv10(byte function) KNXStart(); break; case FUNC_LOOP: - KNXLoop(); - break; - case FUNC_EVERY_SECOND: - KNX_EVERY_SECOND(); + knx.loop(); // Process knx events break; // case FUNC_COMMAND: -// result = MqttCommand(); +// result = KNXCommand(); // break; // case FUNC_SET_POWER: // break;