diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3b6f2d086..a2fa5648e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,6 +6,6 @@ - [ ] The pull request is done against the latest dev branch - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR. - - [ ] The code change is tested and works on core 2.6 + - [ ] The code change is tested and works on core 2.6.1 - [ ] The code change pass travis tests. **Your PR cannot be merged unless tests pass** - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). diff --git a/platformio.ini b/platformio.ini index cbed5b432..297145fd1 100755 --- a/platformio.ini +++ b/platformio.ini @@ -99,8 +99,6 @@ extra_scripts = pio/strip-floats.py [core_active] ; Select one core set for platform and build_flags -;platform = ${core_2_6_0.platform} -;build_flags = ${core_2_6_0.build_flags} platform = ${core_2_6_1.platform} build_flags = ${core_2_6_1.build_flags} ;platform = ${core_stage.platform} @@ -114,60 +112,13 @@ build_flags = ${core_2_6_1.build_flags} build_flags = -D NDEBUG -mtarget-align -Wl,-Map,firmware.map - -[core_2_6_0] -; *** Esp8266 core for Arduino version 2.6.0 (for Windows, most Linux variants and Mac) -; *** custom setup until the core 2.6.0 version is official released from PlatformIO crew -platform = https://github.com/Jason2866/platform-espressif8266.git#core_2_6_0 -build_flags = ${esp82xx_defaults.build_flags} - -Wl,-Teagle.flash.1m.ld - -O2 - -DBEARSSL_SSL_BASIC -; NONOSDK221 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK221 -; NONOSDK22x_190313 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190313 -; NONOSDK22x_190703 = 2.2.2-dev(38a443e) (Tasmota default) - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 -; NONOSDK22x_191024 = 2.2.2-dev(5ab15d1) -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191024 -; NONOSDK22x_191105 = 2.2.2-dev(bb83b9b) -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105 -; NONOSDK3V0 (known issues) -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; lwIP 1.4 -; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH -; lwIP 2 - Low Memory -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -; lwIP 2 - Higher Bandwidth -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -; lwIP 2 - Higher Bandwidth Low Memory no Features -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY_LOW_FLASH -; lwIP 2 - Higher Bandwidth no Features (Tasmota default) - -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH -; lwIP 2 - Higher Bandwidth IPv6 (use ONLY if you need IPv6, experimental!) -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_HIGHER_BANDWIDTH -; VTABLES in Flash (Tasmota default) - -DVTABLES_IN_FLASH -; VTABLES in Heap -; -DVTABLES_IN_DRAM -; VTABLES in IRAM -; -DVTABLES_IN_IRAM -; enable one option set -> No exception recommended -; No exception code in firmware - -fno-exceptions - -lstdc++ -; Exception code in firmware /needs much space! 90k -; -fexceptions -; -lstdc++-exc [core_2_6_1] ; *** Esp8266 core for Arduino version 2.6.1 (for Windows, most Linux variants and Mac) -; *** custom setup until the core 2.6.0 version is official released from PlatformIO crew +; *** custom setup until the core 2.6.1 version is official released from PlatformIO crew platform = https://github.com/Jason2866/platform-espressif8266.git#core_2_6_1 build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld - -O2 -DBEARSSL_SSL_BASIC ; NONOSDK221 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK221 @@ -220,9 +171,9 @@ build_flags = ${esp82xx_defaults.build_flags} ; NONOSDK22x_190313 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190313 ; NONOSDK22x_190703 (Tasmota default) -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 ; NONOSDK22x_191024 - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191024 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191024 ; NONOSDK22x_191105 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105 ; NONOSDK3V0 (known issues) @@ -263,11 +214,11 @@ build_flags = ${esp82xx_defaults.build_flags} ; NONOSDK22x_190313 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190313 ; NONOSDK22x_190703 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 ; NONOSDK22x_191024 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191024 ; NONOSDK22x_191105 - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105 ; NONOSDK3V0 (known issues) ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 ; lwIP 1.4 diff --git a/tasmota/_changelog.ino b/tasmota/_changelog.ino index c54ed15d1..d36ae512d 100644 --- a/tasmota/_changelog.ino +++ b/tasmota/_changelog.ino @@ -1,4 +1,7 @@ /*********************************************************************************************\ + * 7.0.0.6 20191122 + * Add colorpicker to WebUI by Christian Staars (#6984) + * * 7.0.0.5 20191118 * Fix boot loop regression * Add command TempOffset -12.6 .. 12.6 to set global temperature sensor offset (#6958) diff --git a/tasmota/language/es-ES.h b/tasmota/language/es-ES.h index 086c6a2be..014d822a9 100644 --- a/tasmota/language/es-ES.h +++ b/tasmota/language/es-ES.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v7.0.0.3 + * Updated until v7.0.0.5 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -75,7 +75,7 @@ #define D_COUNTER "Contador" #define D_CURRENT "Corriente" // As in Voltage and Current #define D_DATA "Datos" -#define D_DARKLIGHT "Oscura" +#define D_DARKLIGHT "Oscuro" #define D_DEBUG "Debug" #define D_DISABLED "Deshabilitado" #define D_DISTANCE "Distancia" diff --git a/tasmota/language/pl-PL.h b/tasmota/language/pl-PL.h index 47945290f..7a631f95f 100644 --- a/tasmota/language/pl-PL.h +++ b/tasmota/language/pl-PL.h @@ -64,10 +64,10 @@ #define D_BUTTON "Przycisk" #define D_BY "by" // Written by me #define D_BYTES "Bajtów" -#define D_CELSIUS "Celsiusza" +#define D_CELSIUS "Celsiusz" #define D_CHANNEL "Kanał" -#define D_CO2 "Dwutlenku węgla" -#define D_CODE "kod" // Button code +#define D_CO2 "Dwutlenek węgla" +#define D_CODE "Kod" // Button code #define D_COLDLIGHT "Zimny" #define D_COMMAND "Komenda" #define D_CONNECTED "Połączony" @@ -77,11 +77,11 @@ #define D_DATA "Data" #define D_DARKLIGHT "Ciemny" #define D_DEBUG "Debug" -#define D_DISABLED "Zablokowany" +#define D_DISABLED "Wyłączony" #define D_DISTANCE "Odległość" #define D_DNS_SERVER "Serwer DNS" #define D_DONE "Wykonane" -#define D_DST_TIME "DST" +#define D_DST_TIME "Czas DST" #define D_ECO2 "eCO2" #define D_EMULATION "Emulacja" #define D_ENABLED "Załączony" @@ -102,7 +102,7 @@ #define D_HOST "Serwer" #define D_HOSTNAME "Nazwa serwera" #define D_HUMIDITY "Wilgotność" -#define D_ILLUMINANCE "Oświetlenie" +#define D_ILLUMINANCE "Podświetlanie" #define D_IMMEDIATE "Natychmiastowy" // Button immediate #define D_INDEX "Indeks" #define D_INFO "Informacja" @@ -130,8 +130,8 @@ #define D_POWERUSAGE_REACTIVE "Moc bierna" #define D_PRESSURE "Ciśnienie" #define D_PRESSUREATSEALEVEL "Ciśnienie na poziomie morza" -#define D_PROGRAM_FLASH_SIZE "Wielkość programu flash" -#define D_PROGRAM_SIZE "Wielkość programu" +#define D_PROGRAM_FLASH_SIZE "Rozmiar programu flash" +#define D_PROGRAM_SIZE "Rozmiar programu" #define D_PROJECT "Projekt" #define D_RAIN "Deszcz" #define D_RECEIVED "Otrzymany" @@ -203,15 +203,15 @@ #define D_PATCH_ISSUE_2186 "Błąd poprawki 2186" #define D_CONNECTING_TO_AP "Łączenie z AP" #define D_IN_MODE "w trybie" -#define D_CONNECT_FAILED_NO_IP_ADDRESS "Połączenie nie powiodło się, ponieważ nie otrzymano adresu IP." -#define D_CONNECT_FAILED_AP_NOT_REACHED "Połączenie nie powiodło się, AP nie osiągalny." -#define D_CONNECT_FAILED_WRONG_PASSWORD "Połączenie nie powiodło się, nieprawidlowe hasło." -#define D_CONNECT_FAILED_AP_TIMEOUT "Nie udało się nawiązac połączenia, limit czasu przekroczony." +#define D_CONNECT_FAILED_NO_IP_ADDRESS "Połączenie nie powiodło się, ponieważ nie otrzymano adresu IP" +#define D_CONNECT_FAILED_AP_NOT_REACHED "Połączenie nie powiodło się, AP nie osiągalny" +#define D_CONNECT_FAILED_WRONG_PASSWORD "Połączenie nie powiodło się, nieprawidlowe hasło" +#define D_CONNECT_FAILED_AP_TIMEOUT "Nie udało się nawiązac połączenia, limit czasu przekroczony" #define D_ATTEMPTING_CONNECTION "Próba połączenia..." #define D_CHECKING_CONNECTION "Sprawdzanie połączenia..." -#define D_QUERY_DONE "Wykonano zapytanie. Znaleziono uslugi MQTT" +#define D_QUERY_DONE "Zapytanie wykonane" #define D_MQTT_SERVICE_FOUND "Usługa MQTT została znaleziona" -#define D_FOUND_AT "znalezione w" +#define D_FOUND_AT "znaleziono w" #define D_SYSLOG_HOST_NOT_FOUND "Syslog Host nie znaleziony" // settings.ino @@ -233,7 +233,7 @@ #define D_TRYING_TO_CONNECT "Próbuję połączyć urzadzenie z siecią" #define D_RESTART_IN "Zrestartuj" -#define D_SECONDS "sekund" +#define D_SECONDS "Sekund" #define D_DEVICE_WILL_RESTART "Urządzenie zrestartuje sie za kilka sekund" #define D_BUTTON_TOGGLE "Załącz/Wyłącz" #define D_CONFIGURATION "Konfiguracja" @@ -247,7 +247,7 @@ #define D_CONFIGURE_MQTT "Konfiguracja MQTT" #define D_CONFIGURE_DOMOTICZ "Konfiguracja Domoticza" #define D_CONFIGURE_LOGGING "Konfiguracja dziennika" -#define D_CONFIGURE_OTHER "Konfiguracja innych" +#define D_CONFIGURE_OTHER "Inne konfiguracje" #define D_CONFIRM_RESET_CONFIGURATION "Potwierdź reset ustawień" #define D_RESET_CONFIGURATION "Reset ustawień" #define D_BACKUP_CONFIGURATION "Kopia ustawień" @@ -255,7 +255,7 @@ #define D_MAIN_MENU "Menu główne" #define D_MODULE_PARAMETERS "Parametry modułu" -#define D_MODULE_TYPE "Typ modułu" +#define D_MODULE_TYPE "Typ" #define D_PULLUP_ENABLE "Przełącznik pull-up" #define D_ADC "ADC" #define D_GPIO "GPIO" @@ -263,30 +263,30 @@ #define D_SERIAL_OUT "Wyjście rs" #define D_WIFI_PARAMETERS "Parametry sieci WiFi" -#define D_SCAN_FOR_WIFI_NETWORKS "Skanuj sieci WiFi" +#define D_SCAN_FOR_WIFI_NETWORKS "Skanuj sieci" #define D_SCAN_DONE "Skanowanie wykonane" #define D_NO_NETWORKS_FOUND "Nie znaleziono sieci" -#define D_REFRESH_TO_SCAN_AGAIN "Odswież aby ponownie wyszukać sieci WiFi" -#define D_DUPLICATE_ACCESSPOINT "Powiel AP" +#define D_REFRESH_TO_SCAN_AGAIN "Odśwież aby ponownie wyszukać sieci" +#define D_DUPLICATE_ACCESSPOINT "Duplikuj" #define D_SKIPPING_LOW_QUALITY "Pominięto z powodu niskiej jakości sygnału" #define D_RSSI "RSSI" #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "Hasło AP1" -#define D_AP2_SSID "AP2 SSID" -#define D_AP2_PASSWORD "Hasło AP2" +#define D_AP1_SSID "Nazwa 1" +#define D_AP1_PASSWORD "Hasło 1" +#define D_AP2_SSID "Nazwa 2" +#define D_AP2_PASSWORD "Hasło 2" #define D_MQTT_PARAMETERS "Parametry MQTT" #define D_CLIENT "Klient" #define D_FULL_TOPIC "Pełny temat" #define D_LOGGING_PARAMETERS "Opcje dziennika" -#define D_SERIAL_LOG_LEVEL "Serial - poziom dziennika" -#define D_MQTT_LOG_LEVEL "Mqtt - poziom dziennika" -#define D_WEB_LOG_LEVEL "Web - poziom dziennika" -#define D_SYS_LOG_LEVEL "System - poziom dziennika" +#define D_SERIAL_LOG_LEVEL "Serial - poziom" +#define D_MQTT_LOG_LEVEL "Mqtt - poziom" +#define D_WEB_LOG_LEVEL "Web - poziom" +#define D_SYS_LOG_LEVEL "System - poziom" #define D_MORE_DEBUG "Więcej informacji dziennika" #define D_SYSLOG_HOST "Syslog host" #define D_SYSLOG_PORT "Syslog port" @@ -296,8 +296,8 @@ #define D_TEMPLATE "Szablon" #define D_ACTIVATE "Aktywuj" #define D_WEB_ADMIN_PASSWORD "Hasło administratora" -#define D_MQTT_ENABLE "MQTT aktywne" -#define D_FRIENDLY_NAME "Twoja nazwa" +#define D_MQTT_ENABLE "Załącz MQTT" +#define D_FRIENDLY_NAME "Nazwa" #define D_BELKIN_WEMO "Belkin WeMo" #define D_HUE_BRIDGE "Mostek Hue" #define D_SINGLE_DEVICE "pojedyńcze urządzenie" @@ -313,28 +313,28 @@ #define D_CONFIGURATION_SAVED "Ustawienia zapisane" #define D_CONFIGURATION_RESET "Ustawienia zresetowane" -#define D_PROGRAM_VERSION "Wersja programu" -#define D_BUILD_DATE_AND_TIME "Dzień i godzina kompilacji" +#define D_PROGRAM_VERSION "Wersja oprogramowania" +#define D_BUILD_DATE_AND_TIME "Data kompilacji" #define D_CORE_AND_SDK_VERSION "Wersja Core/SDK" #define D_FLASH_WRITE_COUNT "Liczba zapisów do pamięci" #define D_MAC_ADDRESS "Adres MAC" -#define D_MQTT_HOST "Host MQTT" -#define D_MQTT_PORT "Port MQTT" -#define D_MQTT_CLIENT "Klient MQTT" -#define D_MQTT_USER "Użytkownik MQTT" -#define D_MQTT_TOPIC "Temat MQTT" -#define D_MQTT_GROUP_TOPIC "Temat grupy MQTT" -#define D_MQTT_FULL_TOPIC "Pełen temat MQTT" +#define D_MQTT_HOST "Host" +#define D_MQTT_PORT "Port" +#define D_MQTT_CLIENT "Klient" +#define D_MQTT_USER "Użytkownik" +#define D_MQTT_TOPIC "Temat" +#define D_MQTT_GROUP_TOPIC "Temat grupy" +#define D_MQTT_FULL_TOPIC "Pełny temat" #define D_MDNS_DISCOVERY "Wykrywanie mDNS" #define D_MDNS_ADVERTISE "Rozgłaszanie mDNS" #define D_ESP_CHIP_ID "ID ukladu ESP" -#define D_FLASH_CHIP_ID "ID układu pamięci flash" +#define D_FLASH_CHIP_ID "ID pamięci flash" #define D_FLASH_CHIP_SIZE "Rozmiar pamięci flash" #define D_FREE_PROGRAM_SPACE "Wolna pamięć programu" #define D_UPGRADE_BY_WEBSERVER "Aktualizacja z serwera Web" -#define D_OTA_URL "URL serwera" -#define D_START_UPGRADE "Start aktualizacji" +#define D_OTA_URL "Adres serwera" +#define D_START_UPGRADE "Aktualizuj" #define D_UPGRADE_BY_FILE_UPLOAD "Aktualizacja z pliku" #define D_UPLOAD_STARTED "Wgrywanie rozpoczęte" #define D_UPGRADE_STARTED "Aktualizacja rozpoczęta" @@ -373,23 +373,23 @@ #define D_FAILED_TO_SEND_RESPONSE "Nie udało się wysłać odpowiedzi" #define D_WEMO "WeMo" -#define D_WEMO_BASIC_EVENT "Zdarzenie WeNo" -#define D_WEMO_EVENT_SERVICE "Zdarzenie serwisowe WeMo" -#define D_WEMO_META_SERVICE "Meta dane serwisowe WeMo" +#define D_WEMO_BASIC_EVENT "Zdarzenie podstawowe" +#define D_WEMO_EVENT_SERVICE "Zdarzenie serwisowe" +#define D_WEMO_META_SERVICE "Meta dane serwisowe" #define D_WEMO_SETUP "Ustawienia WeMo" -#define D_RESPONSE_SENT "Odpowiedź wysłana" +#define D_RESPONSE_SENT "Wyślij odpowiedź" #define D_HUE "Hue" #define D_HUE_BRIDGE_SETUP "Ustawienia Hue" -#define D_HUE_API_NOT_IMPLEMENTED "Api Hue nie zaimplementowane" -#define D_HUE_API "API Hue" -#define D_HUE_POST_ARGS "POST argument Hue" +#define D_HUE_API_NOT_IMPLEMENTED "Api nie zaimplementowane" +#define D_HUE_API "API" +#define D_HUE_POST_ARGS "POST argument" #define D_3_RESPONSE_PACKETS_SENT "3 pakiety odpowiedzi wysyłane" // xdrv_07_domoticz.ino #define D_DOMOTICZ_PARAMETERS "Parametry Domoticz" #define D_DOMOTICZ_IDX "Idx" -#define D_DOMOTICZ_KEY_IDX "Key idx" +#define D_DOMOTICZ_KEY_IDX "Klucz Idx" #define D_DOMOTICZ_SWITCH_IDX "Przełącznik Idx" #define D_DOMOTICZ_SENSOR_IDX "Sensor Idx" #define D_DOMOTICZ_TEMP "Temperatura" @@ -402,13 +402,13 @@ #define D_DOMOTICZ_CURRENT "Prąd" #define D_DOMOTICZ_AIRQUALITY "Jakość powietrza" #define D_DOMOTICZ_P1_SMART_METER "Miernik P1" -#define D_DOMOTICZ_UPDATE_TIMER "Zaktualizuj czasomierz" +#define D_DOMOTICZ_UPDATE_TIMER "Aktualizacja zegara" // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Konfiguracja harmonogramu" #define D_TIMER_PARAMETERS "Parametry harmonogramu" -#define D_TIMER_ENABLE "Włącz harmonogram" -#define D_TIMER_ARM "Włącz" +#define D_TIMER_ENABLE "Załącz harmonogram" +#define D_TIMER_ARM "Załącz" #define D_TIMER_TIME "Czas" #define D_TIMER_DAYS "Dni" #define D_TIMER_REPEAT "Powtarzaj" @@ -421,7 +421,7 @@ #define D_KNX_GENERAL_CONFIG "Konfiguracja ogólna" #define D_KNX_PHYSICAL_ADDRESS "Adres fizyczny" #define D_KNX_PHYSICAL_ADDRESS_NOTE "(Musi być unikalny w sieci KNX)" -#define D_KNX_ENABLE "Włącz KNX" +#define D_KNX_ENABLE "Załącz" #define D_KNX_GROUP_ADDRESS_TO_WRITE "Adresy grupowe do zapisu" #define D_ADD "Dodaj" #define D_DELETE "Usuń" @@ -431,11 +431,11 @@ #define D_KNX_COMMAND_WRITE "Zapisz" #define D_KNX_COMMAND_READ "Czytaj" #define D_KNX_COMMAND_OTHER "Inna komenda" -#define D_SENT_TO "Wysłane do" +#define D_SENT_TO "Wyślij do" #define D_KNX_WARNING "Adres grupy (0/0/0) jest zarezerwowany i nie można go użyć." -#define D_KNX_ENHANCEMENT "Rozszerzenia KNX" -#define D_KNX_TX_SLOT "KNX TX" -#define D_KNX_RX_SLOT "KNX RX" +#define D_KNX_ENHANCEMENT "Rozszerzenia" +#define D_KNX_TX_SLOT "Gniazdo TX" +#define D_KNX_RX_SLOT "Gniazdo RX" // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energia dzisiaj" @@ -450,20 +450,20 @@ // xdrv_28_pcf8574.ino #define D_CONFIGURE_PCF8574 "Konfiguracja PCF8574" #define D_PCF8574_PARAMETERS "Parametry PCF8574" -#define D_INVERT_PORTS "Odwrócone porty" +#define D_INVERT_PORTS "Porty odwrócone" #define D_DEVICE "Urządzenie" #define D_DEVICE_INPUT "Wejście" #define D_DEVICE_OUTPUT "Wyjście" // xsns_05_ds18b20.ino -#define D_SENSOR_BUSY "Czujnik DS18x20 zajęty" -#define D_SENSOR_CRC_ERROR "Czujnik DS18x20 błąd CRC" -#define D_SENSORS_FOUND "Znaleziono czujnik DS18x20" +#define D_SENSOR_BUSY "Czujnik zajęty" +#define D_SENSOR_CRC_ERROR "Błąd CRC czujnika" +#define D_SENSORS_FOUND "Znaleziono czujnik" // xsns_06_dht.ino #define D_TIMEOUT_WAITING_FOR "Trwa oczekiwanie" -#define D_START_SIGNAL_LOW "sygnał startowy niski" -#define D_START_SIGNAL_HIGH "sygnał startowy wysoki" +#define D_START_SIGNAL_LOW "Sygnał startowy niski" +#define D_START_SIGNAL_HIGH "Sygnał startowy wysoki" #define D_PULSE "Impuls" #define D_CHECKSUM_FAILURE "Błędna suma kontrolna" @@ -498,10 +498,10 @@ #define D_CALIBRATION "Kalibrowanie" //xsns_35_tx20.ino -#define D_TX20_WIND_DIRECTION "Kierunek wiatru" -#define D_TX20_WIND_SPEED "Prędkość wiatru" -#define D_TX20_WIND_SPEED_AVG "Średnia prędkość wiatru" -#define D_TX20_WIND_SPEED_MAX "Maksymalna prędkość wiatru" +#define D_TX20_WIND_DIRECTION "Kierunek" +#define D_TX20_WIND_SPEED "Prędkość" +#define D_TX20_WIND_SPEED_AVG "Średnia prędkość" +#define D_TX20_WIND_SPEED_MAX "Maksymalna prędkość" #define D_TX20_NORTH "N" #define D_TX20_EAST "E" #define D_TX20_SOUTH "S" @@ -523,7 +523,7 @@ #define D_SENSOR_BUTTON "Przycisk" // Suffix "1" #define D_SENSOR_RELAY "Przekaźnik" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" -#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" +#define D_SENSOR_LED_LINK "Led link" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Licznik" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -540,7 +540,7 @@ #define D_SENSOR_SPI_MISO "SPI MISO" #define D_SENSOR_SPI_MOSI "SPI MOSI" #define D_SENSOR_SPI_CLK "SPI CLK" -#define D_SENSOR_BACKLIGHT "Backlight" +#define D_SENSOR_BACKLIGHT "Podświetlanie" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" @@ -669,7 +669,7 @@ #define D_EXPORT_ACTIVE "Czynna oddana" #define D_IMPORT_REACTIVE "Bierna pobrana" #define D_EXPORT_REACTIVE "Bierna oddana" -#define D_TOTAL_REACTIVE "Całkowita bierna" +#define D_TOTAL_REACTIVE "Bierna całkowita" #define D_UNIT_KWARH "kVArh" #define D_UNIT_ANGLE "Deg" diff --git a/tasmota/support_rtc.ino b/tasmota/support_rtc.ino index 1ef84c027..ffb7239a6 100644 --- a/tasmota/support_rtc.ino +++ b/tasmota/support_rtc.ino @@ -373,10 +373,13 @@ void RtcSecond(void) { TIME_T tmpTime; - if (!Rtc.user_time_entry) { - if ((Rtc.ntp_sync_minute > 59) && (RtcTime.minute > 2)) Rtc.ntp_sync_minute = 1; // If sync prepare for a new cycle + if (!Rtc.user_time_entry && !global_state.wifi_down) { + uint8_t uptime_minute = (uptime / 60) % 60; // 0 .. 59 + if ((Rtc.ntp_sync_minute > 59) && (uptime_minute > 2)) { + Rtc.ntp_sync_minute = 1; // If sync prepare for a new cycle + } uint8_t offset = (uptime < 30) ? RtcTime.second : (((ESP.getChipId() & 0xF) * 3) + 3) ; // First try ASAP to sync. If fails try once every 60 seconds based on chip id - if (!global_state.wifi_down && (((offset == RtcTime.second) && ((RtcTime.year < 2016) || (Rtc.ntp_sync_minute == RtcTime.minute))) || ntp_force_sync)) { + 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) { // Fix NTP bug in core 2.4.1/SDK 2.2.1 (returns Thu Jan 01 08:00:10 1970 after power on) ntp_force_sync = false; @@ -405,7 +408,8 @@ void RtcSecond(void) } } } - Rtc.utc_time++; + + Rtc.utc_time++; // Increment every second Rtc.local_time = Rtc.utc_time; if (Rtc.local_time > START_VALID_TIME) { // 2016-01-01 int16_t timezone_minutes = Settings.timezone_minutes; @@ -434,8 +438,8 @@ void RtcSecond(void) Rtc.time_timezone /= 60; if (!Settings.energy_kWhtotal_time) { Settings.energy_kWhtotal_time = Rtc.local_time; } } - BreakTime(Rtc.local_time, RtcTime); + BreakTime(Rtc.local_time, RtcTime); if (RtcTime.valid) { if (!Rtc.midnight) { Rtc.midnight = Rtc.local_time - (RtcTime.hour * 3600) - (RtcTime.minute * 60) - RtcTime.second; diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 26d618326..2377bbd0d 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -163,6 +163,10 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "la('&'+v+i+'='+p);" "}" #endif // USE_JAVASCRIPT_ES6 + "function ld(v,p){" + "eb('s').style.backgroundImage='linear-gradient(to right,grey,hsl('+p+',100%%,50%%))';" + "la('&'+v+'='+p);" + "}" "wl(la);"; @@ -354,7 +358,8 @@ const char HTTP_HEAD_STYLE2[] PROGMEM = ".bgrn:hover{background:#%06x;}" // COLOR_BUTTON_SAVE_HOVER "a{color:#%06x;text-decoration:none;}" // COLOR_BUTTON ".p{float:left;text-align:left;}" - ".q{float:right;text-align:right;}"; + ".q{float:right;text-align:right;}" + ".r{border-radius:0.3em;padding:2px;margin:6px 2px;}"; const char HTTP_HEAD_STYLE3[] PROGMEM = "" @@ -372,12 +377,17 @@ const char HTTP_HEAD_STYLE3[] PROGMEM = #endif "

