mirror of https://github.com/arendst/Tasmota.git
Merge pull request #11583 from s-hadinger/berry_apr_4
Berry add ``light`` module
This commit is contained in:
commit
abd70a93ba
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#include <berry.h>
|
||||
#include <Wire.h>
|
||||
|
||||
/*********************************************************************************************\
|
||||
*
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
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
|
|
@ -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) {
|
||||
|
|
|
@ -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[] =
|
||||
|
|
Loading…
Reference in New Issue