diff --git a/CHANGELOG.md b/CHANGELOG.md index 686e3cc70..7f70e9bd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. - ESP32 support for internal Hall Effect sensor connected to both GPIO36 and GPIO39 only - Support for multiple CCS811 sensors with baseline control (USE_CCS811_V2) by clanganke (#10858) - Berry add ``gpio`` module +- Berry add ``light`` module ### Changed - PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12 diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_gpio_lib.c b/lib/libesp32/Berry-0.1.10/src/port/be_gpio_lib.c index 48d121f4c..2ac789b81 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/be_gpio_lib.c +++ b/lib/libesp32/Berry-0.1.10/src/port/be_gpio_lib.c @@ -288,7 +288,7 @@ be_native_module_attr_table(gpio) { be_define_native_module(gpio, NULL); #else /* @const_object_info_begin -module gpio (scope: global, depend: BE_USE_GPIO_MODULE) { +module gpio (scope: global, depend: BE_USE_TASMOTA) { LOW, int(0) HIGH, int(1) diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_light_lib.c b/lib/libesp32/Berry-0.1.10/src/port/be_light_lib.c new file mode 100644 index 000000000..95f6baf13 --- /dev/null +++ b/lib/libesp32/Berry-0.1.10/src/port/be_light_lib.c @@ -0,0 +1,41 @@ +/******************************************************************** + * Tasmota lib + * + * To use: `import tasmota` + *******************************************************************/ +#include "be_object.h" +#include "be_string.h" +#include "be_gc.h" + + +extern int l_getlight(bvm *vm); +extern int l_setlight(bvm *vm); + +extern int l_gamma8(bvm *vm); +extern int l_gamma10(bvm *vm); +extern int l_rev_gamma10(bvm *vm); + +// #if !BE_USE_PRECOMPILED_OBJECT +#if 1 // TODO we will do pre-compiled later + +be_native_module_attr_table(light) { + + be_native_module_function("get", l_getlight), + be_native_module_function("set", l_setlight), + + be_native_module_function("gamma8", l_gamma8), + be_native_module_function("gamma10", l_gamma10), + be_native_module_function("reverse_gamma10", l_rev_gamma10), + +}; + +be_define_native_module(light, NULL); + +#else +/* @const_object_info_begin +module tasmota (scope: global, depend: 1) { + get_free_heap, func(l_getFreeHeap) +} +@const_object_info_end */ +#include "../generate/be_fixed_tasmota.h" +#endif diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c b/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c index ee151bc66..18f8658e1 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c +++ b/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c @@ -21,6 +21,7 @@ be_extern_native_module(gc); be_extern_native_module(solidify); /* Tasmota specific */ +be_extern_native_module(light); be_extern_native_module(gpio); be_extern_native_module(energy); @@ -60,8 +61,9 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #endif /* user-defined modules register start */ // #ifdef ESP32 -#if BE_USE_GPIO_MODULE +#if BE_USE_TASMOTA &be_native_module(gpio), + &be_native_module(light), #endif &be_native_module(energy), // #endif // ESP32 diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c b/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c index f14d2a4c5..97ecc2cf8 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c +++ b/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c @@ -2124,6 +2124,184 @@ static const bclosure cmd_closure = { /*******************************************************************/ + +/******************************************************************** + "def get_light(l) " + "print('tasmota.get_light() is deprecated, use light.get()') " + "import light " + "if l != nil " + "return light.get(l) " + "else " + "return light.get() " + "end " + "end " +********************************************************************/ +/******************************************************************** +** Solidified function: get_light +********************************************************************/ + +be_define_local_const_str(get_light_str_name, "get_light", 381930476, 0, 9, 0); +be_define_local_const_str(get_light_str_source, "string", 398550328, 0, 6, 0); +be_define_local_const_str(get_light_str_0, "tasmota.get_light() is deprecated, use light.get()", -769213649, 0, 50, 0); +be_define_local_const_str(get_light_str_1, "light", -493019601, 0, 5, 0); +be_define_local_const_str(get_light_str_2, "get", 1410115415, 0, 3, 0); + +static const bvalue get_light_ktab[3] = { + { { .s=be_local_const_str(get_light_str_0) }, BE_STRING}, + { { .s=be_local_const_str(get_light_str_1) }, BE_STRING}, + { { .s=be_local_const_str(get_light_str_2) }, BE_STRING}, +}; + +static const uint32_t get_light_code[16] = { + 0x6008000F, // 0000 GETGBL R2 G15 + 0x580C0000, // 0001 LDCONST R3 K0 + 0x7C080200, // 0002 CALL R2 1 + 0xA40A0200, // 0003 IMPORT R2 R257 + 0x4C0C0000, // 0004 LDNIL 3 + 0x200C0203, // 0005 NE R3 R1 R3 + 0x780E0004, // 0006 JMPF R3 #000C + 0x8C0C0502, // 0007 GETMET R3 R2 R258 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80040600, // 000A RET 1 R3 + 0x70020002, // 000B JMP #000F + 0x8C0C0502, // 000C GETMET R3 R2 R258 + 0x7C0C0200, // 000D CALL R3 1 + 0x80040600, // 000E RET 1 R3 + 0x80000000, // 000F RET 0 R0 +}; + +static const bproto get_light_proto = { + NULL, // bgcobject *next + 8, // type + GC_CONST, // marked + 6, // nstack + 0, // nupvals + 2, // argc + 0, // varg + NULL, // bgcobject *gray + NULL, // bupvaldesc *upvals + (bvalue*) &get_light_ktab, // ktab + NULL, // bproto **ptab + (binstruction*) &get_light_code, // code + be_local_const_str(get_light_str_name), // name + 16, // codesize + 3, // nconst + 0, // nproto + be_local_const_str(get_light_str_source), // source +#if BE_DEBUG_RUNTIME_INFO /* debug information */ + NULL, // lineinfo + 0, // nlineinfo +#endif +#if BE_DEBUG_VAR_INFO + NULL, // varinfo + 0, // nvarinfo +#endif +}; + +static const bclosure get_light_closure = { + NULL, // bgcobject *next + 36, // type + GC_CONST, // marked + 0, // nupvals + NULL, // bgcobject *gray + (bproto*) &get_light_proto, // proto + { NULL } // upvals +}; + +/*******************************************************************/ + +/******************************************************************** + + // set_light and get_light deprecetaion + "def set_light(v,l) " + "print('tasmota.set_light() is deprecated, use light.set()') " + "import light " + "if l != nil " + "return light.set(v,l) " + "else " + "return light.set(v) " + "end " + "end " + +********************************************************************/ +/******************************************************************** +** Solidified function: set_light +********************************************************************/ + +be_define_local_const_str(set_light_str_name, "set_light", -1118891144, 0, 9, 0); +be_define_local_const_str(set_light_str_source, "string", 398550328, 0, 6, 0); +be_define_local_const_str(set_light_str_0, "tasmota.set_light() is deprecated, use light.set()", 2124937871, 0, 50, 0); +be_define_local_const_str(set_light_str_1, "light", -493019601, 0, 5, 0); +be_define_local_const_str(set_light_str_2, "set", -970520829, 0, 3, 0); + +static const bvalue set_light_ktab[3] = { + { { .s=be_local_const_str(set_light_str_0) }, BE_STRING}, + { { .s=be_local_const_str(set_light_str_1) }, BE_STRING}, + { { .s=be_local_const_str(set_light_str_2) }, BE_STRING}, +}; + +static const uint32_t set_light_code[18] = { + 0x600C000F, // 0000 GETGBL R3 G15 + 0x58100000, // 0001 LDCONST R4 K0 + 0x7C0C0200, // 0002 CALL R3 1 + 0xA40E0200, // 0003 IMPORT R3 R257 + 0x4C100000, // 0004 LDNIL 4 + 0x20100404, // 0005 NE R4 R2 R4 + 0x78120005, // 0006 JMPF R4 #000D + 0x8C100702, // 0007 GETMET R4 R3 R258 + 0x5C180200, // 0008 MOVE R6 R1 + 0x5C1C0400, // 0009 MOVE R7 R2 + 0x7C100600, // 000A CALL R4 3 + 0x80040800, // 000B RET 1 R4 + 0x70020003, // 000C JMP #0011 + 0x8C100702, // 000D GETMET R4 R3 R258 + 0x5C180200, // 000E MOVE R6 R1 + 0x7C100400, // 000F CALL R4 2 + 0x80040800, // 0010 RET 1 R4 + 0x80000000, // 0011 RET 0 R0 +}; + +static const bproto set_light_proto = { + NULL, // bgcobject *next + 8, // type + GC_CONST, // marked + 8, // nstack + 0, // nupvals + 3, // argc + 0, // varg + NULL, // bgcobject *gray + NULL, // bupvaldesc *upvals + (bvalue*) &set_light_ktab, // ktab + NULL, // bproto **ptab + (binstruction*) &set_light_code, // code + be_local_const_str(set_light_str_name), // name + 18, // codesize + 3, // nconst + 0, // nproto + be_local_const_str(set_light_str_source), // source +#if BE_DEBUG_RUNTIME_INFO /* debug information */ + NULL, // lineinfo + 0, // nlineinfo +#endif +#if BE_DEBUG_VAR_INFO + NULL, // varinfo + 0, // nvarinfo +#endif +}; + +static const bclosure set_light_closure = { + NULL, // bgcobject *next + 36, // type + GC_CONST, // marked + 0, // nupvals + NULL, // bgcobject *gray + (bproto*) &set_light_proto, // proto + { NULL } // upvals +}; + +/*******************************************************************/ + /******************************************************************** ********************************************************************/ @@ -2162,9 +2340,7 @@ void be_load_tasmota_ntvlib(bvm *vm) { "response_append", l_respAppend }, { "web_send_decimal", l_webSendDecimal }, - { "get_light", l_getlight }, { "get_power", l_getpower }, - { "set_light", l_setlight }, { "set_power", l_setpower }, { "i2c_enabled", l_i2cenabled }, @@ -2187,6 +2363,10 @@ void be_load_tasmota_ntvlib(bvm *vm) { "load", (bntvfunc) &load_closure }, { "wire_scan", (bntvfunc) &wire_scan_closure }, + // deprecated + { "get_light", (bntvfunc) &get_light_closure }, + { "set_light", (bntvfunc) &set_light_closure }, + { NULL, NULL } }; be_regclass(vm, "Tasmota_ntv", members); diff --git a/lib/libesp32/Berry-0.1.10/src/port/berry_conf.h b/lib/libesp32/Berry-0.1.10/src/port/berry_conf.h index faed6fd15..dc31e6a6e 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/berry_conf.h +++ b/lib/libesp32/Berry-0.1.10/src/port/berry_conf.h @@ -158,9 +158,9 @@ #define BE_USE_SOLIDIFY_MODULE 1 // #ifdef ESP32 -#define BE_USE_GPIO_MODULE 1 +#define BE_USE_TASMOTA 1 // #else -// #define BE_USE_GPIO_MODULE 0 +// #define BE_USE_TASMOTA 0 // #endif /* Macro: BE_EXPLICIT_XXX diff --git a/tasmota/xdrv_04_light_utils.ino b/tasmota/xdrv_04_light_utils.ino index 90c2f1dd3..16943c884 100644 --- a/tasmota/xdrv_04_light_utils.ino +++ b/tasmota/xdrv_04_light_utils.ino @@ -325,6 +325,11 @@ uint8_t ledGamma(uint8_t v) { return change10to8(ledGamma10(v)); } +// Reverse 10 bits +uint16_t ledGammaReverse(uint16_t vg) { + return ledGammaReverse_internal(vg, gamma_table); +} + // Fast versions for Fading uint16_t ledGammaFast(uint16_t v) { return ledGamma_internal(v, gamma_table_fast); diff --git a/tasmota/xdrv_52_3_berry_light.ino b/tasmota/xdrv_52_3_berry_light.ino new file mode 100644 index 000000000..2f3832234 --- /dev/null +++ b/tasmota/xdrv_52_3_berry_light.ino @@ -0,0 +1,312 @@ +/* + xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY + +#include +#include + +/*********************************************************************************************\ + * + * +\*********************************************************************************************/ +extern "C" { + +#ifdef USE_LIGHT + // push the light status object on the vm stack + void push_getlight(bvm *vm, uint32_t light_num) { + bool data_present = false; // do we have relevant data + be_newobject(vm, "map"); + // check if the light exist + // TasmotaGlobal.devices_present + // Light.device + // Light.subtype + // Light.pwm_multi_channels + // light_controller.isCTRGBLinked() + + if (Light.device > 0) { + // we have a light + + uint8_t channels[LST_MAX]; + char s_rgb[8] = {0}; // RGB raw levels + light_controller.calcLevels(channels); + uint8_t bri = light_state.getBri(); + + // map_insert_int(vm, "_devices_present", TasmotaGlobal.devices_present); + // map_insert_int(vm, "_light_device", Light.device); + // map_insert_int(vm, "_light_subtype", Light.subtype); + // map_insert_int(vm, "_light_multi", Light.pwm_multi_channels); + // map_insert_int(vm, "_light_linked", light_controller.isCTRGBLinked()); + + if (!Light.pwm_multi_channels) { + uint32_t subtype = Light.subtype; // virtual sub-type, for SO37 128 + uint32_t chanidx = 0; // channel offset, for SO37 128 + + + if (light_controller.isCTRGBLinked() && (light_num == 0)) { + data_present = true; // valid combination + if (subtype >= LST_RGBW) { + map_insert_str(vm, "colormode", (light_state.getColorMode() & LCM_RGB ? "rgb" : "ct")); + } + } + if (!light_controller.isCTRGBLinked()) { + if (light_num == 0) { + data_present = true; // valid combination + if (subtype > LST_RGB) { subtype = LST_RGB; } // limit to RGB + bri = light_state.getBriRGB(); + } + if ((light_num == 1) && subtype > LST_RGB) { + data_present = true; // valid combination + subtype = subtype - LST_RGB; + chanidx = 3; // skip first 3 channels + bri = light_state.getBriCT(); + } + } + + if (data_present) { + // see ResponseLightState() + map_insert_bool(vm, "power", bitRead(TasmotaGlobal.power, light_num + Light.device - 1)); + map_insert_int(vm, "bri", bri); + + if (subtype >= LST_RGB) { + uint16_t hue; + uint8_t sat, bri; + light_state.getHSB(&hue, &sat, &bri); + map_insert_int(vm, "hue", hue); + map_insert_int(vm, "sat", sat); + } + if ((LST_COLDWARM == subtype) || (LST_RGBW <= subtype)) { + map_insert_int(vm, "ct", light_state.getCT()); + } + if (subtype >= LST_RGB) { + snprintf(s_rgb, sizeof(s_rgb), PSTR("%02X%02X%02X"), channels[0], channels[1], channels[2]); + map_insert_str(vm, "rgb", s_rgb); + } + if (subtype > LST_NONE) { + map_insert_list_uint8(vm, "channels", &channels[chanidx], subtype); + } + } + } else { // Light.pwm_multi_channels + if ((light_num >= 0) && (light_num < LST_MAX)) { + data_present = true; + map_insert_bool(vm, "power", Light.power & (1 << light_num)); + map_insert_int(vm, "bri", Light.current_color[light_num]); + map_insert_list_uint8(vm, "channels", &channels[light_num], 1); + } + } + + be_pop(vm, 1); + if (!data_present) { + be_pop(vm, 1); + be_pushnil(vm); + } + } else { + be_pop(vm, 1); + be_pushnil(vm); + } + } + + // get light + int32_t l_getlight(bvm *vm); + int32_t l_getlight(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 0 || (top == 1 && be_isint(vm, 1))) { + int32_t light_num = 0; + if (top > 1) { + light_num = be_toint(vm, 1); + } + push_getlight(vm, light_num); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // set light + int32_t l_setlight(bvm *vm); + int32_t l_setlight(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top >= 1 && be_isinstance(vm, 1) && (top != 2 || be_isint(vm, 2))) { + int32_t idx = 0; + if (top >= 2) { + idx = be_toint(vm, 2); + be_pop(vm, 1); // remove last argument to have the map at the top of stack + } + + // power + if (map_find(vm, "power")) { + bool power = be_tobool(vm, -1); + bool current_power = bitRead(TasmotaGlobal.power, idx + Light.device - 1); + if (power != current_power) { // only send command if needed + ExecuteCommandPower(idx + Light.device, (power) ? POWER_ON : POWER_OFF, SRC_BERRY); + } + } + be_pop(vm, 1); + + // ct + if (map_find(vm, "ct")) { + int32_t ct = be_toint(vm, -1); + light_controller.changeCTB(ct, light_state.getBriCT()); + } + be_pop(vm, 1); + + // hue + if (map_find(vm, "hue")) { + int32_t hue = be_toint(vm, -1); + uint8_t sat; + uint8_t bri; + light_state.getHSB(nullptr, &sat, &bri); + light_controller.changeHSB(hue, sat, bri); + } + be_pop(vm, 1); + + // sat + if (map_find(vm, "sat")) { + int32_t sat = be_toint(vm, -1); + uint16_t hue; + uint8_t bri; + light_state.getHSB(&hue, nullptr, &bri); + light_controller.changeHSB(hue, sat, bri); + } + be_pop(vm, 1); + + // rgb + if (map_find(vm, "rgb")) { + const char * rgb_s = be_tostring(vm, -1); + SBuffer buf = SBuffer::SBufferFromHex(rgb_s, strlen(rgb_s)); + uint8_t channels[LST_MAX] = {}; + memcpy(channels, buf.buf(), buf.len() > LST_MAX ? LST_MAX : buf.len()); + bool on = false; // if all are zero, then only set power off + for (uint32_t i = 0; i < LST_MAX; i++) { + if (channels[i] != 0) { on = true; } + } + if (on) { + light_controller.changeChannels(channels); + } else { + ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); + } + } + be_pop(vm, 1); + + // channels + if (map_find(vm, "channels")) { + if (be_isinstance(vm, -1)) { + be_getbuiltin(vm, "list"); // add "list" class + if (be_isderived(vm, -2)) { + be_pop(vm, 1); // remove "list" class from top + int32_t list_size = get_list_size(vm); + // AddLog(LOG_LEVEL_INFO, "Instance is list size = %d", list_size); + + uint8_t channels[LST_MAX] = {}; // initialized with all zeroes + if (list_size > LST_MAX) { list_size = LST_MAX; } // no more than 5 channels, no need to test for positive, any negative will be discarded by loop + for (uint32_t i = 0; i < list_size; i++) { + // be_dumpstack(vm); + get_list_item(vm, i); + // be_dumpstack(vm); + int32_t val = be_toint(vm, -1); + be_pop(vm, 1); // remove result from stack + channels[i] = to_u8(val); + + bool on = false; // if all are zero, then only set power off + for (uint32_t i = 0; i < LST_MAX; i++) { + if (channels[i] != 0) { on = true; } + } + if (on) { + light_controller.changeChannels(channels); + } else { + ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); + } + } + } else { + be_pop(vm, 1); // remove "list" class from top + } + } + } + be_pop(vm, 1); + + // bri is done after channels and rgb + // bri + if (map_find(vm, "bri")) { + int32_t bri = be_toint(vm, -1); + light_controller.changeBri(bri); + } + be_pop(vm, 1); + + push_getlight(vm, idx); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + int l_gamma8(bvm *vm); + int l_gamma8(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc == 1 && be_isint(vm, 1)) { + int32_t val = be_toint(vm, 1); + if (val < 0) { val = 0; } + if (val >= (1<<8)) { val = (1<<8) - 1; }; + int32_t gamma = ledGamma(val); + be_pushint(vm, gamma); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + int l_gamma10(bvm *vm); + int l_gamma10(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc == 1 && be_isint(vm, 1)) { + int32_t val = be_toint(vm, 1); + if (val < 0) { val = 0; } + if (val >= (1<<10)) { val = (1<<10) - 1; }; + int32_t gamma = ledGamma10_10(val); + be_pushint(vm, gamma); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + int l_rev_gamma10(bvm *vm); + int l_rev_gamma10(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc == 1 && be_isint(vm, 1)) { + int32_t val = be_toint(vm, 1); + if (val < 0) { val = 0; } + if (val >= (1<<10)) { val = (1<<10) - 1; }; + int32_t rev_gamma = ledGammaReverse(val); + be_pushint(vm, rev_gamma); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + +#else // #ifdef USE_LIGHT + + int32_t b_light_missing(struct bvm *vm) { + be_raise(vm, "feature_error", "LIGHT is not enabled, use '#define USE_LIGHT'"); + } + int32_t l_getlight(struct bvm *vm) __attribute__ ((weak, alias ("b_light_missing"))); + int32_t l_setlight(struct bvm *vm) __attribute__ ((weak, alias ("b_light_missing"))); + int32_t gamma8(struct bvm *vm) __attribute__ ((weak, alias ("b_light_missing"))); + int32_t gamma10(struct bvm *vm) __attribute__ ((weak, alias ("b_light_missing"))); + int32_t reverse_gamma10(struct bvm *vm) __attribute__ ((weak, alias ("b_light_missing"))); +#endif // #ifdef USE_LIGHT +} + +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_tasmota.ino b/tasmota/xdrv_52_3_berry_tasmota.ino index baeed6adc..89ea65858 100644 --- a/tasmota/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/xdrv_52_3_berry_tasmota.ino @@ -243,235 +243,6 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } -#ifdef USE_LIGHT - // push the light status object on the vm stack - void push_getlight(bvm *vm, uint32_t light_num) { - bool data_present = false; // do we have relevant data - be_newobject(vm, "map"); - // check if the light exist - // TasmotaGlobal.devices_present - // Light.device - // Light.subtype - // Light.pwm_multi_channels - // light_controller.isCTRGBLinked() - - if (Light.device > 0) { - // we have a light - - uint8_t channels[LST_MAX]; - char s_rgb[8] = {0}; // RGB raw levels - light_controller.calcLevels(channels); - uint8_t bri = light_state.getBri(); - - // map_insert_int(vm, "_devices_present", TasmotaGlobal.devices_present); - // map_insert_int(vm, "_light_device", Light.device); - // map_insert_int(vm, "_light_subtype", Light.subtype); - // map_insert_int(vm, "_light_multi", Light.pwm_multi_channels); - // map_insert_int(vm, "_light_linked", light_controller.isCTRGBLinked()); - - if (!Light.pwm_multi_channels) { - uint32_t subtype = Light.subtype; // virtual sub-type, for SO37 128 - uint32_t chanidx = 0; // channel offset, for SO37 128 - - - if (light_controller.isCTRGBLinked() && (light_num == 0)) { - data_present = true; // valid combination - if (subtype >= LST_RGBW) { - map_insert_str(vm, "colormode", (light_state.getColorMode() & LCM_RGB ? "rgb" : "ct")); - } - } - if (!light_controller.isCTRGBLinked()) { - if (light_num == 0) { - data_present = true; // valid combination - if (subtype > LST_RGB) { subtype = LST_RGB; } // limit to RGB - bri = light_state.getBriRGB(); - } - if ((light_num == 1) && subtype > LST_RGB) { - data_present = true; // valid combination - subtype = subtype - LST_RGB; - chanidx = 3; // skip first 3 channels - bri = light_state.getBriCT(); - } - } - - if (data_present) { - // see ResponseLightState() - map_insert_bool(vm, "power", bitRead(TasmotaGlobal.power, light_num + Light.device - 1)); - map_insert_int(vm, "bri", bri); - - if (subtype >= LST_RGB) { - uint16_t hue; - uint8_t sat, bri; - light_state.getHSB(&hue, &sat, &bri); - map_insert_int(vm, "hue", hue); - map_insert_int(vm, "sat", sat); - } - if ((LST_COLDWARM == subtype) || (LST_RGBW <= subtype)) { - map_insert_int(vm, "ct", light_state.getCT()); - } - if (subtype >= LST_RGB) { - snprintf(s_rgb, sizeof(s_rgb), PSTR("%02X%02X%02X"), channels[0], channels[1], channels[2]); - map_insert_str(vm, "rgb", s_rgb); - } - if (subtype > LST_NONE) { - map_insert_list_uint8(vm, "channels", &channels[chanidx], subtype); - } - } - } else { // Light.pwm_multi_channels - if ((light_num >= 0) && (light_num < LST_MAX)) { - data_present = true; - map_insert_bool(vm, "power", Light.power & (1 << light_num)); - map_insert_int(vm, "bri", Light.current_color[light_num]); - map_insert_list_uint8(vm, "channels", &channels[light_num], 1); - } - } - - be_pop(vm, 1); - if (!data_present) { - be_pop(vm, 1); - be_pushnil(vm); - } - } else { - be_pop(vm, 1); - be_pushnil(vm); - } - } - - // get light - int32_t l_getlight(bvm *vm); - int32_t l_getlight(bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 || (top == 2 && be_isint(vm, 2))) { - int32_t light_num = 0; - if (top > 1) { - light_num = be_toint(vm, 2); - } - push_getlight(vm, light_num); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // set light - int32_t l_setlight(bvm *vm); - int32_t l_setlight(bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top >= 2 && be_isinstance(vm, 2) && (top != 3 || be_isint(vm, 3))) { - int32_t idx = 0; - if (top >= 3) { - idx = be_toint(vm, 3); - be_pop(vm, 1); // remove last argument to have the map at the top of stack - } - - // power - if (map_find(vm, "power")) { - bool power = be_tobool(vm, -1); - bool current_power = bitRead(TasmotaGlobal.power, idx + Light.device - 1); - if (power != current_power) { // only send command if needed - ExecuteCommandPower(idx + Light.device, (power) ? POWER_ON : POWER_OFF, SRC_BERRY); - } - } - be_pop(vm, 1); - - // ct - if (map_find(vm, "ct")) { - int32_t ct = be_toint(vm, -1); - light_controller.changeCTB(ct, light_state.getBriCT()); - } - be_pop(vm, 1); - - // hue - if (map_find(vm, "hue")) { - int32_t hue = be_toint(vm, -1); - uint8_t sat; - uint8_t bri; - light_state.getHSB(nullptr, &sat, &bri); - light_controller.changeHSB(hue, sat, bri); - } - be_pop(vm, 1); - - // sat - if (map_find(vm, "sat")) { - int32_t sat = be_toint(vm, -1); - uint16_t hue; - uint8_t bri; - light_state.getHSB(&hue, nullptr, &bri); - light_controller.changeHSB(hue, sat, bri); - } - be_pop(vm, 1); - - // rgb - if (map_find(vm, "rgb")) { - const char * rgb_s = be_tostring(vm, -1); - SBuffer buf = SBuffer::SBufferFromHex(rgb_s, strlen(rgb_s)); - uint8_t channels[LST_MAX] = {}; - memcpy(channels, buf.buf(), buf.len() > LST_MAX ? LST_MAX : buf.len()); - bool on = false; // if all are zero, then only set power off - for (uint32_t i = 0; i < LST_MAX; i++) { - if (channels[i] != 0) { on = true; } - } - if (on) { - light_controller.changeChannels(channels); - } else { - ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); - } - } - be_pop(vm, 1); - - // channels - if (map_find(vm, "channels")) { - if (be_isinstance(vm, -1)) { - be_getbuiltin(vm, "list"); // add "list" class - if (be_isderived(vm, -2)) { - be_pop(vm, 1); // remove "list" class from top - int32_t list_size = get_list_size(vm); - // AddLog(LOG_LEVEL_INFO, "Instance is list size = %d", list_size); - - uint8_t channels[LST_MAX] = {}; // initialized with all zeroes - if (list_size > LST_MAX) { list_size = LST_MAX; } // no more than 5 channels, no need to test for positive, any negative will be discarded by loop - for (uint32_t i = 0; i < list_size; i++) { - // be_dumpstack(vm); - get_list_item(vm, i); - // be_dumpstack(vm); - int32_t val = be_toint(vm, -1); - be_pop(vm, 1); // remove result from stack - channels[i] = to_u8(val); - - bool on = false; // if all are zero, then only set power off - for (uint32_t i = 0; i < LST_MAX; i++) { - if (channels[i] != 0) { on = true; } - } - if (on) { - light_controller.changeChannels(channels); - } else { - ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); - } - } - } else { - be_pop(vm, 1); // remove "list" class from top - } - } - } - be_pop(vm, 1); - - // bri is done after channels and rgb - // bri - if (map_find(vm, "bri")) { - int32_t bri = be_toint(vm, -1); - light_controller.changeBri(bri); - } - be_pop(vm, 1); - - push_getlight(vm, idx); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } // TODO -#else // #ifdef USE_LIGHT - int32_t l_getlight(bvm *vm) { be_raise(vm, "feature_error", "LIGHT is not enabled, use '#define USE_LIGHT'"); } - int32_t l_setlight(struct bvm *vm) __attribute__ ((weak, alias ("l_getlight"))); -#endif // #ifdef USE_LIGHT - // get power int32_t l_getpower(bvm *vm); int32_t l_getpower(bvm *vm) { diff --git a/tasmota/xdrv_52_7_berry_embedded.ino b/tasmota/xdrv_52_7_berry_embedded.ino index 5c5b3f5d9..84d2e7bcf 100644 --- a/tasmota/xdrv_52_7_berry_embedded.ino +++ b/tasmota/xdrv_52_7_berry_embedded.ino @@ -305,6 +305,27 @@ const char berry_prog[] = // "return nil " // "end " + // // set_light and get_light deprecetaion + // "def set_light(v,l) " + // "print('tasmota.set_light() is deprecated, use light.set()') " + // "import light " + // "if l != nil " + // "return light.set(v,l) " + // "else " + // "return light.set(v) " + // "end " + // "end " + + // "def get_light(l) " + // "print('tasmota.get_light() is deprecated, use light.get()') " + // "import light " + // "if l != nil " + // "return light.get(l) " + // "else " + // "return light.get() " + // "end " + // "end " + // // cmd high-level function // "def cmd(command) " // "import json " @@ -353,6 +374,9 @@ const char berry_prog[] = "wire2 = tasmota.wire2 " // auto-import gpio "import gpio " +#ifdef USE_LIGHT + "import light " +#endif // USE_LIGHT ; const char berry_autoexec[] =