%s

"; -const char HTTP_MSG_SLIDER1[] PROGMEM = - "
%s%s
" - "
"; -const char HTTP_MSG_SLIDER2[] PROGMEM = - "
%s%s
" - "
"; +const char HTTP_MSG_SLIDER_GRADIENT[] PROGMEM = + "
"; +const char HTTP_MSG_SLIDER_HUE[] PROGMEM = + "
" + "
"; +const char HTTP_MSG_SLIDER_CHANNEL[] PROGMEM = + "
"; +const char HTTP_MSG_SLIDER_SHUTTER[] PROGMEM = + "
" D_CLOSE "" D_OPEN "
" + "
"; + const char HTTP_MSG_RSTRT[] PROGMEM = "
" D_DEVICE_WILL_RESTART "

"; @@ -510,6 +520,7 @@ const char kUploadErrors[] PROGMEM = "|" D_UPLOAD_ERR_10 "|" D_UPLOAD_ERR_11 "|" D_UPLOAD_ERR_12 "|" D_UPLOAD_ERR_13 #endif ; +const char kChannelColors[] PROGMEM = "#f00|#0f0|#00f|#fff|#ff0"; // Red, Green, Blue, ColdWhite, WarmWhite const uint16_t DNS_PORT = 53; enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY}; @@ -951,6 +962,8 @@ void HandleWifiLogin(void) WSContentStop(); } + + void HandleRoot(void) { if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the page. @@ -982,7 +995,7 @@ void HandleRoot(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_MAIN_MENU); - char stemp[5]; + char stemp[10]; WSContentStart_P(S_MAIN_MENU); #ifdef USE_SCRIPT_WEB_DISPLAY @@ -996,31 +1009,38 @@ void HandleRoot(void) if (devices_present) { #ifdef USE_LIGHT if (light_type) { + uint8_t light_subtype = light_type &7; if (!Settings.flag3.pwm_multi_channels) { // SetOption68 0 - Enable multi-channels PWM instead of Color PWM - if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { + if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) { // Cold - Warm &t related to lb("t", value) and WebGetArg("t", tmp, sizeof(tmp)); - WSContentSend_P(HTTP_MSG_SLIDER1, F(D_COLDLIGHT), F(D_WARMLIGHT), - 153, 500, LightGetColorTemp(), 't'); + WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, "a", "#fff", "#ff0", 153, 500, LightGetColorTemp(), 't'); // White to Yellow + } + if (light_subtype > 2) { + uint16_t hue; + uint8_t sat; + uint8_t bri; + LightGetHSB(&hue, &sat, &bri); + WSContentSend_P(HTTP_MSG_SLIDER_HUE, hue); // Hue + snprintf_P(stemp, sizeof(stemp), PSTR("#%02X%02X%02X"), Settings.light_color[0], Settings.light_color[1], Settings.light_color[2]); + // Saturation "s" related to eb('s').style.backgroundImage='linear-gradient(to right,grey,hsl('+p+',100%%,50%%))'; + WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, "s", "grey", stemp, 1, 100, changeUIntScale(sat, 0, 255, 0, 100), 'n'); } // Dark - Bright &d related to lb("d", value) and WebGetArg("d", tmp, sizeof(tmp)); - WSContentSend_P(HTTP_MSG_SLIDER1, F(D_DARKLIGHT), F(D_BRIGHTLIGHT), - 1, 100, Settings.light_dimmer, 'd'); + WSContentSend_P(HTTP_MSG_SLIDER_GRADIENT, "b", "#000", "#fff", 1, 100, Settings.light_dimmer, 'd'); // Black to White } else { // Settings.flag3.pwm_multi_channels - SetOption68 1 - Enable multi-channels PWM instead of Color PWM - uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7); + uint32_t pwm_channels = light_subtype > LST_MAX ? LST_MAX : light_subtype; for (uint32_t i = 0; i < pwm_channels; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("c%d"), i); - WSContentSend_P(HTTP_MSG_SLIDER2, stemp, FPSTR("100%"), - 1, 100, - changeUIntScale(Settings.light_color[i], 0, 255, 0, 100), 'd', i+1); + uint8_t index = (pwm_channels < 3) ? i +3 : i; + WSContentSend_P(HTTP_MSG_SLIDER_CHANNEL, GetTextIndexed(stemp, sizeof(stemp), index, kChannelColors), + changeUIntScale(Settings.light_color[i], 0, 255, 0, 100), i+1); // Dark to Light } } // Settings.flag3.pwm_multi_channels } -#endif +#endif // USE_LIGHT #ifdef USE_SHUTTER if (Settings.flag3.shutter_mode) { // SetOption80 - Enable shutter support for (uint32_t i = 0; i < shutters_present; i++) { - WSContentSend_P(HTTP_MSG_SLIDER2, F(D_CLOSE), F(D_OPEN), - 0, 100, Settings.shutter_position[i], 'u', i+1); + WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, Settings.shutter_position[i], i+1); } } #endif // USE_SHUTTER @@ -1136,6 +1156,16 @@ bool HandleRootStatusRefresh(void) snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp); ExecuteWebCommand(svalue, SRC_WEBGUI); } + WebGetArg("u", tmp, sizeof(tmp)); // 0 - 359 Hue value + if (strlen(tmp)) { + snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_HSBCOLOR "1 %s"), tmp); + ExecuteWebCommand(svalue, SRC_WEBGUI); + } + WebGetArg("n", tmp, sizeof(tmp)); // 0 - 99 Saturation value + if (strlen(tmp)) { + snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_HSBCOLOR "2 %s"), tmp); + ExecuteWebCommand(svalue, SRC_WEBGUI); + } #ifdef USE_SHUTTER for (uint32_t j = 1; j <= shutters_present; j++) { snprintf_P(webindex, sizeof(webindex), PSTR("u%d"), j); diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index b45be6523..a51c98619 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1241,6 +1241,10 @@ void LightSetDimmer(uint8_t dimmer) { light_controller.changeDimmer(dimmer); } +uint32_t LightGetHSB(uint16_t *hue,uint8_t *sat, uint8_t *bri) { + light_state.getHSB(hue, sat, bri); +} + // If SetOption68 is set, get the brightness for a specific device uint8_t LightGetBri(uint8_t device) { uint8_t bri = 254; // default value if relay diff --git a/tools/decode-config.py b/tools/decode-config.py index 3288e550d..f15c696ae 100755 --- a/tools/decode-config.py +++ b/tools/decode-config.py @@ -1,7 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function -VER = '2.4.0037' +from past.builtins import long +VER = '2.4.0039' """ decode-config.py - Backup/Restore Tasmota configuration data @@ -23,8 +24,8 @@ VER = '2.4.0037' Requirements: - - Python - - pip install json pycurl urllib2 configargparse + - Python 2.x: + pip install json requests urllib2 configargparse Instructions: @@ -198,7 +199,7 @@ try: import inspect import json import configargparse - import pycurl + import requests if sys.version_info.major==2: import urllib2 else: @@ -1246,6 +1247,38 @@ def exit(status=0, msg="end", type_=LogType.ERROR, src=None, doexit=True, line=N sys.exit(exitcode) +def debug(args): + """ + Get debug level + + @param args: + configargparse.parse_args() result + + @return: + debug level + """ + return 0 if args.debug is None else args.debug + + +def instance(type_): + """ + Creates Python2/3 compatible isinstance test type(s) + + @param args: + Python3 instance type + + @return: + Python2/3 compatible isinstance type(s) + """ + newtype = type_ + if sys.version_info.major==2: + if type_==str: + newtype = (str,unicode) + elif isinstance(type_, tuple) and str in type_: + newtype = newtype + (unicode,) + return newtype + + def ShortHelp(doexit=True): """ Show short help (usage) only - ued by own -h handling @@ -1262,36 +1295,6 @@ def ShortHelp(doexit=True): sys.exit(ExitCode.OK) -class HTTPHeader: - """ - pycurl helper class retrieving the request header - """ - def __init__(self): - self.contents = '' - - def clear(self): - self.contents = '' - - def store(self, _buffer): - self.contents = "{}{}".format(self.contents, _buffer) - - def response(self): - header = str(self.contents).split('\n') - if len(header) > 0: - return header[0].rstrip() - return '' - - def contenttype(self): - for item in str(self.contents).split('\n'): - ditem = item.split(":") - if ditem[0].strip().lower() == 'content-type' and len(ditem) > 1: - return ditem[1].strip() - return '' - - def __str__(self): - return self.contents - - class CustomHelpFormatter(configargparse.HelpFormatter): """ Class for customizing the help output @@ -1337,9 +1340,6 @@ def GetTemplateSizes(): """ Get all possible template sizes as list - @param version: - version number from read binary data to search for - @return: template sizes as list [] """ @@ -1472,7 +1472,7 @@ def GetVersionStr(version): @return: version string """ - if isinstance(version, (unicode,str)): + if isinstance(version, instance(str)): version = int(version, 0) major = ((version>>24) & 0xff) minor = ((version>>16) & 0xff) @@ -1629,43 +1629,21 @@ def TasmotaGet(cmnd, host, port, username=DEFAULTS['source']['username'], passwo @return: binary config data (encrypted) or None on error """ - body = None # read config direct from device via http - c = pycurl.Curl() - buffer = io.BytesIO() - c.setopt(c.WRITEDATA, buffer) - header = HTTPHeader() - c.setopt(c.HEADERFUNCTION, header.store) - c.setopt(c.FOLLOWLOCATION, True) - c.setopt(c.URL, MakeUrl(host, port, cmnd)) + url = MakeUrl(host, port, cmnd) + auth = None if username is not None and password is not None: - c.setopt(c.HTTPAUTH, c.HTTPAUTH_BASIC) - c.setopt(c.USERPWD, username + ':' + password) - c.setopt(c.HTTPGET, True) - c.setopt(c.VERBOSE, False) + auth = (username, password) + res = requests.get(url, auth=auth) - responsecode = 200 - try: - c.perform() - responsecode = c.getinfo(c.RESPONSE_CODE) - response = header.response() - except Exception as e: - exit(e.args[0], e.args[1], line=inspect.getlineno(inspect.currentframe())) - finally: - c.close() + if not res.ok: + exit(res.status_code, "Error on http GET request for {} - {}".format(url,res.reason), line=inspect.getlineno(inspect.currentframe())) - if responsecode >= 400: - exit(responsecode, 'HTTP result: {}'.format(header.response()),line=inspect.getlineno(inspect.currentframe())) - elif contenttype is not None and header.contenttype()!=contenttype: + if contenttype is not None and res.headers['Content-Type']!=contenttype: exit(ExitCode.DOWNLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)",line=inspect.getlineno(inspect.currentframe())) - try: - body = buffer.getvalue() - except: - pass - - return responsecode, body + return res.status_code, res.content def GetTasmotaHostname(host, port, username=DEFAULTS['source']['username'], password=None): @@ -1741,7 +1719,7 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern errorcode, errorstring errorcode=0 if success, otherwise http response or exception code """ - if isinstance(encode_cfg, bytearray): + if isinstance(encode_cfg, (bytes,bytearray)): encode_cfg = str(encode_cfg) # get restore config page first to set internal Tasmota vars @@ -1749,48 +1727,21 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern if body is None: return responsecode, "ERROR" - # post data - c = pycurl.Curl() - header = HTTPHeader() - buffer_ = io.BytesIO() - c.setopt(c.HEADERFUNCTION, header.store) - c.setopt(c.WRITEFUNCTION, lambda x: None) - c.setopt(c.WRITEDATA, buffer_) - c.setopt(c.POST, 1) - c.setopt(c.URL, MakeUrl(host, port, 'u2')) + # ~ # post data + url = MakeUrl(host, port, "u2") + auth = None if username is not None and password is not None: - c.setopt(c.HTTPAUTH, c.HTTPAUTH_BASIC) - c.setopt(c.USERPWD, username + ':' + password) - try: - isfile = os.path.isfile(encode_cfg) - except: - isfile = False - if isfile: - c.setopt(c.HTTPPOST, [("file", (c.FORM_FILE, encode_cfg))]) - else: - # use as binary data - c.setopt(c.HTTPPOST, [ - ('fileupload', ( - c.FORM_BUFFER, '{sprog}_v{sver}.dmp'.format(sprog=os.path.basename(sys.argv[0]), sver=VER), - c.FORM_BUFFERPTR, encode_cfg - )), - ]) + auth = (username, password) + files = {'u2':('{sprog}_v{sver}.dmp'.format(sprog=os.path.basename(sys.argv[0]), sver=VER), encode_cfg)} + res = requests.post(url, auth=auth, files=files) - responsecode = 200 - try: - c.perform() - responsecode = c.getinfo(c.RESPONSE_CODE) - except Exception as e: - return e.args[0], e.args[1] + if not res.ok: + exit(res.status_code, "Error on http POST request for {} - {}".format(url,res.reason), line=inspect.getlineno(inspect.currentframe())) - c.close() + if res.headers['Content-Type']!='text/html': + exit(ExitCode.DOWNLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)",line=inspect.getlineno(inspect.currentframe())) - if responsecode >= 400: - return responsecode, header.response() - elif header.contenttype() != 'text/html': - return ExitCode.UPLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)" - - body = buffer_.getvalue() + body = res.content findUpload = body.find("Upload") if findUpload < 0: @@ -1818,7 +1769,7 @@ def DecryptEncrypt(obj): @return: decrypted configuration (if obj contains encrypted data) """ - if isinstance(obj, bytearray): + if isinstance(obj, (bytes,bytearray)): obj = str(obj) dobj = obj[0:2] for i in range(2, len(obj)): @@ -1837,7 +1788,7 @@ def GetSettingsCrc(dobj): 2 byte unsigned integer crc value """ - if isinstance(dobj, bytearray): + if isinstance(dobj, (bytes,bytearray)): dobj = str(dobj) version, size, setting = GetTemplateSetting(dobj) if version < 0x06060007 or version > 0x0606000A: @@ -1862,7 +1813,7 @@ def GetSettingsCrc32(dobj): 4 byte unsigned integer crc value """ - if isinstance(dobj, bytearray): + if isinstance(dobj, (bytes,bytearray)): dobj = str(dobj) crc = 0 for i in range(0, len(dobj)-4): @@ -1907,35 +1858,35 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da raise SyntaxError(' error') # ignore calls with 'root' setting - if isinstance(format_, dict) and baseaddr is None and datadef is None: + if isinstance(format_, instance(dict)) and baseaddr is None and datadef is None: return eval(fields) - if not isinstance(format_, (unicode,str,dict)): + if not isinstance(format_, instance((str,dict))): print('wrong {} type {} in {}'.format(format_, type(format_), fielddef), file=sys.stderr) raise SyntaxError(' error') # extract addrdef items baseaddr = addrdef - if isinstance(baseaddr, (list,tuple)): + if isinstance(baseaddr, instance((list,tuple))): if len(baseaddr) == 3: # baseaddr bit definition baseaddr, bits, bitshift = baseaddr - if not isinstance(bits, int): + if not isinstance(bits, instance(int)): print(' must be defined as integer in {}'.format(bits, fielddef), file=sys.stderr) raise SyntaxError(' error') - if not isinstance(bitshift, int): + if not isinstance(bitshift, instance(int)): print(' must be defined as integer in {}'.format(bitshift, fielddef), file=sys.stderr) raise SyntaxError(' error') else: print('wrong {} length ({}) in {}'.format(addrdef, len(addrdef), fielddef), file=sys.stderr) raise SyntaxError(' error') - if not isinstance(baseaddr, int): + if not isinstance(baseaddr, instance(int)): print(' must be defined as integer in {}'.format(baseaddr, fielddef), file=sys.stderr) raise SyntaxError(' error') # extract datadef items arraydef = datadef - if isinstance(datadef, (tuple)): + if isinstance(datadef, instance((tuple))): if len(datadef) == 2: # datadef has a validator arraydef, validate = datadef @@ -1943,19 +1894,19 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da # datadef has a validator and cmd set arraydef, validate, cmd = datadef # cmd must be a tuple with 2 objects - if isinstance(cmd, (tuple)) and len(cmd) == 2: + if isinstance(cmd, instance((tuple))) and len(cmd) == 2: group, tasmotacmnd = cmd - if group is not None and not isinstance(group, (str, unicode)): + if group is not None and not isinstance(group, instance(str)): print('wrong {} in {}'.format(group, fielddef), file=sys.stderr) raise SyntaxError(' error') - if tasmotacmnd is isinstance(tasmotacmnd, tuple): + if tasmotacmnd is isinstance(tasmotacmnd, instance(tuple)): tasmotacmnds = tasmotacmnd for tasmotacmnd in tasmotacmnds: - if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, (str, unicode)): + if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, instance(str)): print('wrong {} in {}'.format(tasmotacmnd, fielddef), file=sys.stderr) raise SyntaxError(' error') else: - if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, (str, unicode)): + if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, instance(str)): print('wrong {} in {}'.format(tasmotacmnd, fielddef), file=sys.stderr) raise SyntaxError(' error') else: @@ -1965,28 +1916,28 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da print('wrong {} length ({}) in {}'.format(datadef, len(datadef), fielddef), file=sys.stderr) raise SyntaxError(' error') - if validate is not None and (not isinstance(validate, (unicode,str)) and not callable(validate)): + if validate is not None and (not isinstance(validate, instance(str)) and not callable(validate)): print('wrong {} type {} in {}'.format(validate, type(validate), fielddef), file=sys.stderr) raise SyntaxError(' error') # convert single int into one-dimensional list - if isinstance(arraydef, int): + if isinstance(arraydef, instance(int)): arraydef = [arraydef] - if arraydef is not None and not isinstance(arraydef, (list)): + if arraydef is not None and not isinstance(arraydef, instance((list))): print('wrong {} type {} in {}'.format(arraydef, type(arraydef), fielddef), file=sys.stderr) raise SyntaxError(' error') # get read/write converter items readconverter = converter - if isinstance(converter, (tuple)): + if isinstance(converter, instance((tuple))): if len(converter) == 2: # converter has read/write converter readconverter, writeconverter = converter - if readconverter is not None and not isinstance(readconverter, (str,unicode)) and not callable(readconverter): + if readconverter is not None and not isinstance(readconverter, instance(str)) and not callable(readconverter): print('wrong {} type {} in {}'.format(readconverter, type(readconverter), fielddef), file=sys.stderr) raise SyntaxError(' error') - if writeconverter is not None and (not isinstance(writeconverter, (bool,str,unicode)) and not callable(writeconverter)): + if writeconverter is not None and (not isinstance(writeconverter, instance((bool,str))) and not callable(writeconverter)): print('wrong {} type {} in {}'.format(writeconverter, type(writeconverter), fielddef), file=sys.stderr) raise SyntaxError(' error') else: @@ -2024,7 +1975,7 @@ def ReadWriteConverter(value, fielddef, read=True, raw=False): if not raw and converter is not None: conv = readconverter if read else writeconverter try: - if isinstance(conv, str): # evaluate strings + if isinstance(conv, instance(str)): # evaluate strings return eval(conv.replace('$','value')) elif callable(conv): # use as format function return conv(value) @@ -2061,7 +2012,7 @@ def CmndConverter(valuemapping, value, idx, fielddef): if tasmotacmnd is not None and (callable(tasmotacmnd) or len(tasmotacmnd) > 0): if idx is not None: idx += 1 - if isinstance(tasmotacmnd, str): # evaluate strings + if isinstance(tasmotacmnd, instance(str)): # evaluate strings if idx is not None: evalstr = tasmotacmnd.replace('$','value').replace('#','idx').replace('@','valuemapping') else: @@ -2100,7 +2051,7 @@ def ValidateValue(value, fielddef): valid = True try: - if isinstance(validate, str): # evaluate strings + if isinstance(validate, instance(str)): # evaluate strings valid = eval(validate.replace('$','value')) elif callable(validate): # use as format function valid = validate(value) @@ -2121,7 +2072,7 @@ def GetFormatCount(format_): prefix count or 1 if not specified """ - if isinstance(format_, str): + if isinstance(format_, instance(str)): match = re.search("\s*(\d+)", format_) if match: return int(match.group(0)) @@ -2142,7 +2093,7 @@ def GetFormatType(format_): formattype = format_ bitsize = 0 - if isinstance(format_, str): + if isinstance(format_, instance(str)): match = re.search("\s*(\D+)", format_) if match: formattype = match.group(0) @@ -2204,7 +2155,7 @@ def GetFieldLength(fielddef): format_, addrdef, arraydef = GetFieldDef(fielddef, fields='format_, addrdef, arraydef') # contains a integer list - if isinstance(arraydef, list) and len(arraydef) > 0: + if isinstance(arraydef, instance(list)) and len(arraydef) > 0: # arraydef contains a list # calc size recursive by sum of all elements for i in range(0, arraydef[0]): @@ -2215,7 +2166,7 @@ def GetFieldLength(fielddef): else: length += GetFieldLength( (format_, addrdef, None) ) - elif isinstance(format_, dict): + elif isinstance(format_, instance(dict)): # -> iterate through format addr = None setting = format_ @@ -2227,7 +2178,7 @@ def GetFieldLength(fielddef): length += _len # a simple value - elif isinstance(format_, str): + elif isinstance(format_, instance(str)): length = struct.calcsize(format_) return length @@ -2253,7 +2204,7 @@ def GetSubfieldDef(fielddef): arraydef = None # create new datadef - if isinstance(datadef, tuple): + if isinstance(datadef, instance(tuple)): if cmd is not None: datadef = (arraydef, validate, cmd) else: @@ -2346,7 +2297,7 @@ def SetFieldValue(fielddef, dobj, addr, value): format_, bits, bitshift = GetFieldDef(fielddef, fields='format_, bits, bitshift') formatcnt = GetFormatCount(format_) singletype, bitsize = GetFormatType(format_) - if args.debug >= 2: + if debug(args) >= 2: print("SetFieldValue(): fielddef {}, addr 0x{:04x} value {} formatcnt {} singletype {} bitsize {} ".format(fielddef,addr,value,formatcnt,singletype,bitsize), file=sys.stderr) if not format_[-1:].lower() in ['s','p']: addr += (bitsize / 8) * formatcnt @@ -2355,9 +2306,9 @@ def SetFieldValue(fielddef, dobj, addr, value): maxunsigned = ((2**bitsize) - 1) maxsigned = ((2**bitsize)>>1)-1 val = value & maxunsigned - if isinstance(value,int) and value < 0 and val > maxsigned: + if isinstance(value,instance(int)) and value < 0 and val > maxsigned: val = ((maxunsigned+1)-val) * (-1) - if args.debug >= 3: + if debug(args) >= 3: print("SetFieldValue(): Single type - fielddef {}, addr 0x{:04x} value {} singletype {} bitsize {}".format(fielddef,addr,val,singletype,bitsize), file=sys.stderr) try: struct.pack_into(singletype, dobj, addr, val) @@ -2369,7 +2320,7 @@ def SetFieldValue(fielddef, dobj, addr, value): line=inspect.getlineno(inspect.currentframe())) value >>= bitsize else: - if args.debug >= 3: + if debug(args) >= 3: print("SetFieldValue(): String type - fielddef {}, addr 0x{:04x} value {} format_ {}".format(fielddef,addr,value,format_), file=sys.stderr) try: struct.pack_into(format_, dobj, addr, value) @@ -2402,7 +2353,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): field mapping """ - if isinstance(dobj, bytearray): + if isinstance(dobj, instance((bytes,bytearray))): dobj = str(dobj) valuemapping = None @@ -2415,7 +2366,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): return valuemapping # contains a integer list - if isinstance(arraydef, list) and len(arraydef) > 0: + if isinstance(arraydef, instance(list)) and len(arraydef) > 0: valuemapping = [] offset = 0 for i in range(0, arraydef[0]): @@ -2427,7 +2378,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): offset += length # contains a dict - elif isinstance(format_, dict): + elif isinstance(format_, instance(dict)): mapping_value = {} # -> iterate through format for name in format_: @@ -2439,7 +2390,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): valuemapping = copy.deepcopy(mapping_value) # a simple value - elif isinstance(format_, (str, bool, int, float, long)): + elif isinstance(format_, instance((str, bool, int, float, long))): if GetFieldLength(fielddef) != 0: valuemapping = ReadWriteConverter(GetFieldValue(fielddef, dobj, baseaddr+addroffset), fielddef, read=True, raw=raw) @@ -2479,12 +2430,12 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""): # do not write readonly values if writeconverter is False: - if args.debug >= 2: + if debug(args) >= 2: print("SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr) return dobj # contains a list - if isinstance(arraydef, list) and len(arraydef) > 0: + if isinstance(arraydef, instance(list)) and len(arraydef) > 0: offset = 0 if len(restore) > arraydef[0]: exit(ExitCode.RESTORE_DATA_ERROR, "file '{sfile}', array '{sname}[{selem}]' exceeds max number of elements [{smax}]".format(sfile=filename, sname=fieldname, selem=len(restore), smax=arraydef[0]), type_=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe())) @@ -2499,13 +2450,13 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""): offset += length # contains a dict - elif isinstance(format_, dict): + elif isinstance(format_, instance(dict)): for name in format_: # -> iterate through format if name in restore: dobj = SetField(dobj, name, format_[name], restore[name], addroffset=addroffset, filename=filename) # a simple value - elif isinstance(format_, (str, bool, int, float, long)): + elif isinstance(format_, instance((str, bool, int, float, long))): valid = True err = "" errformat = "" @@ -2533,7 +2484,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""): # integer elif format_[-1:] in ['b','B','h','H','i','I','l','L','q','Q','P']: value = ReadWriteConverter(restore, fielddef, read=False) - if isinstance(value, (str, unicode)): + if isinstance(value, instance(str)): value = int(value, 0) else: value = int(value) @@ -2605,14 +2556,14 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""): # copy value before possible change below _value = value - if isinstance(_value, (str, unicode)): + if isinstance(_value, instance(str)): _value = "'{}'".format(_value) if valid: if not skip: - if args.debug >= 2: + if debug(args) >= 2: sbits = " {} bits shift {}".format(bits, bitshift) if bits else "" - strvalue = "{} [{}]".format(_value, hex(value)) if isinstance(_value, int) else _value + strvalue = "{} [{}]".format(_value, hex(value)) if isinstance(_value, instance(int)) else _value print("SetField(): Set '{}' using '{}'/{}{} @{} to {}".format(fieldname, format_, arraydef, sbits, hex(baseaddr+addroffset), strvalue), file=sys.stderr) if fieldname != 'cfg_crc' and fieldname != '_': prevvalue = GetFieldValue(fielddef, dobj, baseaddr+addroffset) @@ -2621,7 +2572,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""): if prevvalue != curvalue and args.verbose: message("Value for '{}' changed from {} to {}".format(fieldname, prevvalue, curvalue), type_=LogType.INFO) else: - if args.debug >= 2: + if debug(args) >= 2: print("SetField(): Special field '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr) else: sformat = "file '{sfile}' - {{'{sname}': {svalue}}} ({serror})"+errformat @@ -2662,7 +2613,7 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0, return cmnds # contains a list - if isinstance(arraydef, list) and len(arraydef) > 0: + if isinstance(arraydef, instance(list)) and len(arraydef) > 0: offset = 0 if len(mappedvalue) > arraydef[0]: exit(ExitCode.RESTORE_DATA_ERROR, "array '{sname}[{selem}]' exceeds max number of elements [{smax}]".format(sname=fieldname, selem=len(mappedvalue), smax=arraydef[0]), type_=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe())) @@ -2677,23 +2628,23 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0, offset += length # contains a dict - elif isinstance(format_, dict): + elif isinstance(format_, instance(dict)): for name in format_: # -> iterate through format if name in mappedvalue: cmnds = SetCmnd(cmnds, name, format_[name], valuemapping, mappedvalue[name], addroffset=addroffset, idx=idx) # a simple value - elif isinstance(format_, (str, bool, int, float, long)): + elif isinstance(format_, instance((str, bool, int, float, long))): if group is not None: group = group.title(); - if isinstance(tasmotacmnd, tuple): + if isinstance(tasmotacmnd, instance(tuple)): tasmotacmnds = tasmotacmnd for tasmotacmnd in tasmotacmnds: cmnd = CmndConverter(valuemapping, mappedvalue, idx, fielddef) if group is not None and cmnd is not None: if group not in cmnds: cmnds[group] = [] - if isinstance(cmnd, list): + if isinstance(cmnd, instance(list)): for c in cmnd: cmnds[group].append(c) else: @@ -2703,7 +2654,7 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0, if group is not None and cmnd is not None: if group not in cmnds: cmnds[group] = [] - if isinstance(cmnd, list): + if isinstance(cmnd, instance(list)): for c in cmnd: cmnds[group].append(c) else: @@ -2722,7 +2673,7 @@ def Bin2Mapping(decode_cfg): @return: valuemapping data as mapping dictionary """ - if isinstance(decode_cfg, bytearray): + if isinstance(decode_cfg, instance((bytes,bytearray))): decode_cfg = str(decode_cfg) # get binary header and template to use @@ -2814,7 +2765,7 @@ def Mapping2Bin(decode_cfg, jsonconfig, filename=""): @return: changed binary config data (decrypted) or None on error """ - if isinstance(decode_cfg, str): + if isinstance(decode_cfg, instance(str)): decode_cfg = bytearray(decode_cfg) @@ -2864,7 +2815,7 @@ def Mapping2Cmnd(decode_cfg, valuemapping, filename=""): @return: Tasmota command mapping {group: [cmnd <,cmnd <,...>>]} """ - if isinstance(decode_cfg, str): + if isinstance(decode_cfg, instance(str)): decode_cfg = bytearray(decode_cfg) # get binary header data to use the correct version template from device @@ -3297,7 +3248,7 @@ def ParseArgs(): args = parser.parse_args() - if args.debug >= 1: + if debug(args) >= 1: print(parser.format_values(), file=sys.stderr) print("Settings:", file=sys.stderr) for k in args.__dict__: