mirror of https://github.com/arendst/Tasmota.git
Merge pull request #17127 from s-hadinger/zigbee_plugin_default
Zigbee add default plugin in flash
This commit is contained in:
commit
d46f6ea6b0
|
@ -761,17 +761,6 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) {
|
|||
attr_list.addAttribute(0x0001, 0x0021).setUInt(toPercentageCR2032(mv) * 2);
|
||||
}
|
||||
break;
|
||||
case 0x00010021: // BatteryPercentage
|
||||
if (modelId.startsWith(F("TRADFRI")) ||
|
||||
modelId.startsWith(F("SYMFONISK"))) {
|
||||
attr.setUInt(attr.getUInt() * 2); // bug in IKEA remotes battery, need to double the value
|
||||
}
|
||||
break;
|
||||
case 0x00060000: // "Power" for lumi Door/Window is converted to "Contact"
|
||||
if (modelId.startsWith(F("lumi.sensor_magnet"))) {
|
||||
attr.setKeyId(0x0500, 0xFFF0 + ZA_Contact); // change cluster and attribute to 0500/FFF0
|
||||
}
|
||||
break;
|
||||
case 0x02010008: // Pi Heating Demand - solve Eutotronic bug
|
||||
case 0x02014008: // Eurotronic Host Flags decoding
|
||||
{
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
xdrv_23_zigbee_7_6_flash_fs.ino - implement a Flash based read-only triviall file-system
|
||||
|
||||
Copyright (C) 2022 Theo Arends and Stephan Hadinger
|
||||
|
||||
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_ZIGBEE
|
||||
|
||||
#ifdef ESP32
|
||||
#include <vfs_api.h>
|
||||
#else
|
||||
#include "FSImpl.h"
|
||||
#endif
|
||||
|
||||
/********************************************************************
|
||||
** Subfile implementation
|
||||
**
|
||||
** Takes a string point in Flash and turn it to a read-only file
|
||||
********************************************************************/
|
||||
|
||||
class FlashFileImpl;
|
||||
typedef std::shared_ptr<FlashFileImpl> FlashFileImplPtr;
|
||||
|
||||
class FlashFileImpl : public FileImpl {
|
||||
public:
|
||||
|
||||
FlashFileImpl(const char* str) {
|
||||
_buf = str;
|
||||
_len = strlen_P(str);
|
||||
_seek = 0;
|
||||
}
|
||||
|
||||
virtual ~FlashFileImpl() {}
|
||||
|
||||
size_t write(const uint8_t *buf, size_t size) {
|
||||
return 0; // not accepted
|
||||
}
|
||||
|
||||
size_t read(uint8_t* buf, size_t size) {
|
||||
if (_seek < _len) {
|
||||
if (size + _seek > _len) {
|
||||
size = _len - _seek; // always > 0 because of guarding test
|
||||
}
|
||||
memcpy_P(buf, _buf + _seek, size);
|
||||
_seek += size;
|
||||
return size;
|
||||
}
|
||||
return 0; // abort
|
||||
}
|
||||
|
||||
void flush() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool setBufferSize(size_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seek(uint32_t pos, SeekMode mode) {
|
||||
// AddLog(LOG_LEVEL_DEBUG, "ZIP: seek pos=%i mode=%i", pos, mode);
|
||||
if (SeekSet == mode) {
|
||||
if (pos <= _len) {
|
||||
_seek = pos;
|
||||
return true;
|
||||
}
|
||||
} else if (SeekCur == mode) {
|
||||
if (_seek + pos <= _len) {
|
||||
_seek += pos;
|
||||
return true;
|
||||
}
|
||||
} else if (SeekEnd == mode) {
|
||||
_seek = _len;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t position() const {
|
||||
return _seek;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _len;
|
||||
}
|
||||
|
||||
void close() {
|
||||
// do nothing
|
||||
}
|
||||
time_t getLastWrite() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* path() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* name() const {
|
||||
return "<internal>";
|
||||
}
|
||||
|
||||
boolean isDirectory(void) {
|
||||
return false; // no directory allowed
|
||||
}
|
||||
|
||||
FileImplPtr openNextFile(const char* mode) {
|
||||
return nullptr; // TODO
|
||||
}
|
||||
|
||||
void rewindDirectory(void) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ESP8266 specific?
|
||||
bool truncate(uint32_t size) { return false; }
|
||||
const char* fullName() const { return ""; }
|
||||
bool isFile() const { return true; }
|
||||
bool isDirectory() const { return false; }
|
||||
|
||||
protected:
|
||||
const char * _buf;
|
||||
size_t _len;
|
||||
uint32_t _seek;
|
||||
};
|
||||
|
||||
#endif // USE_ZIGBEE
|
|
@ -125,6 +125,200 @@ bool Zb_readline(class File *f, char* buf, size_t size) {
|
|||
extern FS *ffsp;
|
||||
#endif
|
||||
|
||||
bool ZbLoad_inner(const char *filename, File &fp) {
|
||||
char * filename_imported = nullptr;
|
||||
Z_plugin_template * tmpl = nullptr; // current template with matchers and attributes
|
||||
bool new_matchers = false; // indicates that we have finished the current matchers
|
||||
char buf_line[96]; // max line is 96 bytes (comments don't count)
|
||||
|
||||
// read the first 6 chars
|
||||
bool invalid_header = false;
|
||||
static const char Z2T_HEADER_V1[] PROGMEM = "#Z2Tv1";
|
||||
for (uint32_t i = 0; i < 6; i++) {
|
||||
int c = fp.read();
|
||||
if (c < 0) {
|
||||
invalid_header = true;
|
||||
break;
|
||||
}
|
||||
buf_line[i] = c;
|
||||
buf_line[i+1] = 0;
|
||||
}
|
||||
if (!invalid_header) {
|
||||
if (strcmp_P(buf_line, Z2T_HEADER_V1) != 0) {
|
||||
invalid_header = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid_header) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' invalid header", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse line by line
|
||||
while (1) {
|
||||
if (!Zb_readline(&fp, buf_line, sizeof(buf_line))) {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
|
||||
// at first valid line, we instanciate a new plug-in instance and assign a filemane
|
||||
if (filename_imported == nullptr) {
|
||||
// allocate only once the filename for multiple entries
|
||||
// freed only by `ZbUnload`
|
||||
filename_imported = (char*) malloc(strlen(filename)+1);
|
||||
strcpy(filename_imported, filename);
|
||||
}
|
||||
|
||||
// there is a non-empty line, containing no space/tab/crlf
|
||||
// depending on the first char, parse either device name or cluster/attribute+name
|
||||
if (buf_line[0] == ':') {
|
||||
if (tmpl == nullptr || new_matchers) {
|
||||
tmpl = &g_plugin_templates.addToLast();
|
||||
tmpl->filename = filename_imported;
|
||||
new_matchers = false;
|
||||
}
|
||||
// parse device name
|
||||
char *rest = buf_line + 1; // skip first char ':'
|
||||
char *token = strtok_r(rest, ",", &rest);
|
||||
Z_plugin_matcher & matcher = tmpl->matchers.addToLast();
|
||||
if (token != nullptr) {
|
||||
matcher.setModel(token);
|
||||
}
|
||||
token = strtok_r(rest, ",", &rest);
|
||||
if (token != nullptr) {
|
||||
matcher.setManuf(token);
|
||||
}
|
||||
} else {
|
||||
if (tmpl == nullptr) {
|
||||
continue;
|
||||
}
|
||||
new_matchers = true;
|
||||
char *rest = buf_line;
|
||||
char *token = strtok_r(rest, ",", &rest);
|
||||
if (token == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// detect if token contains '=', if yes it is a synonym
|
||||
char * delimiter_equal = strchr(token, '=');
|
||||
|
||||
if (delimiter_equal == nullptr) {
|
||||
// NORMAL ATTRIBUTE
|
||||
// token is of from '0000/0000' or '0000/0000%00'
|
||||
char * delimiter_slash = strchr(token, '/');
|
||||
char * delimiter_percent = strchr(token, '%');
|
||||
if (delimiter_slash == nullptr || (delimiter_percent != nullptr && delimiter_slash > delimiter_percent)) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' wrong delimiter '%s'", filename, token);
|
||||
}
|
||||
|
||||
uint16_t attr_id = 0xFFFF;
|
||||
uint16_t cluster_id = 0xFFFF;
|
||||
uint8_t type_id = Zunk;
|
||||
int8_t multiplier = 1;
|
||||
int8_t divider = 1;
|
||||
int16_t base = 0;
|
||||
char * name = nullptr;
|
||||
uint16_t manuf = 0;
|
||||
|
||||
cluster_id = strtoul(token, &delimiter_slash, 16);
|
||||
if (!delimiter_percent) {
|
||||
attr_id = strtoul(delimiter_slash+1, nullptr, 16);
|
||||
} else {
|
||||
attr_id = strtoul(delimiter_slash+1, &delimiter_percent, 16);
|
||||
type_id = Z_getTypeByName(delimiter_percent+1);
|
||||
}
|
||||
// NAME of the attribute
|
||||
token = strtok_r(rest, ",", &rest);
|
||||
if (token == nullptr) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' ignore missing name '%s'", filename, buf_line);
|
||||
continue;
|
||||
}
|
||||
name = token;
|
||||
// ADDITIONAL ELEMENTS?
|
||||
// Ex: `manuf:1037`
|
||||
while (token = strtok_r(rest, ",", &rest)) {
|
||||
char * sub_token;
|
||||
// look for multiplier
|
||||
if (sub_token = Z_subtoken(token, Z_MUL)) {
|
||||
multiplier = strtol(sub_token, nullptr, 10);
|
||||
}
|
||||
// look for divider
|
||||
else if (sub_token = Z_subtoken(token, Z_DIV)) {
|
||||
divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
// look for offset (base)
|
||||
else if (sub_token = Z_subtoken(token, Z_ADD)) {
|
||||
base = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
// look for `manuf:HHHH`
|
||||
else if (sub_token = Z_subtoken(token, Z_MANUF)) {
|
||||
manuf = strtoul(sub_token, nullptr, 16);
|
||||
}
|
||||
else {
|
||||
AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
|
||||
}
|
||||
}
|
||||
|
||||
// token contains the name of the attribute
|
||||
Z_plugin_attribute & plugin_attr = tmpl->attributes.addToLast();
|
||||
plugin_attr.cluster = cluster_id;
|
||||
plugin_attr.attribute = attr_id;
|
||||
plugin_attr.type = type_id;
|
||||
plugin_attr.setName(name);
|
||||
plugin_attr.multiplier = multiplier;
|
||||
plugin_attr.divider = divider;
|
||||
plugin_attr.base = base;
|
||||
plugin_attr.manuf = manuf;
|
||||
} else {
|
||||
// ATTRIBUTE SYNONYM
|
||||
// token is of from '0000/0000=0000/0000,1'
|
||||
char * rest2 = token;
|
||||
char * tok2 = strtok_r(rest2, "=", &rest2);
|
||||
char * delimiter_slash = strchr(tok2, '/');
|
||||
uint16_t cluster_id = strtoul(tok2, &delimiter_slash, 16);
|
||||
uint16_t attr_id = strtoul(delimiter_slash+1, nullptr, 16);
|
||||
tok2 = strtok_r(rest2, "=", &rest2);
|
||||
char * delimiter_slash2 = strchr(tok2, '/');
|
||||
uint16_t new_cluster_id = strtoul(tok2, &delimiter_slash2, 16);
|
||||
uint16_t new_attr_id = strtoul(delimiter_slash2+1, nullptr, 16);
|
||||
int8_t multiplier = 1;
|
||||
int8_t divider = 1;
|
||||
int16_t base = 0;
|
||||
|
||||
// ADDITIONAL ELEMENTS?
|
||||
while (token = strtok_r(rest, ",", &rest)) {
|
||||
char * sub_token;
|
||||
// look for multiplier
|
||||
if (sub_token = Z_subtoken(token, Z_MUL)) {
|
||||
multiplier = strtol(sub_token, nullptr, 10);
|
||||
}
|
||||
// look for divider
|
||||
else if (sub_token = Z_subtoken(token, Z_DIV)) {
|
||||
divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
// look for offset (base)
|
||||
else if (sub_token = Z_subtoken(token, Z_ADD)) {
|
||||
base = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
else {
|
||||
AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
|
||||
}
|
||||
}
|
||||
// create the synonym
|
||||
Z_attribute_synonym & syn = tmpl->synonyms.addToLast();
|
||||
syn.cluster = cluster_id;
|
||||
syn.attribute = attr_id;
|
||||
syn.new_cluster = new_cluster_id;
|
||||
syn.new_attribute = new_attr_id;
|
||||
syn.multiplier = multiplier;
|
||||
syn.divider = divider;
|
||||
syn.base = base;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// load a file from filesystem
|
||||
// returns `true` if success
|
||||
bool ZbLoad(const char *filename_raw) {
|
||||
|
@ -147,196 +341,7 @@ bool ZbLoad(const char *filename_raw) {
|
|||
return false;
|
||||
}
|
||||
|
||||
char * filename_imported = nullptr;
|
||||
Z_plugin_template * tmpl = nullptr; // current template with matchers and attributes
|
||||
bool new_matchers = false; // indicates that we have finished the current matchers
|
||||
char buf_line[96]; // max line is 96 bytes (comments don't count)
|
||||
|
||||
// read the first 6 chars
|
||||
bool invalid_header = false;
|
||||
static const char Z2T_HEADER_V1[] PROGMEM = "#Z2Tv1";
|
||||
for (uint32_t i = 0; i < 6; i++) {
|
||||
int c = fp.read();
|
||||
if (c < 0) {
|
||||
invalid_header = true;
|
||||
break;
|
||||
}
|
||||
buf_line[i] = c;
|
||||
buf_line[i+1] = 0;
|
||||
}
|
||||
if (!invalid_header) {
|
||||
if (strcmp_P(buf_line, Z2T_HEADER_V1) != 0) {
|
||||
invalid_header = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid_header) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' invalid header", filename_raw);
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse line by line
|
||||
while (1) {
|
||||
if (!Zb_readline(&fp, buf_line, sizeof(buf_line))) {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
|
||||
// at first valid line, we instanciate a new plug-in instance and assign a filemane
|
||||
if (filename_imported == nullptr) {
|
||||
// allocate only once the filename for multiple entries
|
||||
// freed only by `ZbUnload`
|
||||
filename_imported = (char*) malloc(strlen(filename.c_str())+1);
|
||||
strcpy(filename_imported, filename.c_str());
|
||||
}
|
||||
|
||||
// there is a non-empty line, containing no space/tab/crlf
|
||||
// depending on the first char, parse either device name or cluster/attribute+name
|
||||
if (buf_line[0] == ':') {
|
||||
if (tmpl == nullptr || new_matchers) {
|
||||
tmpl = &g_plugin_templates.addToLast();
|
||||
tmpl->filename = filename_imported;
|
||||
new_matchers = false;
|
||||
}
|
||||
// parse device name
|
||||
char *rest = buf_line + 1; // skip first char ':'
|
||||
char *token = strtok_r(rest, ",", &rest);
|
||||
Z_plugin_matcher & matcher = tmpl->matchers.addToLast();
|
||||
if (token != nullptr) {
|
||||
matcher.setModel(token);
|
||||
}
|
||||
token = strtok_r(rest, ",", &rest);
|
||||
if (token != nullptr) {
|
||||
matcher.setManuf(token);
|
||||
}
|
||||
} else {
|
||||
if (tmpl == nullptr) {
|
||||
continue;
|
||||
}
|
||||
new_matchers = true;
|
||||
char *rest = buf_line;
|
||||
char *token = strtok_r(rest, ",", &rest);
|
||||
if (token == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// detect if token contains '=', if yes it is a synonym
|
||||
char * delimiter_equal = strchr(token, '=');
|
||||
|
||||
if (delimiter_equal == nullptr) {
|
||||
// NORMAL ATTRIBUTE
|
||||
// token is of from '0000/0000' or '0000/0000%00'
|
||||
char * delimiter_slash = strchr(token, '/');
|
||||
char * delimiter_percent = strchr(token, '%');
|
||||
if (delimiter_slash == nullptr || (delimiter_percent != nullptr && delimiter_slash > delimiter_percent)) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' wrong delimiter '%s'", filename_raw, token);
|
||||
}
|
||||
|
||||
uint16_t attr_id = 0xFFFF;
|
||||
uint16_t cluster_id = 0xFFFF;
|
||||
uint8_t type_id = Zunk;
|
||||
int8_t multiplier = 1;
|
||||
int8_t divider = 1;
|
||||
int16_t base = 0;
|
||||
char * name = nullptr;
|
||||
uint16_t manuf = 0;
|
||||
|
||||
cluster_id = strtoul(token, &delimiter_slash, 16);
|
||||
if (!delimiter_percent) {
|
||||
attr_id = strtoul(delimiter_slash+1, nullptr, 16);
|
||||
} else {
|
||||
attr_id = strtoul(delimiter_slash+1, &delimiter_percent, 16);
|
||||
type_id = Z_getTypeByName(delimiter_percent+1);
|
||||
}
|
||||
// NAME of the attribute
|
||||
token = strtok_r(rest, ",", &rest);
|
||||
if (token == nullptr) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' ignore missing name '%s'", filename_raw, buf_line);
|
||||
continue;
|
||||
}
|
||||
name = token;
|
||||
// ADDITIONAL ELEMENTS?
|
||||
// Ex: `manuf:1037`
|
||||
while (token = strtok_r(rest, ",", &rest)) {
|
||||
char * sub_token;
|
||||
// look for multiplier
|
||||
if (sub_token = Z_subtoken(token, Z_MUL)) {
|
||||
multiplier = strtol(sub_token, nullptr, 10);
|
||||
}
|
||||
// look for divider
|
||||
else if (sub_token = Z_subtoken(token, Z_DIV)) {
|
||||
divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
// look for offset (base)
|
||||
else if (sub_token = Z_subtoken(token, Z_ADD)) {
|
||||
base = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
// look for `manuf:HHHH`
|
||||
else if (sub_token = Z_subtoken(token, Z_MANUF)) {
|
||||
manuf = strtoul(sub_token, nullptr, 16);
|
||||
}
|
||||
else {
|
||||
AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
|
||||
}
|
||||
}
|
||||
|
||||
// token contains the name of the attribute
|
||||
Z_plugin_attribute & plugin_attr = tmpl->attributes.addToLast();
|
||||
plugin_attr.cluster = cluster_id;
|
||||
plugin_attr.attribute = attr_id;
|
||||
plugin_attr.type = type_id;
|
||||
plugin_attr.setName(name);
|
||||
plugin_attr.multiplier = multiplier;
|
||||
plugin_attr.divider = divider;
|
||||
plugin_attr.base = base;
|
||||
plugin_attr.manuf = manuf;
|
||||
} else {
|
||||
// ATTRIBUTE SYNONYM
|
||||
// token is of from '0000/0000=0000/0000,1'
|
||||
char * rest2 = token;
|
||||
char * tok2 = strtok_r(rest2, "=", &rest2);
|
||||
char * delimiter_slash = strchr(tok2, '/');
|
||||
uint16_t cluster_id = strtoul(tok2, &delimiter_slash, 16);
|
||||
uint16_t attr_id = strtoul(delimiter_slash+1, nullptr, 16);
|
||||
tok2 = strtok_r(rest2, "=", &rest2);
|
||||
char * delimiter_slash2 = strchr(tok2, '/');
|
||||
uint16_t new_cluster_id = strtoul(tok2, &delimiter_slash2, 16);
|
||||
uint16_t new_attr_id = strtoul(delimiter_slash2+1, nullptr, 16);
|
||||
int8_t multiplier = 1;
|
||||
int8_t divider = 1;
|
||||
int16_t base = 0;
|
||||
|
||||
// ADDITIONAL ELEMENTS?
|
||||
while (token = strtok_r(rest, ",", &rest)) {
|
||||
char * sub_token;
|
||||
// look for multiplier
|
||||
if (sub_token = Z_subtoken(token, Z_MUL)) {
|
||||
multiplier = strtol(sub_token, nullptr, 10);
|
||||
}
|
||||
// look for divider
|
||||
else if (sub_token = Z_subtoken(token, Z_DIV)) {
|
||||
divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
// look for offset (base)
|
||||
else if (sub_token = Z_subtoken(token, Z_ADD)) {
|
||||
base = strtol(sub_token, nullptr, 10); // negative to indicate divider
|
||||
}
|
||||
else {
|
||||
AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
|
||||
}
|
||||
}
|
||||
// create the synonym
|
||||
Z_attribute_synonym & syn = tmpl->synonyms.addToLast();
|
||||
syn.cluster = cluster_id;
|
||||
syn.attribute = attr_id;
|
||||
syn.new_cluster = new_cluster_id;
|
||||
syn.new_attribute = new_attr_id;
|
||||
syn.multiplier = multiplier;
|
||||
syn.divider = divider;
|
||||
syn.base = base;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ZbLoad_inner(filename.c_str(), fp);
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_ERROR, "ZIG: filesystem not enabled");
|
||||
}
|
||||
|
@ -447,6 +452,7 @@ void ZbLoadDump(void) {
|
|||
|
||||
// Auto-load all files ending with '.zb'
|
||||
void ZbAutoload(void) {
|
||||
ZbAutoLoadFromFlash();
|
||||
#ifdef USE_UFILESYS
|
||||
if (ffsp) {
|
||||
File dir = ffsp->open("/", "r");
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
xdrv_23_zigbee_7_8_default_plugin.ino - default plugin stored in Flash
|
||||
|
||||
Copyright (C) 2021 Theo Arends and Stephan Hadinger
|
||||
|
||||
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_ZIGBEE
|
||||
|
||||
/********************************************************************
|
||||
** Default plugin
|
||||
**
|
||||
** Below is a the template loaded at boot
|
||||
** We simulate a read-only file from the filesystem
|
||||
********************************************************************/
|
||||
|
||||
const char Z_DEF_PLUGIN[] PROGMEM =
|
||||
"#Z2Tv1" "\n"
|
||||
|
||||
// bug in IKEA remotes battery, need to double the value
|
||||
":TRADFRI*," "\n"
|
||||
":SYMFONISK*," "\n"
|
||||
"0001/0021=0001/0021,mul:2" "\n" // BatteryPercentage
|
||||
|
||||
// "Power" for lumi Door/Window is converted to "Contact"
|
||||
":lumi.sensor_magnet*," "\n"
|
||||
"0006/0000=0500/FFF2" "\n" // 0xFFF0 + ZA_Contact
|
||||
;
|
||||
|
||||
/********************************************************************
|
||||
** Load from flash
|
||||
********************************************************************/
|
||||
void ZbAutoLoadFromFlash(void) {
|
||||
FlashFileImplPtr fp = FlashFileImplPtr(new FlashFileImpl(Z_DEF_PLUGIN));
|
||||
File f = File(fp);
|
||||
if (ZbLoad_inner(PSTR("<internal_plugin>"), f)) {
|
||||
AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' loaded successfully", PSTR("<internal_plugin>"));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_ZIGBEE
|
Loading…
Reference in New Issue