Merge pull request #2 from arendst/development

update local repo
This commit is contained in:
Vic 2020-12-20 11:40:11 +00:00 committed by GitHub
commit b6ae8182ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 4045 additions and 783 deletions

View File

@ -1,6 +1,6 @@
---
name: Problem report
about: Create a report to help us improve
name: Problem Report
about: Create a Report to help us improve
---
<!-- Thanks for reporting a problem for this project. READ THIS FIRST:
@ -29,36 +29,34 @@ _Make sure your have performed every step and checked the applicable boxes befor
- [ ] Read the [Contributing Guide and Policy](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md) and [the Code of Conduct](https://github.com/arendst/Tasmota/blob/development/CODE_OF_CONDUCT.md)
- [ ] Searched the problem in [issues](https://github.com/arendst/Tasmota/issues)
- [ ] Searched the problem in [discussions](https://github.com/arendst/Tasmota/discussions)
- [ ] Searched the problem in the [docs](https://tasmota.github.io/docs/FAQ)
- [ ] Searched the problem in the [forum](https://groups.google.com/d/forum/sonoffusers)
- [ ] Searched the problem in the [chat](https://discord.gg/Ks2Kzd4)
- [ ] Device used (e.g., Sonoff Basic): _____
- [ ] Tasmota binary firmware version number used: _____
- [ ] Pre-compiled
- [ ] Self-compiled
- [ ] IDE / Compiler used: _____
- [ ] Flashing tools used: _____
- [ ] Provide the output of command: `Backlog Template; Module; GPIO 255`:
```
```lua
Configuration output here:
```
- [ ] If using rules, provide the output of this command: `Backlog Rule1; Rule2; Rule3`:
```
```lua
Rules output here:
```
- [ ] Provide the output of this command: `Status 0`:
```
```lua
STATUS 0 output here:
```
- [ ] Provide the output of the Console log output when you experience your issue; if applicable:
_(Please use_ `weblog 4` _for more debug information)_
```
- [ ] Set `weblog` to 4 and then, when you experience your issue, provide the output of the Console log:
```lua
Console output here:

View File

@ -1,27 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!-- Thanks for suggesting an idea for this project. READ THIS FIRST:
Please take a few minutes to complete the requested information below. Our ability to provide assistance is greatly hampered without it. The details requested potentially affect which options to pursue. The small amount of time you spend completing the template will also help the volunteers providing the assistance to you to reduce the time required to help you.
DO NOT DELETE ANY TEXT from this template! Otherwise the issue will be auto-closed.
-->
**Have you looked for this feature in other issues and in the docs?**
**Is your feature request related to a problem? Please describe.**
_A clear and concise description of what the problem is._
**Describe the solution you'd like**
_A clear and concise description of what you want to happen._
**Describe alternatives you've considered**
_A clear and concise description of any alternative solutions or features you've considered._
**Additional context**
_Add any other context or screenshots about the feature request here._
**(Please, remember to close the issue when the problem has been addressed)**

View File

@ -2,7 +2,10 @@ blank_issues_enabled: false
contact_links:
- name: Tasmota Docs
url: https://tasmota.github.io/docs
about: All the information related to Tasmota
- name: Tasmota Support Chat
about: All the information related to Tasmota.
- name: Tasmota Discussions and Support
url: https://github.com/arendst/Tasmota/discussions
about: Tasmota usage Questions, Feature Requests and Projects.
- name: Tasmota Users Chat
url: https://discord.gg/Ks2Kzd4
about: Chat for feedback, questions and troubleshooting.

View File

@ -7,7 +7,7 @@
- [ ] Only relevant files were touched
- [ ] Only one feature/fix was added per PR and the code change compiles without warnings
- [ ] The code change is tested and works on Tasmota core ESP8266 V.2.7.4.9
- [ ] The code change is tested and works on Tasmota core ESP32 V.1.0.4.2
- [ ] The code change is tested and works on Tasmota core ESP32 V.1.0.5-rc4
- [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
_NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_

View File

@ -5,7 +5,7 @@
# Comment that will be sent if an issue is judged to be closed.
comment: >-
This issue has been automatically closed because the issue template is missing or incomplete.
This issue has been automatically closed because the PROBLEM REPORT TEMPLATE is missing or incomplete.
Filling the template is required so standard questions don't need to be asked again each time.
Our ability to provide assistance is greatly hampered if few minutes are not taken to complete the issue template
@ -13,19 +13,17 @@ comment: >-
of time you will spend completing the template will also help the volunteers, providing assistance to you, to reduce
the time required to help you.
Please, could you be so kind on completing the [issue template](https://github.com/arendst/Tasmota/issues/new/choose) in order to have more information so as to properly help you?
Please, could you be so kind on completing the [PROBLEM REPORT TEMPLATE](https://github.com/arendst/Tasmota/issues/new/choose) in order to have more information so as to properly help you?
Thank you for taking the time to report, hopefully it can be resolved soon.
[Wiki](https://tasmota.github.io/docs/) for more information.
[Docs](https://tasmota.github.io/docs/) for more information.
[Chat](https://discord.gg/Ks2Kzd4) for more user experience.
[Discussions](https://github.com/arendst/Tasmota/discussions) for Questions, Feature Requests and Projects.
[Community](https://groups.google.com/d/forum/sonoffusers) for forum.
[Chat](https://discord.gg/Ks2Kzd4) for more users experience.
[Code of Conduct](https://github.com/arendst/Tasmota/blob/development/CODE_OF_CONDUCT.md)
[Contributing Guideline and Policy](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md)
Please check the [Code of Conduct](https://github.com/arendst/Tasmota/blob/development/CODE_OF_CONDUCT.md) and the [Contributing Guideline and Policy](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md)
issueConfigs:
# There can be several configs for different kind of issues.

View File

@ -3,7 +3,21 @@ All notable changes to this project will be documented in this file.
## [Unreleased] - Development
## [9.1.0.2]
## [9.2.0.1]
### Added
- Milliseconds to console output (#10152)
- Support for P9813 RGB Led MOSFET controller (#10104)
### Fixed
- Redesign syslog and mqttlog using log buffer (#10164)
- Shelly Dimmer power on state (#10154, #10182)
## [Released]
## [9.2.0] 20201216
- Release Julie
## [9.1.0.2] 20201216
### Added
- KNX read reply for Power (#9236, #9891)
- Zigbee persistence of device/sensor data in EEPROM (only ZBBridge)
@ -16,6 +30,9 @@ All notable changes to this project will be documented in this file.
- Zigbee better support for Tuya Protocol (#10074)
- Support for SPI connected MFRC522 13.56MHz rfid card reader (#9916)
- Letsencrypt R3 in addition to X3 CA (#10086)
- Zigbee add visual map of network
- Command ``SetOption117 1`` for light fading to be fixed duration instead of fixed slew rate (#10109)
- Support ESP32 SPIFFS for internal use
### Breaking Changed
- KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888)
@ -38,6 +55,11 @@ All notable changes to this project will be documented in this file.
- Backlog timing wraparound (#9995)
- First LED in addressable string does not fade when using scheme (#10088)
- Improved Opentherm error handling (#10055)
- Platformio compiler option `no target align` removed fixing hardware watchdog exceptions
- Shutter motordelay stop issue (#10033)
- Shutter fix overflow on runtime over 100 seconds (#9800)
- ESP32 CC2530 heap corruption (#10121)
- ESP32 Analog input div10 rule trigger (#10149)
### Removed
- PN532 define USE_PN532_CAUSE_EVENTS replaced by generic rule trigger `on pn532#uid=`
@ -71,8 +93,6 @@ All notable changes to this project will be documented in this file.
### Removed
- Version compatibility check
## [Released]
## [9.1.0] 20201105
- Release Imogen

View File

@ -18,7 +18,7 @@ See [CHANGELOG.md](https://github.com/arendst/Tasmota/blob/development/tasmota/C
## Development
[![Dev Version](https://img.shields.io/badge/development%20version-v9.0.x.x-blue.svg)](https://github.com/arendst/Tasmota)
[![Dev Version](https://img.shields.io/badge/development%20version-v9.2.x.x-blue.svg)](https://github.com/arendst/Tasmota)
[![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://ota.tasmota.com/tasmota/)
[![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22)
[![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22)

View File

@ -21,7 +21,7 @@ In addition to the [release webpage](https://github.com/arendst/Tasmota/releases
## Development
[![Dev Version](https://img.shields.io/badge/development%20version-v9.1.x.x-blue.svg)](https://github.com/arendst/Tasmota)
[![Dev Version](https://img.shields.io/badge/development%20version-v9.2.x.x-blue.svg)](https://github.com/arendst/Tasmota)
[![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://ota.tasmota.com/tasmota/)
[![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22)
[![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22)
@ -97,24 +97,18 @@ If you're looking for support on **Tasmota** there are some options available:
### Support's Community
* [Tasmota Forum](https://groups.google.com/d/forum/sonoffusers): For usage and discussions.
* [Tasmota Support Chat](https://discord.gg/Ks2Kzd4): For support, troubleshooting and general questions. You have better chances to get fast answers from members of the Tasmota Community.
* [Tasmota Discussions](https://github.com/arendst/Tasmota/discussions): For Tasmota usage questions, Feature Requests and Projects.
* [Tasmota Users Chat](https://discord.gg/Ks2Kzd4): For support, troubleshooting and general questions. You have better chances to get fast answers from members of the Tasmota Community.
* [Search in Issues](https://github.com/arendst/Tasmota/issues): You might find an answer to your question by searching current or closed issues.
### Developers' Community
* [Bug Report](https://github.com/arendst/Tasmota/issues/new?template=Bug_report.md): For reporting Bugs of Tasmota Software.
* [Feature Request](https://github.com/arendst/Tasmota/issues/new?template=Feature_request.md): For requesting features/functions to Tasmota Software.
* [Troubleshooting](https://github.com/arendst/Tasmota/issues/new?template=Custom.md): As a last resort, you can open new *Troubleshooting* issue on GitHub if the solution could not be found using the other channels. Just remember: the more info you provide the more chances you'll have to get an accurate answer.
* [Issue a question](https://github.com/arendst/Tasmota/issues/new/choose): As a last resort, you can open a new *Question* issue on GitHub if the answer could not be found using the other channels. Just remember: the more info you provide the more chances you'll have to get an accurate answer.
* [Software Problem Report](https://github.com/arendst/Tasmota/issues/new?template=Bug_report.md): For reporting problems of Tasmota Software.
## Contribute
You can contribute to Tasmota by
- providing Pull Requests (Features, Proof of Concepts, Language files or Fixes)
- testing new released features and report issues
- donating to acquire hardware for testing and implementing or out of gratitude
- contributing missing [documentation](https://tasmota.github.io/docs) for features and devices
- Providing Pull Requests (Features, Proof of Concepts, Language files or Fixes)
- Testing new released features and report issues
- Donating to acquire hardware for testing and implementing or out of gratitude
- Contributing missing [documentation](https://tasmota.github.io/docs) for features and devices
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota)

View File

@ -30,7 +30,7 @@ Support of Core versions before 2.7.1 has been removed.
## Support of TLS
To save resources when TLS is enabled mDNS needs to be disabled. In addition to TLS using fingerprints now also user supplied CA certs and AWS IoT is supported. Read [full documentation](https://tasmota.github.io/docs/AWS-IoT)
In addition to TLS using fingerprints now also user supplied CA certs and AWS IoT is supported. Read [full documentation](https://tasmota.github.io/docs/AWS-IoT)
## Initial configuration tools
@ -56,56 +56,11 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
[Complete list](BUILDS.md) of available feature and sensors.
## Changelog v9.1.0.2
## Changelog v9.2.0.1
### Added
- Command ``SetOption115 1`` to enable ESP32 MiBle
- Command ``SetOption116 1`` to disable auto-query of zigbee light devices (avoids network storms with large groups)
- Command ``RfProtocol`` to control RcSwitch receive protocols by BBBits (#10063)
- Commands ``TuyaRGB``, ``TuyaEnum`` and ``TuyaEnumList`` (#9769)
- Zigbee command ``ZbInfo`` and prepare support for EEPROM
- Zigbee command ``ZbLeave`` to unpair a device
- Zigbee support for Mi Door and Contact (#9759)
- Zigbee alarm persistence (#9785)
- Zigbee persistence of device/sensor data in EEPROM (only ZBBridge)
- Zigbee better support for Tuya Protocol (#10074)
- TyuaMcu update 2/3 by Federico Leoni (#10004)
- Support for additional EZO sensors by Christopher Tremblay
- Support for AS608 optical and R503 capacitive fingerprint sensor
- Support for Shelly Dimmer 1 and 2 by James Turton (#9854)
- Support for common anode sevenseg displays by adding ``#define USE_DISPLAY_SEVENSEG_COMMON_ANODE`` by Ken Sanislo (#9963)
- Support for multiple WeMo devices by Magic73 (#9208)
- Support for SPI connected MFRC522 13.56MHz rfid card reader (#9916)
- KNX read reply for Power (#9236, #9891)
- Fallback NTP server from x.pool.ntp.org if no ntpservers are configured
- Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970)
- Letsencrypt R3 in addition to X3 CA (#10086)
### Breaking Changed
- KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888)
### Changed
- Core library from v2.7.4.5 to v2.7.4.9
- IRremoteESP8266 library from v2.7.12 to v2.7.13
- Shelly Dimmer 1 and 2 stm32 firmware from v51.4 to v51.5
- mDNS has been disabled from all pre-compiled binaries to allow new features
- Platformio compiler option `no target align` enabled (#9749)
- Sonoff L1 color up scaling and color margin detection (#9545)
- MQTT Wifi connection timeout from 5000 to 200 mSec (#9886)
- Force bigger Thunk Stack if 4K RSA even without EC ciphers (#10075)
- Milliseconds to console output (#10152)
- Support for P9813 RGB Led MOSFET controller (#10104)
### Fixed
- Command ``gpio`` using non-indexed functions regression from v9.1.0 (#9962)
- NTP fallback server functionality (#9739)
- Telegram group chatid not supported (#9831)
- KNX buttons, switches and sensors detection regression from v9.1.0 (#9811)
- KNX ESP32 UDP mulicastpackage (#9811)
- GUI MqttUser and MqttPassword updates when TLS is compiled in (#9825)
- ESP32 TasmotaClient firmware upgrade (#9218)
- Reset to defaults after 6 hours of DeepSleep (#9993)
- Backlog timing wraparound (#9995)
- First LED in addressable string does not fade when using scheme (#10088)
- Improved Opentherm error handling (#10055)
### Removed
- Version compatibility check
- PN532 define USE_PN532_CAUSE_EVENTS replaced by generic rule trigger `on pn532#uid=`
- Redesign syslog and mqttlog using log buffer (#10164)
- Shelly Dimmer power on state (#10154, #10182)

View File

@ -399,6 +399,7 @@ void json_unescape(char* string) {
c = string[++i];
switch (c) {
case 0:
string[outlength++] = 0;
return; // end of stream
case '\"':
case '/':
@ -427,7 +428,10 @@ void json_unescape(char* string) {
uint32_t hexval = 0;
for (uint32_t j = 0; j < 4; ++j) {
char val = string[++i];
if (0 == val) { return; } // we reached end of string
if (0 == val) {
string[outlength++] = 0;
return; // we reached end of string
}
uint32_t uival = 0;
if ((val >= 'a') && (val <= 'f'))
uival = 10 + (val - 'a');
@ -450,4 +454,5 @@ void json_unescape(char* string) {
string[outlength++] = c;
}
}
string[outlength++] = 0;
}

View File

@ -60,6 +60,15 @@
#define ILI9341_2_HWSPI
#endif
#if defined (ILI9341_2_HWSPI)
#define SPI_BEGIN_TRANSACTION() if (_hwspi) spi2->beginTransaction(sspi2)
#define SPI_END_TRANSACTION() if (_hwspi) spi2->endTransaction()
#else
#define SPI_BEGIN_TRANSACTION() (void)
#define SPI_END_TRANSACTION() (void)
#endif
const uint16_t ili9341_2_colors[]={ILI9341_2_BLACK,ILI9341_2_WHITE,ILI9341_2_RED,ILI9341_2_GREEN,ILI9341_2_BLUE,ILI9341_2_CYAN,ILI9341_2_MAGENTA,\
ILI9341_2_YELLOW,ILI9341_2_NAVY,ILI9341_2_DARKGREEN,ILI9341_2_DARKCYAN,ILI9341_2_MAROON,ILI9341_2_PURPLE,ILI9341_2_OLIVE,\
@ -99,6 +108,32 @@ static const uint8_t PROGMEM ili9341_2_initcmd[] = {
0x00 // End of list
};
static const uint8_t PROGMEM ili9342_initcmd[] = {
0xEF, 3, 0x03, 0x80, 0x02,
0xCF, 3, 0x00, 0xC1, 0x30,
0xED, 4, 0x64, 0x03, 0x12, 0x81,
0xE8, 3, 0x85, 0x00, 0x78,
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
0xF7, 1, 0x20,
0xEA, 2, 0x00, 0x00,
ILI9341_2_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
ILI9341_2_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
ILI9341_2_VMCTR1 , 2, 0x2B, 0x2B, // 0x3e, 0x28, // VCM control
ILI9341_2_VMCTR2 , 1, 0xC0, // VCM control2
ILI9341_2_MADCTL , 1, 0x48, // Memory Access Control
ILI9341_2_VSCRSADD, 1, 0x00, // Vertical scroll zero
ILI9341_2_PIXFMT , 1, 0x55,
ILI9341_2_FRMCTR1 , 2, 0x00, 0x1B,
ILI9341_2_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
0xF2, 1, 0x00, // 3Gamma Function Disable
ILI9341_2_GAMMASET , 1, 0x01, // Gamma curve selected
ILI9341_2_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
ILI9341_2_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
ILI9341_2_INVON , 0x80,
ILI9341_2_SLPOUT , 0x80, // Exit Sleep
ILI9341_2_DISPON , 0x80, // Display on
0x00 // End of list
};
ILI9341_2::ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t res, int8_t dc, int8_t bp) : Renderer(ILI9341_2_TFTWIDTH, ILI9341_2_TFTHEIGHT) {
_cs = cs;
@ -108,7 +143,16 @@ ILI9341_2::ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t re
_res = res;
_dc = dc;
_bp = bp;
_hwspi = 0;
_hwspi = 1;
}
// special init for ILI9342
ILI9341_2::ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp) : Renderer(ILI9341_2_TFTWIDTH, ILI9341_2_TFTHEIGHT) {
_cs = cs;
_res = res;
_dc = dc;
_bp = bp;
_hwspi = 2;
}
#define ILI9341_2_CS_LOW digitalWrite( _cs, LOW);
@ -128,12 +172,25 @@ void ILI9341_2::writecmd(uint8_t d) {
void ILI9341_2::init(uint16_t width, uint16_t height) {
//sspi2 = SPISettings(2500000, MSBFIRST, SPI_MODE3);
if (_hwspi==2) {
iwidth=ILI9341_2_TFTWIDTH;
iheight=ILI9341_2_TFTHEIGHT;
} else {
iwidth=ILI9341_2_TFTHEIGHT;
iheight=ILI9341_2_TFTWIDTH;
}
#ifdef ILI9341_2_HWSPI
sspi2 = SPISettings(40000000, MSBFIRST, SPI_MODE0);
if (_hwspi==2) {
spi2=&SPI;
} else {
spi2 = new SPIClass(HSPI);
spi2->setDataMode(SPI_MODE3);
spi2->setBitOrder(MSBFIRST);
spi2->setFrequency(40000000);
spi2->begin(_sclk, _miso, _mosi, -1);
}
#else
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi,HIGH);
@ -144,13 +201,31 @@ void ILI9341_2::init(uint16_t width, uint16_t height) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs,HIGH);
pinMode(_dc, OUTPUT);
digitalWrite(_dc,HIGH);
if (_bp>=0) {
pinMode(_bp, OUTPUT);
digitalWrite(_bp,HIGH);
pinMode(_res, OUTPUT);
digitalWrite(_res,HIGH);
}
if (_res>=0) {
pinMode(_res, OUTPUT);
digitalWrite(_res, HIGH);
delay(100);
digitalWrite(_res, LOW);
delay(100);
digitalWrite(_res, HIGH);
delay(200);
} else {
SPI_BEGIN_TRANSACTION();
ILI9341_2_CS_LOW
writecmd(ILI9341_2_SWRESET); // software reset
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
delay(150);
}
if (_bp>=0) {
#ifdef ILI9341_2_DIMMER
@ -162,16 +237,16 @@ void ILI9341_2::init(uint16_t width, uint16_t height) {
#endif
}
pinMode(_res, OUTPUT);
digitalWrite(_res, HIGH);
delay(100);
digitalWrite(_res, LOW);
delay(100);
digitalWrite(_res, HIGH);
delay(200);
uint8_t cmd, x, numArgs;
const uint8_t *addr = ili9341_2_initcmd;
const uint8_t *addr;
if (_hwspi<2) {
addr = ili9341_2_initcmd;
} else {
addr = ili9342_initcmd;
}
SPI_BEGIN_TRANSACTION();
while ((cmd = pgm_read_byte(addr++)) > 0) {
ILI9341_2_CS_LOW
@ -188,11 +263,15 @@ void ILI9341_2::init(uint16_t width, uint16_t height) {
ILI9341_2_CS_HIGH
if(x & 0x80) delay(120);
}
SPI_END_TRANSACTION();
// endWrite();
}
void ILI9341_2::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
// SPI_BEGIN_TRANSACTION();
// writecmd(ILI9341_2_INVOFF);
// SPI_END_TRANSACTION();
setRotation(rot);
setTextFont(font&3);
setTextSize(size&7);
@ -201,9 +280,37 @@ void ILI9341_2::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
fillScreen(ILI9341_2_BLACK);
}
void ILI9341_2::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
void ILI9341_2::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
if (!x0 && !y0 && !x1 && !y1) {
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
} else {
ILI9341_2_CS_LOW
SPI_BEGIN_TRANSACTION();
setAddrWindow_int(x0,y0,x1-x0,y1-y0);
}
}
void ILI9341_2::pushColors(uint16_t *data, uint8_t len, boolean first) {
uint16_t color;
while (len--) {
color = *data++;
#ifdef ILI9341_2_HWSPI
spi2->write16(color);
#else
spiwrite16(color);
#endif
}
}
void ILI9341_2::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
writecmd(ILI9341_2_CASET); // Column addr set
#ifdef ILI9341_2_HWSPI
spi2->write32(xa);
@ -218,6 +325,8 @@ void ILI9341_2::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
spiwrite32(ya);
#endif
writecmd(ILI9341_2_RAMWR); // write to RAM
}
void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) {
@ -227,7 +336,10 @@ void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) {
ILI9341_2_CS_LOW
setAddrWindow(x,y,1,1);
SPI_BEGIN_TRANSACTION();
setAddrWindow_int(x,y,1,1);
#ifdef ILI9341_2_HWSPI
spi2->write16(color);
@ -236,39 +348,80 @@ void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) {
#endif
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
}
void ILI9341_2::setRotation(uint8_t m) {
if (_hwspi<2) {
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
m = (MADCTL_2_MX | MADCTL_2_BGR);
_width = ILI9341_2_TFTWIDTH;
_height = ILI9341_2_TFTHEIGHT;
_width = iwidth;
_height = iheight;
break;
case 1:
m = (MADCTL_2_MV | MADCTL_2_BGR);
_width = ILI9341_2_TFTHEIGHT;
_height = ILI9341_2_TFTWIDTH;
_width = iheight;
_height = iwidth;
break;
case 2:
m = (MADCTL_2_MY | MADCTL_2_BGR);
_width = ILI9341_2_TFTWIDTH;
_height = ILI9341_2_TFTHEIGHT;
_width = iwidth;
_height = iheight;
break;
case 3:
m = (MADCTL_2_MX | MADCTL_2_MY | MADCTL_2_MV | MADCTL_2_BGR);
_width = ILI9341_2_TFTHEIGHT;
_height = ILI9341_2_TFTWIDTH;
_width = iheight;
_height = iwidth;
break;
}
} else {
#define MADCTL_MY 0x80 ///< Bottom to top
#define MADCTL_MX 0x40 ///< Right to left
#define MADCTL_MV 0x20 ///< Reverse Mode
#define MADCTL_ML 0x10 ///< LCD refresh Bottom to top
#define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order
#define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order
#define MADCTL_MH 0x04 ///< LCD refresh right to left
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
m = (MADCTL_BGR);
_width = iwidth;
_height = iheight;
break;
case 1:
m = (MADCTL_MV | MADCTL_BGR);
_width = iheight;
_height = iwidth;
break;
case 2:
m = (MADCTL_MY | MADCTL_BGR);
_width = iwidth;
_height = iheight;
break;
case 3:
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
_width = iheight;
_height = iwidth;
break;
}
}
SPI_BEGIN_TRANSACTION();
ILI9341_2_CS_LOW
writecmd(ILI9341_2_MADCTL);
spiwrite(m);
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
}
void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
// Rudimentary clipping
@ -277,7 +430,10 @@ void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
ILI9341_2_CS_LOW
setAddrWindow(x, y, 1, h);
SPI_BEGIN_TRANSACTION();
setAddrWindow_int(x, y, 1, h);
while (h--) {
#ifdef ILI9341_2_HWSPI
@ -289,6 +445,7 @@ void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
}
void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
@ -299,7 +456,10 @@ void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
ILI9341_2_CS_LOW
setAddrWindow(x, y, w, 1);
SPI_BEGIN_TRANSACTION();
setAddrWindow_int(x, y, w, 1);
while (w--) {
#ifdef ILI9341_2_HWSPI
@ -310,6 +470,8 @@ void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
}
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
}
void ILI9341_2::fillScreen(uint16_t color) {
@ -326,7 +488,9 @@ void ILI9341_2::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t co
ILI9341_2_CS_LOW
setAddrWindow(x, y, w-1, h-1);
SPI_BEGIN_TRANSACTION();
setAddrWindow_int(x, y, w, h);
for (y=h; y>0; y--) {
for (x=w; x>0; x--) {
@ -338,11 +502,26 @@ void ILI9341_2::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t co
}
}
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
}
void ili9342_bpwr(uint8_t on);
void ILI9341_2::DisplayOnff(int8_t on) {
if (_hwspi==2) {
ili9342_bpwr(on);
}
if (on) {
writecmd(ILI9341_2_DISPON); //Display on
SPI_BEGIN_TRANSACTION();
ILI9341_2_CS_LOW
writecmd(ILI9341_2_DISPON);
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
if (_bp>=0) {
#ifdef ILI9341_2_DIMMER
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
@ -351,7 +530,11 @@ void ILI9341_2::DisplayOnff(int8_t on) {
#endif
}
} else {
SPI_BEGIN_TRANSACTION();
ILI9341_2_CS_LOW
writecmd(ILI9341_2_DISPOFF);
ILI9341_2_CS_HIGH
SPI_END_TRANSACTION();
if (_bp>=0) {
#ifdef ILI9341_2_DIMMER
ledcWrite(ESP32_PWM_CHANNEL,0);
@ -362,13 +545,21 @@ void ILI9341_2::DisplayOnff(int8_t on) {
}
}
void ili9342_dimm(uint8_t dim);
// dimmer 0-100
void ILI9341_2::dim(uint8_t dim) {
dimmer = dim;
if (dimmer>15) dimmer=15;
dimmer=((float)dimmer/15.0)*255.0;
#ifdef ESP32
if (_bp>=0) {
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
} else {
if (_hwspi==2) {
ili9342_dimm(dim);
}
}
#endif
}

View File

@ -23,7 +23,7 @@
#include <SPI.h>
#define ILI9341_2_TFTWIDTH 320
#define ILI9341_2_TFTHEIGHT 480
#define ILI9341_2_TFTHEIGHT 240
#define ILI9341_2_NOP 0x00 ///< No-op register
#define ILI9341_2_SWRESET 0x01 ///< Software reset register
@ -116,6 +116,7 @@ class ILI9341_2 : public Renderer {
public:
ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t res, int8_t dc, int8_t bp);
ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp);
void init(uint16_t width, uint16_t height);
/*
@ -148,7 +149,8 @@ class ILI9341_2 : public Renderer {
SPIClass *spi2;
SPISettings sspi2;
void writecmd(uint8_t d);
void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void setAddrWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void DisplayOnff(int8_t on);
void setRotation(uint8_t m);
@ -158,7 +160,7 @@ class ILI9341_2 : public Renderer {
void fillScreen(uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void dim(uint8_t dim);
void pushColors(uint16_t *data, uint8_t len, boolean first);
void spiwrite(uint8_t c);
void spiwrite16(uint16_t c);
@ -174,6 +176,8 @@ class ILI9341_2 : public Renderer {
int8_t _dc;
int8_t _bp;
int8_t _hwspi;
uint16_t iwidth;
uint16_t iheight;
};
#endif

View File

@ -0,0 +1,614 @@
#include "AXP192.h"
//#define AXP192_DEBUG
AXP192::AXP192()
{
}
void AXP192::begin(void)
{
Wire1.begin(21, 22);
Wire1.setClock(400000);
//AXP192 30H
Write1Byte(0x30, (Read8bit(0x30) & 0x04) | 0X02);
#ifdef AXP192_DEBUG
Serial.printf("axp: vbus limit off\n");
#endif
//AXP192 GPIO1:OD OUTPUT
Write1Byte(0x92, Read8bit(0x92) & 0xf8);
#ifdef AXP192_DEBUG
Serial.printf("axp: gpio1 init\n");
#endif
//AXP192 GPIO2:OD OUTPUT
Write1Byte(0x93, Read8bit(0x93) & 0xf8);
#ifdef AXP192_DEBUG
Serial.printf("axp: gpio2 init\n");
#endif
//AXP192 RTC CHG
Write1Byte(0x35, (Read8bit(0x35) & 0x1c) | 0xa2);
#ifdef AXP192_DEBUG
Serial.printf("axp: rtc battery charging enabled\n");
#endif
SetESPVoltage(3350);
#ifdef AXP192_DEBUG
Serial.printf("axp: esp32 power voltage was set to 3.35v\n");
#endif
SetLcdVoltage(2800);
#ifdef AXP192_DEBUG
Serial.printf("axp: lcd backlight voltage was set to 2.80v\n");
#endif
SetLDOVoltage(2, 3300); //Periph power voltage preset (LCD_logic, SD card)
#ifdef AXP192_DEBUG
Serial.printf("axp: lcd logic and sdcard voltage preset to 3.3v\n");
#endif
SetLDOVoltage(3, 2000); //Vibrator power voltage preset
#ifdef AXP192_DEBUG
Serial.printf("axp: vibrator voltage preset to 2v\n");
#endif
SetLDOEnable(2, true);
SetDCDC3(true); // LCD backlight
SetLed(true);
SetCHGCurrent(kCHG_100mA);
//SetAxpPriphPower(1);
//Serial.printf("axp: lcd_logic and sdcard power enabled\n\n");
//pinMode(39, INPUT_PULLUP);
//AXP192 GPIO4
Write1Byte(0X95, (Read8bit(0x95) & 0x72) | 0X84);
Write1Byte(0X36, 0X4C);
Write1Byte(0x82,0xff);
SetLCDRSet(0);
delay(100);
SetLCDRSet(1);
delay(100);
// I2C_WriteByteDataAt(0X15,0XFE,0XFF);
// bus power mode_output
SetBusPowerMode(0);
}
void AXP192::Write1Byte(uint8_t Addr, uint8_t Data)
{
Wire1.beginTransmission(0x34);
Wire1.write(Addr);
Wire1.write(Data);
Wire1.endTransmission();
}
uint8_t AXP192::Read8bit(uint8_t Addr)
{
Wire1.beginTransmission(0x34);
Wire1.write(Addr);
Wire1.endTransmission();
Wire1.requestFrom(0x34, 1);
return Wire1.read();
}
uint16_t AXP192::Read12Bit(uint8_t Addr)
{
uint16_t Data = 0;
uint8_t buf[2];
ReadBuff(Addr, 2, buf);
Data = ((buf[0] << 4) + buf[1]); //
return Data;
}
uint16_t AXP192::Read13Bit(uint8_t Addr)
{
uint16_t Data = 0;
uint8_t buf[2];
ReadBuff(Addr, 2, buf);
Data = ((buf[0] << 5) + buf[1]); //
return Data;
}
uint16_t AXP192::Read16bit(uint8_t Addr)
{
uint16_t ReData = 0;
Wire1.beginTransmission(0x34);
Wire1.write(Addr);
Wire1.endTransmission();
Wire1.requestFrom(0x34, 2);
for (int i = 0; i < 2; i++)
{
ReData <<= 8;
ReData |= Wire1.read();
}
return ReData;
}
uint32_t AXP192::Read24bit(uint8_t Addr)
{
uint32_t ReData = 0;
Wire1.beginTransmission(0x34);
Wire1.write(Addr);
Wire1.endTransmission();
Wire1.requestFrom(0x34, 3);
for (int i = 0; i < 3; i++)
{
ReData <<= 8;
ReData |= Wire1.read();
}
return ReData;
}
uint32_t AXP192::Read32bit(uint8_t Addr)
{
uint32_t ReData = 0;
Wire1.beginTransmission(0x34);
Wire1.write(Addr);
Wire1.endTransmission();
Wire1.requestFrom(0x34, 2);
for (int i = 0; i < 4; i++)
{
ReData <<= 8;
ReData |= Wire1.read();
}
return ReData;
}
void AXP192::ReadBuff(uint8_t Addr, uint8_t Size, uint8_t *Buff)
{
Wire1.beginTransmission(0x34);
Wire1.write(Addr);
Wire1.endTransmission();
Wire1.requestFrom(0x34, (int)Size);
for (int i = 0; i < Size; i++)
{
*(Buff + i) = Wire1.read();
}
}
void AXP192::ScreenBreath(uint8_t brightness)
{
if (brightness > 12)
{
brightness = 12;
}
uint8_t buf = Read8bit(0x28);
Write1Byte(0x28, ((buf & 0x0f) | (brightness << 4)));
}
bool AXP192::GetBatState()
{
if (Read8bit(0x01) | 0x20)
return true;
else
return false;
}
//---------coulombcounter_from_here---------
//enable: void EnableCoulombcounter(void);
//disable: void DisableCOulombcounter(void);
//stop: void StopCoulombcounter(void);
//clear: void ClearCoulombcounter(void);
//get charge data: uint32_t GetCoulombchargeData(void);
//get discharge data: uint32_t GetCoulombdischargeData(void);
//get coulomb val affter calculation: float GetCoulombData(void);
//------------------------------------------
void AXP192::EnableCoulombcounter(void)
{
Write1Byte(0xB8, 0x80);
}
void AXP192::DisableCoulombcounter(void)
{
Write1Byte(0xB8, 0x00);
}
void AXP192::StopCoulombcounter(void)
{
Write1Byte(0xB8, 0xC0);
}
void AXP192::ClearCoulombcounter(void)
{
Write1Byte(0xB8, 0xA0);
}
uint32_t AXP192::GetCoulombchargeData(void)
{
return Read32bit(0xB0);
}
uint32_t AXP192::GetCoulombdischargeData(void)
{
return Read32bit(0xB4);
}
float AXP192::GetCoulombData(void)
{
uint32_t coin = 0;
uint32_t coout = 0;
coin = GetCoulombchargeData();
coout = GetCoulombdischargeData();
//c = 65536 * current_LSB * (coin - coout) / 3600 / ADC rate
//Adc rate can be read from 84H ,change this variable if you change the ADC reate
float ccc = 65536 * 0.5 * (coin - coout) / 3600.0 / 25.0;
return ccc;
}
// Cut all power, except for LDO1 (RTC)
void AXP192::PowerOff(void)
{
Write1Byte(0x32, Read8bit(0x32) | 0b10000000);
}
void AXP192::SetAdcState(bool state)
{
// Enable / Disable all ADCs
Write1Byte(0x82, state ? 0xff : 0x00);
}
void AXP192::PrepareToSleep(void)
{
// Disable ADCs
SetAdcState(false);
// Turn LED off
SetLed(false);
// Turn LCD backlight off
SetDCDC3(false);
}
void AXP192::RestoreFromLightSleep(void)
{
// Turn LCD backlight on
SetDCDC3(true);
// Turn LED on
SetLed(true);
// Enable ADCs
SetAdcState(true);
}
uint8_t AXP192::GetWarningLeve(void)
{
Wire1.beginTransmission(0x34);
Wire1.write(0x47);
Wire1.endTransmission();
Wire1.requestFrom(0x34, 1);
uint8_t buf = Wire1.read();
return (buf & 0x01);
}
// -- sleep
void AXP192::DeepSleep(uint64_t time_in_us)
{
PrepareToSleep();
if (time_in_us > 0)
{
esp_sleep_enable_timer_wakeup(time_in_us);
}
else
{
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
}
(time_in_us == 0) ? esp_deep_sleep_start() : esp_deep_sleep(time_in_us);
// Never reached - after deep sleep ESP32 restarts
}
void AXP192::LightSleep(uint64_t time_in_us)
{
PrepareToSleep();
if (time_in_us > 0)
{
esp_sleep_enable_timer_wakeup(time_in_us);
}
else
{
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
}
esp_light_sleep_start();
RestoreFromLightSleep();
}
uint8_t AXP192::GetWarningLevel(void)
{
return Read8bit(0x47) & 0x01;
}
float AXP192::GetBatVoltage()
{
float ADCLSB = 1.1 / 1000.0;
uint16_t ReData = Read12Bit(0x78);
return ReData * ADCLSB;
}
float AXP192::GetBatCurrent()
{
float ADCLSB = 0.5;
uint16_t CurrentIn = Read13Bit(0x7A);
uint16_t CurrentOut = Read13Bit(0x7C);
return (CurrentIn - CurrentOut) * ADCLSB;
}
float AXP192::GetVinVoltage()
{
float ADCLSB = 1.7 / 1000.0;
uint16_t ReData = Read12Bit(0x56);
return ReData * ADCLSB;
}
float AXP192::GetVinCurrent()
{
float ADCLSB = 0.625;
uint16_t ReData = Read12Bit(0x58);
return ReData * ADCLSB;
}
float AXP192::GetVBusVoltage()
{
float ADCLSB = 1.7 / 1000.0;
uint16_t ReData = Read12Bit(0x5A);
return ReData * ADCLSB;
}
float AXP192::GetVBusCurrent()
{
float ADCLSB = 0.375;
uint16_t ReData = Read12Bit(0x5C);
return ReData * ADCLSB;
}
float AXP192::GetTempInAXP192()
{
float ADCLSB = 0.1;
const float OFFSET_DEG_C = -144.7;
uint16_t ReData = Read12Bit(0x5E);
return OFFSET_DEG_C + ReData * ADCLSB;
}
float AXP192::GetBatPower()
{
float VoltageLSB = 1.1;
float CurrentLCS = 0.5;
uint32_t ReData = Read24bit(0x70);
return VoltageLSB * CurrentLCS * ReData / 1000.0;
}
float AXP192::GetBatChargeCurrent()
{
float ADCLSB = 0.5;
uint16_t ReData = Read12Bit(0x7A);
return ReData * ADCLSB;
}
float AXP192::GetAPSVoltage()
{
float ADCLSB = 1.4 / 1000.0;
uint16_t ReData = Read12Bit(0x7E);
return ReData * ADCLSB;
}
float AXP192::GetBatCoulombInput()
{
uint32_t ReData = Read32bit(0xB0);
return ReData * 65536 * 0.5 / 3600 / 25.0;
}
float AXP192::GetBatCoulombOut()
{
uint32_t ReData = Read32bit(0xB4);
return ReData * 65536 * 0.5 / 3600 / 25.0;
}
void AXP192::SetCoulombClear()
{
Write1Byte(0xB8, 0x20);
}
void AXP192::SetLDO2(bool State)
{
uint8_t buf = Read8bit(0x12);
if (State == true)
buf = (1 << 2) | buf;
else
buf = ~(1 << 2) & buf;
Write1Byte(0x12, buf);
}
void AXP192::SetDCDC3(bool State)
{
uint8_t buf = Read8bit(0x12);
if (State == true)
buf = (1 << 1) | buf;
else
buf = ~(1 << 1) & buf;
Write1Byte(0x12, buf);
}
uint8_t AXP192::AXPInState()
{
return Read8bit(0x00);
}
bool AXP192::isACIN()
{
return ( Read8bit(0x00) & 0x80 ) ? true : false;
}
bool AXP192::isCharging()
{
return ( Read8bit(0x00) & 0x04 ) ? true : false;
}
bool AXP192::isVBUS()
{
return ( Read8bit(0x00) & 0x20 ) ? true : false;
}
void AXP192::SetLDOVoltage(uint8_t number, uint16_t voltage)
{
voltage = (voltage > 3300) ? 15 : (voltage / 100) - 18;
switch (number)
{
//uint8_t reg, data;
case 2:
Write1Byte(0x28, (Read8bit(0x28) & 0X0F) | (voltage << 4));
break;
case 3:
Write1Byte(0x28, (Read8bit(0x28) & 0XF0) | voltage);
break;
}
}
void AXP192::SetDCVoltage(uint8_t number, uint16_t voltage)
{
uint8_t addr;
if (number > 2)
return;
voltage = (voltage < 700) ? 0 : (voltage - 700) / 25;
switch (number)
{
case 0:
addr = 0x26;
break;
case 1:
addr = 0x25;
break;
case 2:
addr = 0x27;
break;
}
Write1Byte(addr, (Read8bit(addr) & 0X80) | (voltage & 0X7F));
}
void AXP192::SetESPVoltage(uint16_t voltage)
{
if (voltage >= 3000 && voltage <= 3400)
{
SetDCVoltage(0, voltage);
}
}
void AXP192::SetLcdVoltage(uint16_t voltage)
{
if (voltage >= 2500 && voltage <= 3300)
{
SetDCVoltage(2, voltage);
}
}
void AXP192::SetLDOEnable(uint8_t number, bool state)
{
uint8_t mark = 0x01;
if ((number < 2) || (number > 3))
return;
mark <<= number;
if (state)
{
Write1Byte(0x12, (Read8bit(0x12) | mark));
}
else
{
Write1Byte(0x12, (Read8bit(0x12) & (~mark)));
}
}
void AXP192::SetLCDRSet(bool state)
{
uint8_t reg_addr = 0x96;
uint8_t gpio_bit = 0x02;
uint8_t data;
data = Read8bit(reg_addr);
if (state)
{
data |= gpio_bit;
}
else
{
data &= ~gpio_bit;
}
Write1Byte(reg_addr, data);
}
void AXP192::SetBusPowerMode(uint8_t state)
{
uint8_t data;
if (state == 0)
{
data = Read8bit(0x91);
Write1Byte(0x91, (data & 0X0F) | 0XF0);
data = Read8bit(0x90);
Write1Byte(0x90, (data & 0XF8) | 0X02); //set GPIO0 to LDO OUTPUT , pullup N_VBUSEN to disable supply from BUS_5V
data = Read8bit(0x91);
data = Read8bit(0x12); //read reg 0x12
Write1Byte(0x12, data | 0x40); //set EXTEN to enable 5v boost
}
else
{
data = Read8bit(0x12); //read reg 0x10
Write1Byte(0x12, data & 0XBF); //set EXTEN to disable 5v boost
//delay(2000);
data = Read8bit(0x90);
Write1Byte(0x90, (data & 0xF8) | 0X01); //set GPIO0 to float , using enternal pulldown resistor to enable supply from BUS_5VS
}
}
void AXP192::SetLed(uint8_t state)
{
uint8_t reg_addr=0x94;
uint8_t data;
data=Read8bit(reg_addr);
if(state)
{
data=data&0XFD;
}
else
{
data|=0X02;
}
Write1Byte(reg_addr,data);
}
//set led state(GPIO high active,set 1 to enable amplifier)
void AXP192::SetSpkEnable(uint8_t state)
{
uint8_t reg_addr=0x94;
uint8_t gpio_bit=0x04;
uint8_t data;
data=Read8bit(reg_addr);
if(state)
{
data|=gpio_bit;
}
else
{
data&=~gpio_bit;
}
Write1Byte(reg_addr,data);
}
void AXP192::SetCHGCurrent(uint8_t state)
{
uint8_t data = Read8bit(0x33);
data &= 0xf0;
data = data | ( state & 0x0f );
Write1Byte(0x33,data);
}

View File

@ -0,0 +1,106 @@
#ifndef __AXP192_H__
#define __AXP192_H__
#include <Wire.h>
#include <Arduino.h>
#define SLEEP_MSEC(us) (((uint64_t)us) * 1000L)
#define SLEEP_SEC(us) (((uint64_t)us) * 1000000L)
#define SLEEP_MIN(us) (((uint64_t)us) * 60L * 1000000L)
#define SLEEP_HR(us) (((uint64_t)us) * 60L * 60L * 1000000L)
#define AXP_ADDR 0X34
#define PowerOff(x) SetSleep(x)
class AXP192 {
public:
enum CHGCurrent{
kCHG_100mA = 0,
kCHG_190mA,
kCHG_280mA,
kCHG_360mA,
kCHG_450mA,
kCHG_550mA,
kCHG_630mA,
kCHG_700mA,
kCHG_780mA,
kCHG_880mA,
kCHG_960mA,
kCHG_1000mA,
kCHG_1080mA,
kCHG_1160mA,
kCHG_1240mA,
kCHG_1320mA,
};
AXP192();
void begin(void);
void ScreenBreath(uint8_t brightness);
bool GetBatState();
void EnableCoulombcounter(void);
void DisableCoulombcounter(void);
void StopCoulombcounter(void);
void ClearCoulombcounter(void);
uint32_t GetCoulombchargeData(void);
uint32_t GetCoulombdischargeData(void);
float GetCoulombData(void);
void PowerOff(void);
void SetAdcState(bool state);
// -- sleep
void PrepareToSleep(void);
void RestoreFromLightSleep(void);
void DeepSleep(uint64_t time_in_us = 0);
void LightSleep(uint64_t time_in_us = 0);
uint8_t GetWarningLeve(void);
public:
// void SetChargeVoltage( uint8_t );
// void SetChargeCurrent( uint8_t );
float GetBatVoltage();
float GetBatCurrent();
float GetVinVoltage();
float GetVinCurrent();
float GetVBusVoltage();
float GetVBusCurrent();
float GetTempInAXP192();
float GetBatPower();
float GetBatChargeCurrent();
float GetAPSVoltage();
float GetBatCoulombInput();
float GetBatCoulombOut();
uint8_t GetWarningLevel(void);
void SetCoulombClear();
void SetLDO2( bool State );
void SetDCDC3( bool State );
uint8_t AXPInState();
bool isACIN();
bool isCharging();
bool isVBUS();
void SetLDOVoltage(uint8_t number , uint16_t voltage);
void SetDCVoltage(uint8_t number , uint16_t voltage);
void SetESPVoltage(uint16_t voltage);
void SetLcdVoltage(uint16_t voltage);
void SetLDOEnable( uint8_t number ,bool state );
void SetLCDRSet( bool state );
void SetBusPowerMode( uint8_t state );
void SetLed(uint8_t state);
void SetSpkEnable(uint8_t state);
void SetCHGCurrent(uint8_t state);
private:
void Write1Byte( uint8_t Addr , uint8_t Data );
uint8_t Read8bit( uint8_t Addr );
uint16_t Read12Bit( uint8_t Addr);
uint16_t Read13Bit( uint8_t Addr);
uint16_t Read16bit( uint8_t Addr );
uint32_t Read24bit( uint8_t Addr );
uint32_t Read32bit( uint8_t Addr );
void ReadBuff( uint8_t Addr , uint8_t Size , uint8_t *Buff );
};
#endif

View File

@ -0,0 +1,353 @@
#include "BM8563_RTC.h"
BM8563_RTC::BM8563_RTC()
{
}
void BM8563_RTC::begin(void)
{
Wire1.begin(21, 22);
WriteReg(0x00,0x00);
WriteReg(0x01,0x00);
WriteReg(0x0D,0x00);
}
void BM8563_RTC::WriteReg(uint8_t reg, uint8_t data)
{
Wire1.beginTransmission(RTC_ADRESS);
Wire1.write(reg);
Wire1.write(data);
Wire1.endTransmission();
}
uint8_t BM8563_RTC::ReadReg(uint8_t reg)
{
Wire1.beginTransmission(0x51);
Wire1.write(reg);
Wire1.endTransmission();
Wire1.requestFrom(0x51, 1);
return Wire1.read();
}
void BM8563_RTC::GetBm8563Time(void)
{
Wire1.beginTransmission(0x51);
Wire1.write(0x02);
Wire1.endTransmission();
Wire1.requestFrom(0x51, 7);
while (Wire1.available())
{
trdata[0] = Wire1.read();
trdata[1] = Wire1.read();
trdata[2] = Wire1.read();
trdata[3] = Wire1.read();
trdata[4] = Wire1.read();
trdata[5] = Wire1.read();
trdata[6] = Wire1.read();
}
DataMask();
Bcd2asc();
Str2Time();
}
void BM8563_RTC::Str2Time(void)
{
Second = (asc[0] - 0x30) * 10 + asc[1] - 0x30;
Minute = (asc[2] - 0x30) * 10 + asc[3] - 0x30;
Hour = (asc[4] - 0x30) * 10 + asc[5] - 0x30;
/*
uint8_t Hour;
uint8_t Week;
uint8_t Day;
uint8_t Month;
uint8_t Year;
*/
}
void BM8563_RTC::DataMask()
{
trdata[0] = trdata[0] & 0x7f; //秒
trdata[1] = trdata[1] & 0x7f; //分
trdata[2] = trdata[2] & 0x3f; //时
trdata[3] = trdata[3] & 0x3f; //日
trdata[4] = trdata[4] & 0x07; //星期
trdata[5] = trdata[5] & 0x1f; //月
trdata[6] = trdata[6] & 0xff; //年
}
/********************************************************************
void Bcd2asc(void)
bcd asc Lcd显示用
***********************************************************************/
void BM8563_RTC::Bcd2asc(void)
{
uint8_t i, j;
for (j = 0, i = 0; i < 7; i++)
{
asc[j++] = (trdata[i] & 0xf0) >> 4 | 0x30; /*格式为: 秒 分 时 日 月 星期 年 */
asc[j++] = (trdata[i] & 0x0f) | 0x30;
}
}
uint8_t BM8563_RTC::Bcd2ToByte(uint8_t Value)
{
uint8_t tmp = 0;
tmp = ((uint8_t)(Value & (uint8_t)0xF0) >> (uint8_t)0x4) * 10;
return (tmp + (Value & (uint8_t)0x0F));
}
uint8_t BM8563_RTC::ByteToBcd2(uint8_t Value)
{
uint8_t bcdhigh = 0;
while (Value >= 10)
{
bcdhigh++;
Value -= 10;
}
return ((uint8_t)(bcdhigh << 4) | Value);
}
void BM8563_RTC::GetTime(RTC_TimeTypeDef *RTC_TimeStruct)
{
//if()
uint8_t buf[3] = {0};
Wire1.beginTransmission(0x51);
Wire1.write(0x02);
Wire1.endTransmission();
Wire1.requestFrom(0x51, 3);
while (Wire1.available())
{
buf[0] = Wire1.read();
buf[1] = Wire1.read();
buf[2] = Wire1.read();
}
RTC_TimeStruct->Seconds = Bcd2ToByte(buf[0] & 0x7f); //秒
RTC_TimeStruct->Minutes = Bcd2ToByte(buf[1] & 0x7f); //分
RTC_TimeStruct->Hours = Bcd2ToByte(buf[2] & 0x3f); //时
}
void BM8563_RTC::SetTime(RTC_TimeTypeDef *RTC_TimeStruct)
{
if (RTC_TimeStruct == NULL)
return;
Wire1.beginTransmission(0x51);
Wire1.write(0x02);
Wire1.write(ByteToBcd2(RTC_TimeStruct->Seconds));
Wire1.write(ByteToBcd2(RTC_TimeStruct->Minutes));
Wire1.write(ByteToBcd2(RTC_TimeStruct->Hours));
Wire1.endTransmission();
}
void BM8563_RTC::GetDate(RTC_DateTypeDef *RTC_DateStruct)
{
uint8_t buf[4] = {0};
Wire1.beginTransmission(0x51);
Wire1.write(0x05);
Wire1.endTransmission();
Wire1.requestFrom(0x51, 4);
while (Wire1.available())
{
buf[0] = Wire1.read();
buf[1] = Wire1.read();
buf[2] = Wire1.read();
buf[3] = Wire1.read();
}
RTC_DateStruct->Date = Bcd2ToByte(buf[0] & 0x3f);
RTC_DateStruct->WeekDay = Bcd2ToByte(buf[1] & 0x07);
RTC_DateStruct->Month = Bcd2ToByte(buf[2] & 0x1f);
if (buf[2] & 0x80)
{
RTC_DateStruct->Year = 1900 + Bcd2ToByte(buf[3] & 0xff);
}
else
{
RTC_DateStruct->Year = 2000 + Bcd2ToByte(buf[3] & 0xff);
}
}
void BM8563_RTC::SetDate(RTC_DateTypeDef *RTC_DateStruct)
{
if (RTC_DateStruct == NULL)
return;
Wire1.beginTransmission(0x51);
Wire1.write(0x05);
Wire1.write(ByteToBcd2(RTC_DateStruct->Date));
Wire1.write(ByteToBcd2(RTC_DateStruct->WeekDay));
if (RTC_DateStruct->Year < 2000)
{
Wire1.write(ByteToBcd2(RTC_DateStruct->Month) | 0x80);
Wire1.write(ByteToBcd2((uint8_t)(RTC_DateStruct->Year % 100)));
}
else
{
/* code */
Wire1.write(ByteToBcd2(RTC_DateStruct->Month) | 0x00);
Wire1.write(ByteToBcd2((uint8_t)(RTC_DateStruct->Year % 100)));
}
Wire1.endTransmission();
}
int BM8563_RTC::SetAlarmIRQ(int afterSeconds)
{
uint8_t reg_value = 0;
reg_value = ReadReg(0x01);
if (afterSeconds < 0)
{
reg_value &= ~(1 << 0);
WriteReg(0x01, reg_value);
reg_value = 0x03;
WriteReg(0x0E, reg_value);
return -1;
}
uint8_t type_value = 2;
uint8_t div = 1;
if (afterSeconds > 255)
{
div = 60;
type_value = 0x83;
}
else
{
type_value = 0x82;
}
afterSeconds = (afterSeconds / div) & 0xFF;
WriteReg(0x0F, afterSeconds);
WriteReg(0x0E, type_value);
reg_value |= (1 << 0);
reg_value &= ~(1 << 7);
WriteReg(0x01, reg_value);
return afterSeconds * div;
}
int BM8563_RTC::SetAlarmIRQ(const RTC_TimeTypeDef &RTC_TimeStruct)
{
uint8_t irq_enable = false;
uint8_t out_buf[4] = {0x80, 0x80, 0x80, 0x80};
if (RTC_TimeStruct.Minutes >= 0)
{
irq_enable = true;
out_buf[0] = ByteToBcd2(RTC_TimeStruct.Minutes) & 0x7f;
}
if (RTC_TimeStruct.Hours >= 0)
{
irq_enable = true;
out_buf[1] = ByteToBcd2(RTC_TimeStruct.Hours) & 0x3f;
}
out_buf[2] = 0x00;
out_buf[3] = 0x00;
uint8_t reg_value = ReadReg(0x01);
if (irq_enable)
{
reg_value |= (1 << 1);
}
else
{
reg_value &= ~(1 << 1);
}
for (int i = 0; i < 4; i++)
{
WriteReg(0x09 + i, out_buf[i]);
}
WriteReg(0x01, reg_value);
return irq_enable ? 1 : 0;
}
int BM8563_RTC::SetAlarmIRQ(const RTC_DateTypeDef &RTC_DateStruct, const RTC_TimeTypeDef &RTC_TimeStruct)
{
uint8_t irq_enable = false;
uint8_t out_buf[4] = {0x80, 0x80, 0x80, 0x80};
if (RTC_TimeStruct.Minutes >= 0)
{
irq_enable = true;
out_buf[0] = ByteToBcd2(RTC_TimeStruct.Minutes) & 0x7f;
}
if (RTC_TimeStruct.Hours >= 0)
{
irq_enable = true;
out_buf[1] = ByteToBcd2(RTC_TimeStruct.Hours) & 0x3f;
}
if (RTC_DateStruct.Date >= 0)
{
irq_enable = true;
out_buf[2] = ByteToBcd2(RTC_DateStruct.Date) & 0x3f;
}
if (RTC_DateStruct.WeekDay >= 0)
{
irq_enable = true;
out_buf[3] = ByteToBcd2(RTC_DateStruct.WeekDay) & 0x07;
}
uint8_t reg_value = ReadReg(0x01);
if (irq_enable)
{
reg_value |= (1 << 1);
}
else
{
reg_value &= ~(1 << 1);
}
for (int i = 0; i < 4; i++)
{
WriteReg(0x09 + i, out_buf[i]);
}
WriteReg(0x01, reg_value);
return irq_enable ? 1 : 0;
}
void BM8563_RTC::clearIRQ()
{
uint8_t data = ReadReg(0x01);
WriteReg(0x01, data & 0xf3);
}
void BM8563_RTC::disableIRQ()
{
clearIRQ();
uint8_t data = ReadReg(0x01);
WriteReg(0x01, data & 0xfC);
}

View File

@ -0,0 +1,76 @@
#ifndef __RTC_H__
#define __RTC_H__
#include <Wire.h>
#define RTC_ADRESS 0x51
typedef struct
{
uint8_t Hours;
uint8_t Minutes;
uint8_t Seconds;
}RTC_TimeTypeDef;
typedef struct
{
uint8_t WeekDay;
uint8_t Month;
uint8_t Date;
uint16_t Year;
}RTC_DateTypeDef;
class BM8563_RTC {
public:
BM8563_RTC();
void begin(void);
void GetBm8563Time(void);
void SetTime(RTC_TimeTypeDef* RTC_TimeStruct);
void SetDate(RTC_DateTypeDef* RTC_DateStruct);
void GetTime(RTC_TimeTypeDef* RTC_TimeStruct);
void GetDate(RTC_DateTypeDef* RTC_DateStruct);
int SetAlarmIRQ(int afterSeconds);
int SetAlarmIRQ( const RTC_TimeTypeDef &RTC_TimeStruct);
int SetAlarmIRQ( const RTC_DateTypeDef &RTC_DateStruct, const RTC_TimeTypeDef &RTC_TimeStruct);
void clearIRQ();
void disableIRQ();
public:
uint8_t Second;
uint8_t Minute;
uint8_t Hour;
uint8_t Week;
uint8_t Day;
uint8_t Month;
uint8_t Year;
uint8_t DateString[9];
uint8_t TimeString[9];
uint8_t asc[14];
private:
void Bcd2asc(void);
void DataMask();
void Str2Time(void);
void WriteReg(uint8_t reg, uint8_t data);
uint8_t ReadReg(uint8_t reg);
uint8_t Bcd2ToByte(uint8_t Value);
uint8_t ByteToBcd2(uint8_t Value);
private:
/*定义数组用来存储读取的时间数据 */
uint8_t trdata[7];
/*定义数组用来存储转换的 asc 码时间数据*/
//uint8_t asc[14];
};
#endif

View File

@ -0,0 +1,252 @@
#include "MPU6886.h"
#include <math.h>
#include <Arduino.h>
MPU6886::MPU6886(){
}
void MPU6886::I2C_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer){
Wire1.beginTransmission(driver_Addr);
Wire1.write(start_Addr);
Wire1.endTransmission(false);
uint8_t i = 0;
Wire1.requestFrom(driver_Addr,number_Bytes);
//! Put read results in the Rx buffer
while (Wire1.available()) {
read_Buffer[i++] = Wire1.read();
}
}
void MPU6886::I2C_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer){
Wire1.beginTransmission(driver_Addr);
Wire1.write(start_Addr);
Wire1.write(*write_Buffer);
Wire1.endTransmission();
}
int MPU6886::Init(void){
unsigned char tempdata[1];
unsigned char regdata;
Wire1.begin(21,22);
I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_WHOAMI, 1, tempdata);
if(tempdata[0] != 0x19)
return -1;
delay(1);
regdata = 0x00;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);
delay(10);
regdata = (0x01<<7);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);
delay(10);
regdata = (0x01<<0);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);
delay(10);
regdata = 0x10;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG, 1, &regdata);
delay(1);
regdata = 0x18;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_GYRO_CONFIG, 1, &regdata);
delay(1);
regdata = 0x01;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_CONFIG, 1, &regdata);
delay(1);
regdata = 0x05;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_SMPLRT_DIV, 1,&regdata);
delay(1);
regdata = 0x00;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_ENABLE, 1, &regdata);
delay(1);
regdata = 0x00;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG2, 1, &regdata);
delay(1);
regdata = 0x00;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_USER_CTRL, 1, &regdata);
delay(1);
regdata = 0x00;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_FIFO_EN, 1, &regdata);
delay(1);
regdata = 0x22;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_PIN_CFG, 1, &regdata);
delay(1);
regdata = 0x01;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_ENABLE, 1, &regdata);
delay(100);
getGres();
getAres();
return 0;
}
void MPU6886::getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az){
uint8_t buf[6];
I2C_Read_NBytes(MPU6886_ADDRESS,MPU6886_ACCEL_XOUT_H,6,buf);
*ax=((int16_t)buf[0]<<8)|buf[1];
*ay=((int16_t)buf[2]<<8)|buf[3];
*az=((int16_t)buf[4]<<8)|buf[5];
}
void MPU6886::getGyroAdc(int16_t* gx, int16_t* gy, int16_t* gz){
uint8_t buf[6];
I2C_Read_NBytes(MPU6886_ADDRESS,MPU6886_GYRO_XOUT_H,6,buf);
*gx=((uint16_t)buf[0]<<8)|buf[1];
*gy=((uint16_t)buf[2]<<8)|buf[3];
*gz=((uint16_t)buf[4]<<8)|buf[5];
}
void MPU6886::getTempAdc(int16_t *t){
uint8_t buf[2];
I2C_Read_NBytes(MPU6886_ADDRESS,MPU6886_TEMP_OUT_H,2,buf);
*t=((uint16_t)buf[0]<<8)|buf[1];
}
//!俯仰航向横滚pitchyawroll指三维空间中飞行器的旋转状态。
void MPU6886::getAhrsData(float *pitch,float *roll,float *yaw){
float accX = 0;
float accY = 0;
float accZ = 0;
float gyroX = 0;
float gyroY = 0;
float gyroZ = 0;
getGyroData(&gyroX,&gyroY,&gyroZ);
getAccelData(&accX,&accY,&accZ);
MahonyAHRSupdateIMU(gyroX * DEG_TO_RAD, gyroY * DEG_TO_RAD, gyroZ * DEG_TO_RAD, accX, accY, accZ,pitch,roll,yaw);
}
void MPU6886::getGres(){
switch (Gyscale)
{
// Possible gyro scales (and their register bit settings) are:
case GFS_250DPS:
gRes = 250.0/32768.0;
break;
case GFS_500DPS:
gRes = 500.0/32768.0;
break;
case GFS_1000DPS:
gRes = 1000.0/32768.0;
break;
case GFS_2000DPS:
gRes = 2000.0/32768.0;
break;
}
}
void MPU6886::getAres(){
switch (Acscale)
{
// Possible accelerometer scales (and their register bit settings) are:
// 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs (11).
// Here's a bit of an algorith to calculate DPS/(ADC tick) based on that 2-bit value:
case AFS_2G:
aRes = 2.0/32768.0;
break;
case AFS_4G:
aRes = 4.0/32768.0;
break;
case AFS_8G:
aRes = 8.0/32768.0;
break;
case AFS_16G:
aRes = 16.0/32768.0;
break;
}
}
void MPU6886::SetGyroFsr(Gscale scale)
{
//return IIC_Write_Byte(MPU_GYRO_CFG_REG,scale<<3);//设置陀螺仪满量程范围
unsigned char regdata;
regdata = (scale<<3);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_GYRO_CONFIG, 1, &regdata);
delay(10);
Gyscale = scale;
getGres();
}
void MPU6886::SetAccelFsr(Ascale scale)
{
unsigned char regdata;
regdata = (scale<<3);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG, 1, &regdata);
delay(10);
Acscale = scale;
getAres();
}
void MPU6886::getAccelData(float* ax, float* ay, float* az){
int16_t accX = 0;
int16_t accY = 0;
int16_t accZ = 0;
getAccelAdc(&accX,&accY,&accZ);
*ax = (float)accX * aRes;
*ay = (float)accY * aRes;
*az = (float)accZ * aRes;
}
void MPU6886::getGyroData(float* gx, float* gy, float* gz){
int16_t gyroX = 0;
int16_t gyroY = 0;
int16_t gyroZ = 0;
getGyroAdc(&gyroX,&gyroY,&gyroZ);
*gx = (float)gyroX * gRes;
*gy = (float)gyroY * gRes;
*gz = (float)gyroZ * gRes;
}
void MPU6886::getTempData(float *t){
int16_t temp = 0;
getTempAdc(&temp);
*t = (float)temp / 326.8 + 25.0;
}

View File

@ -0,0 +1,98 @@
/*
Note: The MPU6886 is an I2C sensor and uses the Arduino Wire library.
Because the sensor is not 5V tolerant, we are using a 3.3 V 8 MHz Pro Mini or
a 3.3 V Teensy 3.1. We have disabled the internal pull-ups used by the Wire
library in the Wire.h/twi.c utility file. We are also using the 400 kHz fast
I2C mode by setting the TWI_FREQ to 400000L /twi.h utility file.
*/
#ifndef _MPU6886_H_
#define _MPU6886_H_
#include <Wire.h>
#include <Arduino.h>
#include "MahonyAHRS.h"
#define MPU6886_ADDRESS 0x68
#define MPU6886_WHOAMI 0x75
#define MPU6886_ACCEL_INTEL_CTRL 0x69
#define MPU6886_SMPLRT_DIV 0x19
#define MPU6886_INT_PIN_CFG 0x37
#define MPU6886_INT_ENABLE 0x38
#define MPU6886_ACCEL_XOUT_H 0x3B
#define MPU6886_ACCEL_XOUT_L 0x3C
#define MPU6886_ACCEL_YOUT_H 0x3D
#define MPU6886_ACCEL_YOUT_L 0x3E
#define MPU6886_ACCEL_ZOUT_H 0x3F
#define MPU6886_ACCEL_ZOUT_L 0x40
#define MPU6886_TEMP_OUT_H 0x41
#define MPU6886_TEMP_OUT_L 0x42
#define MPU6886_GYRO_XOUT_H 0x43
#define MPU6886_GYRO_XOUT_L 0x44
#define MPU6886_GYRO_YOUT_H 0x45
#define MPU6886_GYRO_YOUT_L 0x46
#define MPU6886_GYRO_ZOUT_H 0x47
#define MPU6886_GYRO_ZOUT_L 0x48
#define MPU6886_USER_CTRL 0x6A
#define MPU6886_PWR_MGMT_1 0x6B
#define MPU6886_PWR_MGMT_2 0x6C
#define MPU6886_CONFIG 0x1A
#define MPU6886_GYRO_CONFIG 0x1B
#define MPU6886_ACCEL_CONFIG 0x1C
#define MPU6886_ACCEL_CONFIG2 0x1D
#define MPU6886_FIFO_EN 0x23
//#define G (9.8)
#define RtA 57.324841
#define AtR 0.0174533
#define Gyro_Gr 0.0010653
class MPU6886 {
public:
enum Ascale {
AFS_2G = 0,
AFS_4G,
AFS_8G,
AFS_16G
};
enum Gscale {
GFS_250DPS = 0,
GFS_500DPS,
GFS_1000DPS,
GFS_2000DPS
};
Gscale Gyscale = GFS_2000DPS;
Ascale Acscale = AFS_8G;
public:
MPU6886();
int Init(void);
void getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az);
void getGyroAdc(int16_t* gx, int16_t* gy, int16_t* gz);
void getTempAdc(int16_t *t);
void getAccelData(float* ax, float* ay, float* az);
void getGyroData(float* gx, float* gy, float* gz);
void getTempData(float *t);
void SetGyroFsr(Gscale scale);
void SetAccelFsr(Ascale scale);
void getAhrsData(float *pitch,float *roll,float *yaw);
public:
float aRes, gRes;
private:
private:
void I2C_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer);
void I2C_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer);
void getGres();
void getAres();
};
#endif

View File

@ -0,0 +1,254 @@
//=====================================================================================================
// MahonyAHRS.c
//=====================================================================================================
//
// Madgwick's implementation of Mayhony's AHRS algorithm.
// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
//
// Date Author Notes
// 29/09/2011 SOH Madgwick Initial release
// 02/10/2011 SOH Madgwick Optimised for reduced CPU load
//
//=====================================================================================================
//---------------------------------------------------------------------------------------------------
// Header files
#include "MahonyAHRS.h"
#include "Arduino.h"
#include <math.h>
//---------------------------------------------------------------------------------------------------
// Definitions
#define sampleFreq 25.0f // sample frequency in Hz
#define twoKpDef (2.0f * 1.0f) // 2 * proportional gain
#define twoKiDef (2.0f * 0.0f) // 2 * integral gain
//#define twoKiDef (0.0f * 0.0f)
//---------------------------------------------------------------------------------------------------
// Variable definitions
volatile float twoKp = twoKpDef; // 2 * proportional gain (Kp)
volatile float twoKi = twoKiDef; // 2 * integral gain (Ki)
volatile float q0 = 1.0, q1 = 0.0, q2 = 0.0, q3 = 0.0; // quaternion of sensor frame relative to auxiliary frame
volatile float integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki
//---------------------------------------------------------------------------------------------------
// Function declarations
//float invSqrt(float x);
//====================================================================================================
// Functions
//---------------------------------------------------------------------------------------------------
// AHRS algorithm update
void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {
float recipNorm;
float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;
float hx, hy, bx, bz;
float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz;
float halfex, halfey, halfez;
float qa, qb, qc;
// Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation)
if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {
//MahonyAHRSupdateIMU(gx, gy, gz, ax, ay, az);
return;
}
// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
// Normalise accelerometer measurement
recipNorm = sqrt(ax * ax + ay * ay + az * az);
ax *= recipNorm;
ay *= recipNorm;
az *= recipNorm;
// Normalise magnetometer measurement
recipNorm = sqrt(mx * mx + my * my + mz * mz);
mx *= recipNorm;
my *= recipNorm;
mz *= recipNorm;
// Auxiliary variables to avoid repeated arithmetic
q0q0 = q0 * q0;
q0q1 = q0 * q1;
q0q2 = q0 * q2;
q0q3 = q0 * q3;
q1q1 = q1 * q1;
q1q2 = q1 * q2;
q1q3 = q1 * q3;
q2q2 = q2 * q2;
q2q3 = q2 * q3;
q3q3 = q3 * q3;
// Reference direction of Earth's magnetic field
hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
bx = sqrt(hx * hx + hy * hy);
bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2));
// Estimated direction of gravity and magnetic field
halfvx = q1q3 - q0q2;
halfvy = q0q1 + q2q3;
halfvz = q0q0 - 0.5f + q3q3;
halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);
// Error is sum of cross product between estimated direction and measured direction of field vectors
halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy);
halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz);
halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx);
// Compute and apply integral feedback if enabled
if(twoKi > 0.0f) {
integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki
integralFBy += twoKi * halfey * (1.0f / sampleFreq);
integralFBz += twoKi * halfez * (1.0f / sampleFreq);
gx += integralFBx; // apply integral feedback
gy += integralFBy;
gz += integralFBz;
}
else {
integralFBx = 0.0f; // prevent integral windup
integralFBy = 0.0f;
integralFBz = 0.0f;
}
// Apply proportional feedback
gx += twoKp * halfex;
gy += twoKp * halfey;
gz += twoKp * halfez;
}
// Integrate rate of change of quaternion
gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors
gy *= (0.5f * (1.0f / sampleFreq));
gz *= (0.5f * (1.0f / sampleFreq));
qa = q0;
qb = q1;
qc = q2;
q0 += (-qb * gx - qc * gy - q3 * gz);
q1 += (qa * gx + qc * gz - q3 * gy);
q2 += (qa * gy - qb * gz + q3 * gx);
q3 += (qa * gz + qb * gy - qc * gx);
// Normalise quaternion
recipNorm = sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
q0 *= recipNorm;
q1 *= recipNorm;
q2 *= recipNorm;
q3 *= recipNorm;
}
//---------------------------------------------------------------------------------------------------
// IMU algorithm update
void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az,float *pitch,float *roll,float *yaw) {
float recipNorm;
float halfvx, halfvy, halfvz;
float halfex, halfey, halfez;
float qa, qb, qc;
// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
// Normalise accelerometer measurement
recipNorm = invSqrt(ax * ax + ay * ay + az * az);
ax *= recipNorm;
ay *= recipNorm;
az *= recipNorm;
// Estimated direction of gravity and vector perpendicular to magnetic flux
halfvx = q1 * q3 - q0 * q2;
halfvy = q0 * q1 + q2 * q3;
halfvz = q0 * q0 - 0.5f + q3 * q3;
// Error is sum of cross product between estimated and measured direction of gravity
halfex = (ay * halfvz - az * halfvy);
halfey = (az * halfvx - ax * halfvz);
halfez = (ax * halfvy - ay * halfvx);
// Compute and apply integral feedback if enabled
if(twoKi > 0.0f) {
integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki
integralFBy += twoKi * halfey * (1.0f / sampleFreq);
integralFBz += twoKi * halfez * (1.0f / sampleFreq);
gx += integralFBx; // apply integral feedback
gy += integralFBy;
gz += integralFBz;
}
else {
integralFBx = 0.0f; // prevent integral windup
integralFBy = 0.0f;
integralFBz = 0.0f;
}
// Apply proportional feedback
gx += twoKp * halfex;
gy += twoKp * halfey;
gz += twoKp * halfez;
}
// Integrate rate of change of quaternion
gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors
gy *= (0.5f * (1.0f / sampleFreq));
gz *= (0.5f * (1.0f / sampleFreq));
qa = q0;
qb = q1;
qc = q2;
q0 += (-qb * gx - qc * gy - q3 * gz);
q1 += (qa * gx + qc * gz - q3 * gy);
q2 += (qa * gy - qb * gz + q3 * gx);
q3 += (qa * gz + qb * gy - qc * gx);
// Normalise quaternion
recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
q0 *= recipNorm;
q1 *= recipNorm;
q2 *= recipNorm;
q3 *= recipNorm;
*pitch = asin(-2 * q1 * q3 + 2 * q0* q2); // pitch
*roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1); // roll
*yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3); //yaw
*pitch *= RAD_TO_DEG;
*yaw *= RAD_TO_DEG;
// Declination of SparkFun Electronics (40°05'26.6"N 105°11'05.9"W) is
// 8° 30' E ± 0° 21' (or 8.5°) on 2016-07-19
// - http://www.ngdc.noaa.gov/geomag-web/#declination
*yaw -= 8.5;
*roll *= RAD_TO_DEG;
///Serial.printf("%f %f %f \r\n", pitch, roll, yaw);
}
//---------------------------------------------------------------------------------------------------
// Fast inverse square-root
// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
float invSqrt(float x) {
float halfx = 0.5f * x;
float y = x;
long i = *(long*)&y;
i = 0x5f3759df - (i>>1);
y = *(float*)&i;
y = y * (1.5f - (halfx * y * y));
return y;
}
#pragma GCC diagnostic pop
//====================================================================================================
// END OF CODE
//====================================================================================================

View File

@ -0,0 +1,33 @@
//=====================================================================================================
// MahonyAHRS.h
//=====================================================================================================
//
// Madgwick's implementation of Mayhony's AHRS algorithm.
// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
//
// Date Author Notes
// 29/09/2011 SOH Madgwick Initial release
// 02/10/2011 SOH Madgwick Optimised for reduced CPU load
//
//=====================================================================================================
#ifndef MahonyAHRS_h
#define MahonyAHRS_h
//----------------------------------------------------------------------------------------------------
// Variable declaration
extern volatile float twoKp; // 2 * proportional gain (Kp)
extern volatile float twoKi; // 2 * integral gain (Ki)
//volatile float q0, q1, q2, q3; // quaternion of sensor frame relative to auxiliary frame
//---------------------------------------------------------------------------------------------------
// Function declarations
void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz);
//void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az);
void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az,float *pitch,float *roll,float *yaw);
float invSqrt(float x);
#endif
//=====================================================================================================
// End of file
//=====================================================================================================

View File

@ -87,6 +87,6 @@ build_flags = ${esp_defaults.build_flags}
[core32]
platform = espressif32 @ 2.1.0
platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/1.0.4.2/esp32-1.0.4.2.zip
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/1.0.5-rc4/esp32-1.0.5-rc4.zip
build_unflags = ${esp32_defaults.build_unflags}
build_flags = ${esp32_defaults.build_flags}

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -642,6 +642,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -1,7 +1,7 @@
/*
it-IT.h - localization for Italian - Italy for Tasmota
Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 20.11.2020
Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 28.12.2020
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
@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 - CLK"
#define D_SENSOR_SM16716_DAT "SM16716 - DAT"
#define D_SENSOR_SM16716_POWER "SM16716 - PWR"
#define D_SENSOR_P9813_CLK "P9813 - CLK"
#define D_SENSOR_P9813_DAT "P9813 - DAT"
#define D_SENSOR_MY92X1_DI "MY92x1 - DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 - DCKI"
#define D_SENSOR_ARIRFRCV "IR ALux - RCV"
@ -671,8 +673,8 @@
#define D_SENSOR_A4988_STP "A4988 - STP"
#define D_SENSOR_A4988_ENA "A4988 - ENA"
#define D_SENSOR_A4988_MS1 "A4988 - MS1"
#define D_SENSOR_OUTPUT_HI "Output - Hi"
#define D_SENSOR_OUTPUT_LO "Output - Lo"
#define D_SENSOR_OUTPUT_HI "Uscita - Hi"
#define D_SENSOR_OUTPUT_LO "Uscita - Lo"
#define D_SENSOR_AS608_TX "AS608 - TX"
#define D_SENSOR_AS608_RX "AS608 - RX"
#define D_SENSOR_DDS2382_TX "DDS238-2 - TX"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -646,6 +646,8 @@
#define D_SENSOR_SM16716_CLK "SM16716 CLK"
#define D_SENSOR_SM16716_DAT "SM16716 DAT"
#define D_SENSOR_SM16716_POWER "SM16716 PWR"
#define D_SENSOR_P9813_CLK "P9813 Clk"
#define D_SENSOR_P9813_DAT "P9813 Dat"
#define D_SENSOR_MY92X1_DI "MY92x1 DI"
#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI"
#define D_SENSOR_ARIRFRCV "ALux IrRcv"

View File

@ -484,7 +484,7 @@
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
// #define USE_WS2812_INVERTED // Use inverted data signal
#define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106)
#define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106, NEO_HW_P9813)
#define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
#define USE_MY92X1 // Add support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas
#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)

View File

@ -142,7 +142,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t mqtt_switches : 1; // bit 0 (v9.0.0.3) - SetOption114 - (Switch) Detach Switches from relays and enable MQTT action state for all the SwitchModes (1)
uint32_t mi32_enable : 1; // bit 1 (v9.1.0.1) - SetOption115 - (ESP32 BLE) Enable ESP32 MI32 BLE (1)
uint32_t zb_disable_autoquery : 1; // bit 2 (v9.1.0.1) - SetOption116 - (Zigbee) Disable auto-query of zigbee lights and devices (1)
uint32_t spare03 : 1; // bit 3
uint32_t fade_fixed_duration : 1; // bit 3 (v9.1.0.2) - SetOption117 - (Light) run fading at fixed duration instead of fixed slew rate
uint32_t spare04 : 1; // bit 4
uint32_t spare05 : 1; // bit 5
uint32_t spare06 : 1; // bit 6

View File

@ -17,9 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
IPAddress syslog_host_addr; // Syslog host IP address
uint32_t syslog_host_hash = 0; // Syslog host name hash
extern "C" {
extern struct rst_info resetInfo;
}
@ -1899,34 +1896,11 @@ void SetSyslog(uint32_t loglevel)
TasmotaGlobal.syslog_timer = 0;
}
#ifdef USE_WEBSERVER
void GetLog(uint32_t idx, char** entry_pp, size_t* len_p)
{
char* entry_p = nullptr;
size_t len = 0;
if (idx) {
char* it = TasmotaGlobal.web_log;
do {
uint32_t cur_idx = *it;
it++;
size_t tmp = strchrspn(it, '\1');
tmp++; // Skip terminating '\1'
if (cur_idx == idx) { // Found the requested entry
len = tmp;
entry_p = it;
break;
}
it += tmp;
} while (it < TasmotaGlobal.web_log + WEB_LOG_SIZE && *it != '\0');
}
*entry_pp = entry_p;
*len_p = len;
}
#endif // USE_WEBSERVER
void Syslog(void)
{
static IPAddress syslog_host_addr; // Syslog host IP address
static uint32_t syslog_host_hash = 0; // Syslog host name hash
// Destroys TasmotaGlobal.log_data
uint32_t current_hash = GetHash(SettingsText(SET_SYSLOG_HOST), strlen(SettingsText(SET_SYSLOG_HOST)));
@ -1950,53 +1924,102 @@ void Syslog(void)
}
}
void AddLog(uint32_t loglevel)
{
char mxtime[10]; // "13:45:21 "
snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second);
void SyslogAsync(void) {
static uint32_t index = 1;
char* line;
size_t len;
while (GetLog(TasmotaGlobal.syslog_level, &index, &line, &len)) {
if (len > 13) {
strlcpy(TasmotaGlobal.log_data, line +13, len -13); // Skip mxtime
Syslog();
}
}
}
bool GetLog(uint32_t req_loglevel, uint32_t* index_p, char** entry_pp, size_t* len_p) {
uint32_t index = *index_p;
if (!req_loglevel || (index == TasmotaGlobal.log_buffer_pointer)) { return false; }
if (!index) { // Dump all
index = TasmotaGlobal.log_buffer_pointer +1;
if (index > 255) { index = 1; }
}
do {
size_t len = 0;
uint32_t loglevel = 0;
char* entry_p = TasmotaGlobal.log_buffer;
do {
uint32_t cur_idx = *entry_p;
entry_p++;
size_t tmp = strchrspn(entry_p, '\1');
tmp++; // Skip terminating '\1'
if (cur_idx == index) { // Found the requested entry
loglevel = *entry_p - '0';
entry_p++; // Skip loglevel
len = tmp -1;
break;
}
entry_p += tmp;
} while (entry_p < TasmotaGlobal.log_buffer + LOG_BUFFER_SIZE && *entry_p != '\0');
index++;
if (index > 255) { index = 1; } // Skip 0 as it is not allowed
*index_p = index;
if ((len > 0) &&
(loglevel <= req_loglevel) &&
(TasmotaGlobal.masterlog_level <= req_loglevel)) {
*entry_pp = entry_p;
*len_p = len;
return true;
}
delay(0);
} while (index != TasmotaGlobal.log_buffer_pointer);
return false;
}
void AddLog(uint32_t loglevel) {
// char mxtime[10]; // "13:45:21 "
// snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second);
char mxtime[14]; // "13:45:21.999 "
snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d.%03d "), RtcTime.hour, RtcTime.minute, RtcTime.second, RtcMillis());
if ((loglevel <= TasmotaGlobal.seriallog_level) &&
(TasmotaGlobal.masterlog_level <= TasmotaGlobal.seriallog_level)) {
Serial.printf("%s%s\r\n", mxtime, TasmotaGlobal.log_data);
}
#ifdef USE_WEBSERVER
if (Settings.webserver &&
(loglevel <= Settings.weblog_level) &&
(TasmotaGlobal.masterlog_level <= Settings.weblog_level)) {
uint32_t highest_loglevel = Settings.weblog_level;
if (Settings.mqttlog_level > highest_loglevel) { highest_loglevel = Settings.mqttlog_level; }
if (TasmotaGlobal.syslog_level > highest_loglevel) { highest_loglevel = TasmotaGlobal.syslog_level; }
if ((loglevel <= highest_loglevel) && // Log only when needed
(TasmotaGlobal.masterlog_level <= highest_loglevel)) {
// Delimited, zero-terminated buffer of log lines.
// Each entry has this format: [index][log data]['\1']
TasmotaGlobal.web_log_index &= 0xFF;
if (!TasmotaGlobal.web_log_index) {
TasmotaGlobal.web_log_index++; // Index 0 is not allowed as it is the end of char string
// Each entry has this format: [index][loglevel][log data]['\1']
TasmotaGlobal.log_buffer_pointer &= 0xFF;
if (!TasmotaGlobal.log_buffer_pointer) {
TasmotaGlobal.log_buffer_pointer++; // Index 0 is not allowed as it is the end of char string
}
while (TasmotaGlobal.web_log_index == TasmotaGlobal.web_log[0] || // If log already holds the next index, remove it
strlen(TasmotaGlobal.web_log) + strlen(TasmotaGlobal.log_data) + 13 > WEB_LOG_SIZE) // 13 = web_log_index + mxtime + '\1' + '\0'
while (TasmotaGlobal.log_buffer_pointer == TasmotaGlobal.log_buffer[0] || // If log already holds the next index, remove it
strlen(TasmotaGlobal.log_buffer) + strlen(TasmotaGlobal.log_data) + strlen(mxtime) + 4 > LOG_BUFFER_SIZE) // 4 = log_buffer_pointer + '\1' + '\0'
{
char* it = TasmotaGlobal.web_log;
it++; // Skip web_log_index
char* it = TasmotaGlobal.log_buffer;
it++; // Skip log_buffer_pointer
it += strchrspn(it, '\1'); // Skip log line
it++; // Skip delimiting "\1"
memmove(TasmotaGlobal.web_log, it, WEB_LOG_SIZE -(it-TasmotaGlobal.web_log)); // Move buffer forward to remove oldest log line
memmove(TasmotaGlobal.log_buffer, it, LOG_BUFFER_SIZE -(it-TasmotaGlobal.log_buffer)); // Move buffer forward to remove oldest log line
}
snprintf_P(TasmotaGlobal.web_log, sizeof(TasmotaGlobal.web_log), PSTR("%s%c%s%s\1"), TasmotaGlobal.web_log, TasmotaGlobal.web_log_index++, mxtime, TasmotaGlobal.log_data);
TasmotaGlobal.web_log_index &= 0xFF;
if (!TasmotaGlobal.web_log_index) {
TasmotaGlobal.web_log_index++; // Index 0 is not allowed as it is the end of char string
snprintf_P(TasmotaGlobal.log_buffer, sizeof(TasmotaGlobal.log_buffer), PSTR("%s%c%c%s%s\1"),
TasmotaGlobal.log_buffer, TasmotaGlobal.log_buffer_pointer++, '0'+loglevel, mxtime, TasmotaGlobal.log_data);
TasmotaGlobal.log_buffer_pointer &= 0xFF;
if (!TasmotaGlobal.log_buffer_pointer) {
TasmotaGlobal.log_buffer_pointer++; // Index 0 is not allowed as it is the end of char string
}
}
#endif // USE_WEBSERVER
if (Settings.flag.mqtt_enabled && // SetOption3 - Enable MQTT
!TasmotaGlobal.global_state.mqtt_down &&
(loglevel <= Settings.mqttlog_level) &&
(TasmotaGlobal.masterlog_level <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); }
if (!TasmotaGlobal.global_state.network_down &&
(loglevel <= TasmotaGlobal.syslog_level) &&
(TasmotaGlobal.masterlog_level <= TasmotaGlobal.syslog_level)) { Syslog(); }
TasmotaGlobal.prepped_loglevel = 0;
// TasmotaGlobal.prepped_loglevel = 0;
}
/*
void PrepLog_P(uint32_t loglevel, PGM_P formatP, ...)
{
va_list arg;
@ -2006,13 +2029,14 @@ void PrepLog_P(uint32_t loglevel, PGM_P formatP, ...)
TasmotaGlobal.prepped_loglevel = loglevel;
}
*/
void AddLog_P(uint32_t loglevel, PGM_P formatP, ...)
{
/*
if (TasmotaGlobal.prepped_loglevel) {
AddLog(TasmotaGlobal.prepped_loglevel);
}
*/
va_list arg;
va_start(arg, formatP);
vsnprintf_P(TasmotaGlobal.log_data, sizeof(TasmotaGlobal.log_data), formatP, arg);

View File

@ -1154,11 +1154,15 @@ void CmndGpio(void)
TasmotaGlobal.restart_flag = 2;
}
}
Response_P(PSTR("{"));
bool jsflg = false;
bool jsflg2 = false;
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) {
if (ValidGPIO(i, template_gp.io[i]) || ((255 == XdrvMailbox.payload) && !FlashPin(i))) {
if (jsflg) { ResponseAppend_P(PSTR(",")); }
if (!jsflg) {
Response_P(PSTR("{"));
} else {
ResponseAppend_P(PSTR(","));
}
jsflg = true;
uint32_t sensor_type = Settings.my_gp.io[i];
if (!ValidGPIO(i, template_gp.io[i])) {
@ -1183,12 +1187,16 @@ void CmndGpio(void)
sensor_names = kSensorNamesFixed;
}
char stemp1[TOPSZ];
ResponseAppend_P(PSTR("\"" D_CMND_GPIO "%d\":{\"%d\":\"%s%s\"}"),
i, sensor_type, GetTextIndexed(stemp1, sizeof(stemp1), sensor_name_idx, sensor_names), sindex);
if ((ResponseAppend_P(PSTR("\"" D_CMND_GPIO "%d\":{\"%d\":\"%s%s\"}"), i, sensor_type, GetTextIndexed(stemp1, sizeof(stemp1), sensor_name_idx, sensor_names), sindex) > (LOGSZ - TOPSZ)) || (i == ARRAY_SIZE(Settings.my_gp.io) -1)) {
ResponseJsonEndEnd();
MqttPublishPrefixTopic_P(RESULT_OR_STAT, XdrvMailbox.command);
jsflg2 = true;
jsflg = false;
}
}
if (jsflg) {
ResponseJsonEnd();
}
if (jsflg2) {
ResponseClear();
} else {
ResponseCmndChar(D_JSON_NOT_SUPPORTED);
}
@ -2068,6 +2076,9 @@ void CmndDriver(void)
void CmndInfo(void) {
NvsInfo();
#ifdef USE_TFS
TfsInfo();
#endif
ResponseCmndDone();
}

View File

@ -167,10 +167,19 @@ void SettingsErase(uint8_t type) {
}
void SettingsRead(void *data, size_t size) {
#ifdef USE_TFS
// if (!TfsLoadFile("/settings", (uint8_t*)data, size)) {
NvmLoad("main", "Settings", data, size);
// }
#else
NvmLoad("main", "Settings", data, size);
#endif
}
void SettingsWrite(const void *pSettings, unsigned nSettingsLen) {
#ifdef USE_TFS
// TfsSaveFile("/settings", (const uint8_t*)pSettings, nSettingsLen);
#endif
NvmSave("main", "Settings", pSettings, nSettingsLen);
}
@ -182,23 +191,11 @@ void QPCWrite(const void *pSettings, unsigned nSettingsLen) {
NvmSave("qpc", "pcreg", pSettings, nSettingsLen);
}
void ZigbeeErase(void) {
NvmErase("zb");
}
void ZigbeeRead(void *pSettings, unsigned nSettingsLen) {
NvmLoad("zb", "zigbee", pSettings, nSettingsLen);
}
void ZigbeeWrite(const void *pSettings, unsigned nSettingsLen) {
NvmSave("zb", "zigbee", pSettings, nSettingsLen);
}
void NvsInfo(void) {
nvs_stats_t nvs_stats;
nvs_get_stats(NULL, &nvs_stats);
AddLog_P(LOG_LEVEL_INFO, PSTR("INF: NVS Used %d, Free %d, Total %d, Namspaces %d"),
nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries, nvs_stats.namespace_count);
AddLog_P(LOG_LEVEL_INFO, PSTR("NVS: Used %d/%d entries, NameSpaces %d"),
nvs_stats.used_entries, nvs_stats.total_entries, nvs_stats.namespace_count);
}
//

View File

@ -0,0 +1,148 @@
/*
support_filesystem.ino - Filesystem support for Tasmota
Copyright (C) 2020 Theo Arends
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/>.
*/
/*********************************************************************************************\
* ESP32 Filesystem Support
\*********************************************************************************************/
#ifdef ESP32
#ifdef USE_TFS
//#define USE_LITTLEFS // LittleFS not tested yet as currently ESP8266 only
//#define USE_FFAT // FFat minimal 983k partition (4096 sector size) - tested
#define USE_SPIFFS // SPIFFS - tested
#ifdef USE_LITTLEFS
#include <LittleFS.h>
#define TASMOTA_FS LittleFS
#endif
#ifdef USE_FFAT
#include <FFat.h>
#define TASMOTA_FS FFat
#endif
#ifdef USE_SPIFFS
#include <SPIFFS.h>
#define TASMOTA_FS SPIFFS
#endif
bool TfsInit(void) {
static uint8_t FsMounted = 0;
if (FsMounted) { return FsMounted -1; }
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Mounting..."));
if (!TASMOTA_FS.begin()) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Formatting..."));
TASMOTA_FS.format();
if (!TASMOTA_FS.begin()) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Failed"));
FsMounted = 1; // false
return false;
}
}
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Mounted"));
FsMounted = 2; // true
return true;
}
bool TfsFileExists(const char *fname){
if (!TfsInit()) { return false; }
bool yes = false;
File file = TASMOTA_FS.open(fname, "r");
if (!file.isDirectory()) {
yes = true;
} else {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File not found"));
}
file.close();
return yes;
}
bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
if (!TfsInit()) { return false; }
File file = TASMOTA_FS.open(fname, "w");
if (!file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Save failed"));
return false;
}
file.write(buf, len);
file.close();
return true;
}
bool TfsEraseFile(const char *fname, uint32_t len) {
if (!TfsInit()) { return false; }
File file = TASMOTA_FS.open(fname, "w");
if (!file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Erase failed"));
return false;
}
uint8_t init_value = 0xff;
for (uint32_t i = 0; i < len; i++) {
file.write(&init_value, 1);
}
file.close();
return true;
}
bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
if (!TfsInit()) { return false; }
if (!TfsFileExists(fname)) { return false; }
File file = TASMOTA_FS.open(fname, "r");
if (!file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File not found"));
return false;
}
file.read(buf, len);
file.close();
return true;
}
void TfsInfo(void) {
if (!TfsInit()) { return; }
uint32_t total_bytes = TASMOTA_FS.totalBytes();
#ifdef USE_SPIFFS
uint32_t used_bytes = TASMOTA_FS.usedBytes();
#endif // USE_SPIFFS
#ifdef USE_FFAT
uint32_t used_bytes = total_bytes - TASMOTA_FS.freeBytes();
#endif // USE_FFAT
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Used %d/%d bytes"), used_bytes, total_bytes);
File root = TASMOTA_FS.open("/");
File file = root.openNextFile();
while (file) {
String filename = file.name();
size_t filesize = file.size();
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File %s, size %d"), filename.c_str(), filesize);
file = root.openNextFile();
}
}
#endif // USE_TFS
#endif // ESP32

View File

@ -392,7 +392,7 @@ void RtcSecond(void)
Rtc.standard_time = RuleToTime(Settings.tflag[0], RtcTime.year);
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
PrepLog_P(LOG_LEVEL_DEBUG, PSTR("RTC: " D_UTC_TIME " %s, " D_DST_TIME " %s, " D_STD_TIME " %s"),
AddLog_P(LOG_LEVEL_DEBUG, PSTR("RTC: " D_UTC_TIME " %s, " D_DST_TIME " %s, " D_STD_TIME " %s"),
GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str());
if (Rtc.local_time < START_VALID_TIME) { // 2016-01-01
@ -407,7 +407,7 @@ void RtcSecond(void)
if ((Rtc.utc_time > (2 * 60 * 60)) && (last_sync < Rtc.utc_time - (2 * 60 * 60))) { // Every two hours a warning
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
PrepLog_P(LOG_LEVEL_DEBUG, PSTR("RTC: Not synced"));
AddLog_P(LOG_LEVEL_DEBUG, PSTR("RTC: Not synced"));
last_sync = Rtc.utc_time;
}
@ -482,3 +482,7 @@ void RtcInit(void) {
BreakTime(Rtc.utc_time, RtcTime);
TickerRtc.attach(1, RtcSecond);
}
void RtcPreInit(void) {
Rtc.millis = millis();
}

View File

@ -845,6 +845,9 @@ void PerformEverySecond(void)
}
}
MqttPublishLoggingAsync();
SyslogAsync();
ResetGlobalValues();
if (Settings.tele_period) {
@ -894,10 +897,11 @@ void Every100mSeconds(void)
// As the max amount of sleep = 250 mSec this loop will shift in time...
power_t power_now;
/*
if (TasmotaGlobal.prepped_loglevel) {
AddLog(TasmotaGlobal.prepped_loglevel);
}
*/
if (TasmotaGlobal.latching_relay_pulse) {
TasmotaGlobal.latching_relay_pulse--;
if (!TasmotaGlobal.latching_relay_pulse) SetLatchingRelay(0, 0);

View File

@ -183,6 +183,7 @@ const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to
#define NEO_HW_SK6812 2 // NeoPixelBus hardware SK6812
#define NEO_HW_LC8812 2 // NeoPixelBus hardware LC8812
#define NEO_HW_APA106 3 // NeoPixelBus hardware APA106
#define NEO_HW_P9813 4 // NeoPixelBus hardware P9813
#define MQTT_PUBSUBCLIENT 1 // Mqtt PubSubClient library
#define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino - soon obsolete

View File

@ -86,7 +86,7 @@ struct {
uint32_t blink_timer; // Power cycle timer
uint32_t backlog_timer; // Timer for next command in backlog
uint32_t loop_load_avg; // Indicative loop load average
uint32_t web_log_index; // Index in Web log buffer
uint32_t log_buffer_pointer; // Index in log buffer
uint32_t uptime; // Counting every second until 4294967295 = 130 year
power_t power; // Current copy of Settings.power
@ -153,7 +153,7 @@ struct {
uint8_t module_type; // Current copy of Settings.module or user template type
uint8_t last_source; // Last command source
uint8_t shutters_present; // Number of actual define shutters
uint8_t prepped_loglevel; // Delayed log level message
// uint8_t prepped_loglevel; // Delayed log level message
#ifndef SUPPORT_IF_STATEMENT
uint8_t backlog_index; // Command backlog index
@ -169,7 +169,7 @@ struct {
char mqtt_topic[TOPSZ]; // Composed MQTT topic
char mqtt_data[MESSZ]; // MQTT publish buffer and web page ajax buffer
char log_data[LOGSZ]; // Logging
char web_log[WEB_LOG_SIZE]; // Web log buffer
char log_buffer[LOG_BUFFER_SIZE]; // Web log buffer
} TasmotaGlobal;
#ifdef SUPPORT_IF_STATEMENT
@ -191,6 +191,8 @@ void setup(void) {
#endif
#endif
RtcPreInit();
memset(&TasmotaGlobal, 0, sizeof(TasmotaGlobal));
TasmotaGlobal.baudrate = APP_BAUDRATE;
TasmotaGlobal.seriallog_timer = SERIALLOG_TIMER;

View File

@ -61,7 +61,7 @@
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
#ifndef USE_WS2812_HARDWARE
#define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106)
#define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106, NEO_HW_P9813)
#endif
#ifndef USE_WS2812_CTYPE
#define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)

View File

@ -107,6 +107,12 @@ String EthernetMacAddress(void);
#define ARDUINO_CORE_RELEASE ARDUINO_ESP32_RELEASE
#endif // ARDUINO_ESP32_RELEASE
#define USE_TFS
#ifdef USE_SCRIPT
#undef USE_TFS
#endif // USE_SCRIPT
// Hardware has no ESP32
#undef USE_TUYA_DIMMER
#undef USE_PWM_DIMMER
@ -203,11 +209,7 @@ String EthernetMacAddress(void);
#define WS2812_LEDS 30 // [Pixels] Number of LEDs
#endif
//#ifdef USE_MQTT_TLS // Set to 4000 on 20200922 per #9305
// const uint16_t WEB_LOG_SIZE = 2000; // Max number of characters in weblog
//#else
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
//#endif
const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in logbuffer used by weblog, syslog and mqttlog
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) || defined(ARDUINO_ESP8266_RELEASE_2_5_0) || defined(ARDUINO_ESP8266_RELEASE_2_5_1) || defined(ARDUINO_ESP8266_RELEASE_2_5_2)
#error "Arduino ESP8266 Core versions before 2.7.1 are not supported"

View File

@ -129,6 +129,7 @@ enum UserSelectablePins {
GPIO_AS608_TX, GPIO_AS608_RX, // Serial interface AS608 / R503
GPIO_SHELLY_DIMMER_BOOT0, GPIO_SHELLY_DIMMER_RST_INV,
GPIO_RC522_RST, // RC522 reset
GPIO_P9813_CLK, GPIO_P9813_DAT, // P9813 Clock and Data
GPIO_SENSOR_END };
enum ProgramSelectablePins {
@ -237,7 +238,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_WE517_TX "|" D_SENSOR_WE517_RX "|"
D_SENSOR_AS608_TX "|" D_SENSOR_AS608_RX "|"
D_SENSOR_SHELLY_DIMMER_BOOT0 "|" D_SENSOR_SHELLY_DIMMER_RST_INV "|"
D_SENSOR_RC522_RST
D_SENSOR_RC522_RST "|"
D_SENSOR_P9813_CLK "|" D_SENSOR_P9813_DAT
;
const char kSensorNamesFixed[] PROGMEM =
@ -247,6 +249,7 @@ const char kSensorNamesFixed[] PROGMEM =
#define MAX_A4988_MSS 3
#define MAX_WEBCAM_DATA 8
#define MAX_WEBCAM_HSD 3
#define MAX_SM2135_DAT 4
const uint16_t kGpioNiceList[] PROGMEM = {
GPIO_NONE, // Not used
@ -336,7 +339,12 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#ifdef USE_LIGHT
#ifdef USE_WS2812
#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
AGPIO(GPIO_P9813_CLK), // P9813 CLOCK
AGPIO(GPIO_P9813_DAT), // P9813 DATA
#else
AGPIO(GPIO_WS2812), // WS2812 Led string
#endif // NEO_HW_P9813
#endif
#ifdef USE_ARILUX_RF
AGPIO(GPIO_ARIRFRCV), // AriLux RF Receive input
@ -353,7 +361,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#endif // USE_SM16716
#ifdef USE_SM2135
AGPIO(GPIO_SM2135_CLK), // SM2135 CLOCK
AGPIO(GPIO_SM2135_DAT), // SM2135 DATA
AGPIO(GPIO_SM2135_DAT) + MAX_SM2135_DAT, // SM2135 DATA
#endif // USE_SM2135
#ifdef USE_TUYA_MCU
AGPIO(GPIO_TUYA_TX), // Tuya Serial interface

View File

@ -20,6 +20,6 @@
#ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_
const uint32_t VERSION = 0x09010002;
const uint32_t VERSION = 0x09020001;
#endif // _TASMOTA_VERSION_H_

View File

@ -1661,6 +1661,18 @@ bool HandleRootStatusRefresh(void)
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
#endif // USE_SONOFF_RF
#ifdef USE_ZIGBEE
WebGetArg("zbj", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR("ZbPermitJoin"));
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
WebGetArg("zbr", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR("ZbMap"));
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
#endif // USE_ZIGBEE
WSContentBegin(200, CT_HTML);
WSContentSend_P(PSTR("{t}"));
XsnsCall(FUNC_WEB_SENSOR);
@ -3005,23 +3017,21 @@ void HandleHttpCommand(void)
}
WSContentBegin(200, CT_JSON);
uint32_t curridx = TasmotaGlobal.web_log_index;
uint32_t curridx = TasmotaGlobal.log_buffer_pointer;
String svalue = Webserver->arg("cmnd");
if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) {
ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND);
if (TasmotaGlobal.web_log_index != curridx) {
uint32_t counter = curridx;
if (TasmotaGlobal.log_buffer_pointer != curridx) {
WSContentSend_P(PSTR("{"));
bool cflg = false;
do {
char* tmp;
uint32_t index = curridx;
char* line;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(tmp, '{', len);
while (GetLog(Settings.weblog_level, &index, &line, &len)) {
// [14:49:36.123 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(line, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - (JSON - tmp);
size_t JSONlen = len - (JSON - line);
if (JSONlen > sizeof(TasmotaGlobal.mqtt_data)) { JSONlen = sizeof(TasmotaGlobal.mqtt_data); }
char stemp[JSONlen];
strlcpy(stemp, JSON +1, JSONlen -2);
@ -3029,10 +3039,6 @@ void HandleHttpCommand(void)
cflg = true;
}
}
counter++;
counter &= 0xFF;
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != TasmotaGlobal.web_log_index);
WSContentSend_P(PSTR("}"));
} else {
WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}"));
@ -3066,9 +3072,6 @@ void HandleConsole(void)
void HandleConsoleRefresh(void)
{
bool cflg = true;
uint32_t counter = 0; // Initial start, should never be 0 again
String svalue = Webserver->arg("c1");
if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), svalue.c_str());
@ -3077,35 +3080,25 @@ void HandleConsoleRefresh(void)
char stmp[8];
WebGetArg("c2", stmp, sizeof(stmp));
if (strlen(stmp)) { counter = atoi(stmp); }
uint32_t index = 0; // Initial start, dump all
if (strlen(stmp)) { index = atoi(stmp); }
WSContentBegin(200, CT_PLAIN);
WSContentSend_P(PSTR("%d}1%d}1"), TasmotaGlobal.web_log_index, Web.reset_web_log_flag);
WSContentSend_P(PSTR("%d}1%d}1"), TasmotaGlobal.log_buffer_pointer, Web.reset_web_log_flag);
if (!Web.reset_web_log_flag) {
counter = 0;
index = 0;
Web.reset_web_log_flag = true;
}
if (counter != TasmotaGlobal.web_log_index) {
if (!counter) {
counter = TasmotaGlobal.web_log_index;
cflg = false;
}
do {
char* tmp;
bool cflg = (index);
char* line;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
while (GetLog(Settings.weblog_level, &index, &line, &len)) {
if (len > sizeof(TasmotaGlobal.mqtt_data) -2) { len = sizeof(TasmotaGlobal.mqtt_data); }
char stemp[len +1];
strlcpy(stemp, tmp, len);
strlcpy(stemp, line, len);
WSContentSend_P(PSTR("%s%s"), (cflg) ? "\n" : "", stemp);
cflg = true;
}
counter++;
counter &= 0xFF;
if (!counter) { counter++; } // Skip log index 0 as it is not allowed
} while (counter != TasmotaGlobal.web_log_index);
}
WSContentSend_P(PSTR("}1"));
WSContentEnd();
}

View File

@ -291,18 +291,19 @@ void MqttUnsubscribe(const char *topic)
MqttUnsubscribeLib(topic);
}
void MqttPublishLogging(const char *mxtime)
{
char saved_mqtt_data[strlen(TasmotaGlobal.mqtt_data) +1];
memcpy(saved_mqtt_data, TasmotaGlobal.mqtt_data, sizeof(saved_mqtt_data));
void MqttPublishLoggingAsync(void) {
static uint32_t index = 1;
// ResponseTime_P(PSTR(",\"Log\":{\"%s\"}}"), TasmotaGlobal.log_data); // Will fail as some messages contain JSON
Response_P(PSTR("%s%s"), mxtime, TasmotaGlobal.log_data); // No JSON and ugly!!
if (!Settings.flag.mqtt_enabled) { return; } // SetOption3 - Enable MQTT
char* line;
size_t len;
while (GetLog(Settings.mqttlog_level, &index, &line, &len)) {
strlcpy(TasmotaGlobal.mqtt_data, line, len); // No JSON and ugly!!
char stopic[TOPSZ];
GetTopic_P(stopic, STAT, TasmotaGlobal.mqtt_topic, PSTR("LOGGING"));
MqttPublishLib(stopic, false);
memcpy(TasmotaGlobal.mqtt_data, saved_mqtt_data, sizeof(saved_mqtt_data));
}
}
void MqttPublish(const char* topic, bool retained)

View File

@ -2137,7 +2137,10 @@ bool LightApplyFade(void) { // did the value chanegd and needs to be applied
// compute the duration of the animation
// Note: Settings.light_speed is the number of half-seconds for a 100% fade,
// i.e. light_speed=1 means 1024 steps in 500ms
Light.fade_duration = (distance * Settings.light_speed * 500) / 1023;
Light.fade_duration = Settings.light_speed * 500;
if (!Settings.flag5.fade_fixed_duration) {
Light.fade_duration = (distance * Light.fade_duration) / 1023; // time is proportional to distance, except with SO117
}
if (Settings.save_data) {
// Also postpone the save_data for the duration of the Fade (in seconds)
uint32_t delay_seconds = 1 + (Light.fade_duration + 999) / 1000; // add one more second

View File

@ -67,8 +67,8 @@ keywords if then else endif, or, and are better readable for beginners (others m
#define MAX_SARRAY_NUM 32
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
//uint32_t EncodeLightId(uint8_t relay_id);
//uint32_t DecodeLightId(uint32_t hue_id);
#ifdef USE_UNISHOX_COMPRESSION
#define USE_SCRIPT_COMPRESSION
@ -108,7 +108,11 @@ uint32_t DecodeLightId(uint32_t hue_id);
#pragma message "script 24c256 file option used"
#else
//#warning "EEP_SCRIPT_SIZE also needs USE_24C256"
#if EEP_SCRIPT_SIZE==SPI_FLASH_SEC_SIZE
#pragma message "internal eeprom script buffer used"
#else
#pragma message "internal compressed eeprom script buffer used"
#endif
//#define USE_24C256
#endif
#endif // EEP_SCRIPT_SIZE
@ -119,7 +123,7 @@ uint32_t DecodeLightId(uint32_t hue_id);
#endif // USE_UNISHOX_COMPRESSION
#ifdef USE_SCRIPT_COMPRESSION
//#ifdef USE_SCRIPT_COMPRESSION
#include <unishox.h>
#define SCRIPT_COMPRESS compressor.unishox_compress
@ -127,7 +131,8 @@ uint32_t DecodeLightId(uint32_t hue_id);
#ifndef UNISHOXRSIZE
#define UNISHOXRSIZE 2560
#endif
#endif // USE_SCRIPT_COMPRESSION
//#endif // USE_SCRIPT_COMPRESSION
#ifndef STASK_PRIO
#define STASK_PRIO 1
@ -158,6 +163,51 @@ void Script_ticker4_end(void) {
}
#endif
// EEPROM MACROS
// i2c eeprom
#if defined(ALT_EEPROM) && !defined(ESP32)
#undef EEP_WRITE
#undef EEP_READ
#undef EEP_INIT
#define EEP_WRITE(A,B,C) alt_eeprom_writeBytes(A, B, (uint8_t*)C);
#define EEP_READ(A,B,C) alt_eeprom_readBytes(A, B, (uint8_t*)C);
#define EEP_INIT(A) alt_eeprom_init(A)
#if EEP_SCRIPT_SIZE>6500
#undef EEP_SCRIPT_SIZE
#define EEP_SCRIPT_SIZE 6500
#endif
uint32_t eeprom_block;
// these support only one 4 k block below EEPROM this steals 4k of application area
uint32_t alt_eeprom_init(uint32_t size) {
//EEPROM.begin(size);
eeprom_block = (uint32_t)&_FS_end - 0x40200000 - SPI_FLASH_SEC_SIZE;
return 1;
}
void alt_eeprom_writeBytes(uint32_t adr, uint32_t len, uint8_t *buf) {
uint32_t *lwp=(uint32_t*)buf;
ESP.flashEraseSector(eeprom_block / SPI_FLASH_SEC_SIZE);
ESP.flashWrite(eeprom_block , lwp, SPI_FLASH_SEC_SIZE);
}
void alt_eeprom_readBytes(uint32_t adr, uint32_t len, uint8_t *buf) {
uint32_t *lwp=(uint32_t*)buf;
ESP.flashRead(eeprom_block , lwp, SPI_FLASH_SEC_SIZE);
}
#else
#undef EEP_WRITE
#undef EEP_READ
#undef EEP_INIT
#define EEP_WRITE(A,B,C) eeprom_writeBytes(A, B, (uint8_t*)C);
#define EEP_READ(A,B,C) eeprom_readBytes(A, B, (uint8_t*)C);
#define EEP_INIT(A) eeprom_init(A)
#endif // ALT_EEPROM
#if defined(LITTLEFS_SCRIPT_SIZE) || (USE_SCRIPT_FATFS==-1)
#ifdef ESP32
@ -516,10 +566,7 @@ void RulesTeleperiod(void) {
if (bitRead(Settings.rule_enabled, 0) && TasmotaGlobal.mqtt_data[0]) Run_Scripter(">T", 2, TasmotaGlobal.mqtt_data);
}
// EEPROM MACROS
// i2c eeprom
#define EEP_WRITE(A,B,C) eeprom_writeBytes(A, B, (uint8_t*)C);
#define EEP_READ(A,B,C) eeprom_readBytes(A, B, (uint8_t*)C);
#define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++;
@ -1537,7 +1584,7 @@ float fvar;
char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, float *fp, char *sp, JsonParserObject *jo) {
uint16_t count,len = 0;
uint8_t nres = 0;
char vname[32];
char vname[64];
float fvar = 0;
tind->index = 0;
tind->bits.data = 0;
@ -1666,7 +1713,7 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, float *fp, char *sp,
if (jo) {
// look for json input
char jvname[32];
char jvname[64];
strcpy(jvname, vname);
const char* str_value;
uint8_t aindex;
@ -1872,6 +1919,19 @@ chknext:
fvar = xPortGetCoreID();
goto exit;
}
#ifdef USE_M5STACK_CORE2
if (!strncmp(vname, "c2ps(", 5)) {
lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, 0);
while (*lp==' ') lp++;
float fvar1;
lp = GetNumericArgument(lp, OPER_EQU, &fvar1, 0);
fvar = core2_setaxppin(fvar, fvar1);
lp++;
len=0;
goto exit;
}
#endif // USE_M5STACK_CORE2
#ifdef USE_SCRIPT_TASK
if (!strncmp(vname, "ct(", 3)) {
lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, 0);
@ -2620,7 +2680,7 @@ chknext:
len++;
goto exit;
}
#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH))
#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2))
if (!strncmp(vname, "pl(", 3)) {
char path[SCRIPT_MAXSSIZE];
lp = GetStringArgument(lp + 3, OPER_EQU, path, 0);
@ -2813,7 +2873,7 @@ chknext:
len = 0;
goto strexit;
}
#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH))
#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2))
if (!strncmp(vname, "say(", 4)) {
char text[SCRIPT_MAXSSIZE];
lp = GetStringArgument(lp + 4, OPER_EQU, text, 0);
@ -3114,7 +3174,7 @@ chknext:
goto exit;
}
#endif // USE_TTGO_WATCH
#if defined(USE_TTGO_WATCH) && defined(USE_FT5206)
#if defined(USE_FT5206)
if (!strncmp(vname, "wtch(", 5)) {
lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, 0);
fvar = Touch_Status(fvar);
@ -3734,22 +3794,45 @@ void esp32_beep(int32_t freq ,uint32_t len) {
xTimerChangePeriod( beep_th, ticks, 10);
}
}
#endif // ESP32
void esp32_pwm(int32_t value) {
uint8_t pwmpin[5];
void esp_pwm(int32_t value, uint32 freq, uint32_t channel) {
if (channel < 1 || channel > 3) channel = 1;
#ifdef ESP32
channel+=7;
if (value < 0) {
if (value <= -64) value = 0;
ledcSetup(7, 4000, 10);
ledcAttachPin(-value, 7);
ledcWrite(7, 0);
// set range to 10 bit
ledcSetup(channel, freq, 10);
ledcAttachPin(-value, channel);
ledcWrite(channel, 0);
} else {
if (value > 1023) {
value = 1023;
}
ledcWrite(7, value);
ledcWrite(channel, value);
}
#else
// esp8266 default to range 0-1023
channel-=1;
if (value < 0) {
if (value <= -64) value = 0;
pwmpin[channel] = -value;
pinMode(pwmpin[channel], OUTPUT);
analogWriteFreq(freq);
analogWrite(pwmpin[channel], 0);
} else {
if (value > 1023) {
value = 1023;
}
analogWrite(pwmpin[channel],value);
}
#endif // ESP32
}
#endif // ESP32
//#define IFTHEN_DEBUG
@ -4164,14 +4247,34 @@ int16_t Run_script_sub(const char *type, int8_t tlen, JsonParserObject *jo) {
lp++;
goto next_line;
}
else if (!strncmp(lp, "pwm(", 4)) {
lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0);
#endif //ESP32
else if (!strncmp(lp, "pwm", 3)) {
lp += 3;
uint8_t channel = 1;
if (*(lp+1)=='(') {
channel = *lp & 7;
if (channel > 5) {
channel = 5;
}
lp += 2;
} else {
if (*lp=='(') {
lp++;
} else {
goto next_line;
}
}
lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0);
SCRIPT_SKIP_SPACES
esp32_pwm(fvar);
float fvar1=4000;
if (*lp!=')') {
lp = GetNumericArgument(lp, OPER_EQU, &fvar1, 0);
}
esp_pwm(fvar, fvar1, channel);
lp++;
goto next_line;
}
#endif //ESP32
else if (!strncmp(lp, "wcs", 3)) {
lp+=4;
// skip one space after cmd
@ -5116,7 +5219,16 @@ void SaveScript(void) {
#ifdef EEP_SCRIPT_SIZE
if (glob_script_mem.flags&1) {
#if EEP_SCRIPT_SIZE==SPI_FLASH_SEC_SIZE
EEP_WRITE(0, EEP_SCRIPT_SIZE, glob_script_mem.script_ram);
#else
char *ucs;
ucs = (char*)calloc(SPI_FLASH_SEC_SIZE + 4, 1);
if (!script_compress(ucs,EEP_SCRIPT_SIZE-1)) {
EEP_WRITE(0, EEP_SCRIPT_SIZE, ucs);
}
if (ucs) free(ucs);
#endif
}
#endif // EEP_SCRIPT_SIZE
@ -5198,6 +5310,21 @@ void ScriptSaveSettings(void) {
SaveScriptEnd();
}
//
uint32_t script_compress(char *dest, uint32_t size) {
//AddLog_P(LOG_LEVEL_INFO,PSTR("in string: %s len = %d"),glob_script_mem.script_ram,strlen(glob_script_mem.script_ram));
uint32_t len_compressed = SCRIPT_COMPRESS(glob_script_mem.script_ram, strlen(glob_script_mem.script_ram), dest, size);
if (len_compressed > 0) {
dest[len_compressed] = 0;
AddLog_P(LOG_LEVEL_INFO,PSTR("script compressed to %d bytes = %d %%"),len_compressed,len_compressed * 100 / strlen(glob_script_mem.script_ram));
return 0;
} else {
AddLog_P(LOG_LEVEL_INFO, PSTR("script compress error: %d"), len_compressed);
return 1;
}
}
//#endif // USE_SCRIPT_COMPRESSION
void SaveScriptEnd(void) {
#ifdef USE_SCRIPT_GLOBVARS
@ -5212,20 +5339,11 @@ void SaveScriptEnd(void) {
}
#ifdef USE_SCRIPT_COMPRESSION
//AddLog_P(LOG_LEVEL_INFO,PSTR("in string: %s len = %d"),glob_script_mem.script_ram,strlen(glob_script_mem.script_ram));
uint32_t len_compressed = SCRIPT_COMPRESS(glob_script_mem.script_ram, strlen(glob_script_mem.script_ram), Settings.rules[0], MAX_SCRIPT_SIZE-1);
if (len_compressed > 0) {
Settings.rules[0][len_compressed] = 0;
AddLog_P(LOG_LEVEL_INFO,PSTR("script compressed to %d bytes = %d %%"),len_compressed,len_compressed * 100 / strlen(glob_script_mem.script_ram));
} else {
AddLog_P(LOG_LEVEL_INFO, PSTR("script compress error: %d"), len_compressed);
}
script_compress(Settings.rules[0],MAX_SCRIPT_SIZE-1);
#endif // USE_SCRIPT_COMPRESSION
if (bitRead(Settings.rule_enabled, 0)) {
int16_t res = Init_Scripter();
if (res) {
AddLog_P(LOG_LEVEL_INFO, PSTR("script init error: %d"), res);
@ -5728,24 +5846,26 @@ bool Script_SubCmd(void) {
if (!bitRead(Settings.rule_enabled, 0)) return false;
if (tasm_cmd_activ) return false;
//AddLog_P(LOG_LEVEL_INFO,PSTR(">> %s, %s, %d, %d "),XdrvMailbox.topic, XdrvMailbox.data, XdrvMailbox.payload, XdrvMailbox.index);
char command[CMDSZ];
strlcpy(command, XdrvMailbox.topic, CMDSZ);
uint32_t pl = XdrvMailbox.payload;
char pld[64];
strlcpy(pld, XdrvMailbox.data, sizeof(pld));
if (XdrvMailbox.index > 1) {
char ind[2];
ind[0] = XdrvMailbox.index | 0x30;
ind[1] = 0;
strcat(command, ind);
}
int32_t pl = XdrvMailbox.payload;
char cmdbuff[128];
char *cp = cmdbuff;
*cp++ = '#';
strcpy(cp, XdrvMailbox.topic);
uint8_t tlen = strlen(XdrvMailbox.topic);
strcpy(cp, command);
uint8_t tlen = strlen(command);
cp += tlen;
if (XdrvMailbox.index > 0) {
*cp++ = XdrvMailbox.index | 0x30;
tlen++;
}
if ((XdrvMailbox.payload>0) || (XdrvMailbox.data_len>0)) {
if (XdrvMailbox.data_len>0) {
*cp++ = '(';
strncpy(cp, XdrvMailbox.data,XdrvMailbox.data_len);
cp += XdrvMailbox.data_len;
@ -5755,12 +5875,16 @@ bool Script_SubCmd(void) {
//toLog(cmdbuff);
uint32_t res = Run_Scripter(cmdbuff, tlen + 1, 0);
//AddLog_P(LOG_LEVEL_INFO,">>%d",res);
if (res) return false;
if (res) {
return false;
}
else {
if (pl>=0) {
Response_P(S_JSON_COMMAND_NVALUE, command, pl);
cp=XdrvMailbox.data;
while (*cp==' ') cp++;
if (isdigit(*cp) || *cp=='-') {
Response_P(S_JSON_COMMAND_NVALUE, command, XdrvMailbox.payload);
} else {
Response_P(S_JSON_COMMAND_SVALUE, command, pld);
Response_P(S_JSON_COMMAND_SVALUE, command, XdrvMailbox.data);
}
}
return true;
@ -6990,7 +7114,7 @@ exgc:
WSContentSend_PD("['");
char lbl[16];
if (todflg>=0) {
sprintf(lbl, "%d", todflg / divflg);
sprintf(lbl, "%d:%02d", todflg / divflg, (todflg % divflg) * (60 / divflg) );
todflg++;
if (todflg >= entries) {
todflg = 0;
@ -7395,9 +7519,10 @@ bool Xdrv10(uint8_t function)
#endif //USE_BUTTON_EVENT
#ifdef EEP_SCRIPT_SIZE
if (eeprom_init(EEP_SCRIPT_SIZE)) {
// found 32kb eeprom
if (EEP_INIT(EEP_SCRIPT_SIZE)) {
// found 32kb eeprom,
char *script;
#if EEP_SCRIPT_SIZE==SPI_FLASH_SEC_SIZE
script = (char*)calloc(EEP_SCRIPT_SIZE + 4, 1);
if (!script) break;
glob_script_mem.script_ram = script;
@ -7407,6 +7532,28 @@ bool Xdrv10(uint8_t function)
memset(script, EEP_SCRIPT_SIZE, 0);
}
script[EEP_SCRIPT_SIZE - 1] = 0;
#else
char *ucs;
ucs = (char*)calloc(SPI_FLASH_SEC_SIZE + 4, 1);
if (!ucs) break;
EEP_READ(0, SPI_FLASH_SEC_SIZE, ucs);
if (*ucs==0xff) {
memset(ucs, SPI_FLASH_SEC_SIZE, 0);
}
ucs[SPI_FLASH_SEC_SIZE - 1] = 0;
script = (char*)calloc(EEP_SCRIPT_SIZE + 4, 1);
if (!script) break;
glob_script_mem.script_ram = script;
glob_script_mem.script_size = EEP_SCRIPT_SIZE;
int32_t len_decompressed;
len_decompressed = SCRIPT_DECOMPRESS(ucs, strlen(ucs), glob_script_mem.script_ram, glob_script_mem.script_size);
if (len_decompressed>0) glob_script_mem.script_ram[len_decompressed] = 0;
if (ucs) free(ucs);
#endif
// use rules storage for permanent vars
glob_script_mem.script_pram = (uint8_t*)Settings.rules[0];
glob_script_mem.script_pram_size = MAX_SCRIPT_SIZE;
@ -7422,7 +7569,7 @@ bool Xdrv10(uint8_t function)
// fs on SD card
#ifdef ESP32
if (PinUsed(GPIO_SPI_MOSI) && PinUsed(GPIO_SPI_MISO) && PinUsed(GPIO_SPI_CLK)) {
SPI.begin(Pin(GPIO_SPI_CLK),Pin(GPIO_SPI_MISO),Pin(GPIO_SPI_MOSI), -1);
SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
}
#endif // ESP32
fsp = &SD;

View File

@ -2089,8 +2089,8 @@ uint32_t Touch_Status(uint32_t sel) {
#ifdef USE_TOUCH_BUTTONS
void Touch_MQTT(uint8_t index, const char *cp) {
ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, buttons[index]->vpower.on_off);
void Touch_MQTT(uint8_t index, const char *cp, uint32_t val) {
ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, val);
MqttPublishTeleSensor();
}
@ -2100,6 +2100,10 @@ void Touch_RDW_BUTT(uint32_t count, uint32_t pwr) {
else buttons[count]->vpower.on_off = 0;
}
#ifdef USE_M5STACK_CORE2
uint8_t tbstate[3];
#endif
// check digitizer hit
void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
uint16_t temp;
@ -2113,6 +2117,26 @@ uint8_t vbutt=0;
if (renderer) {
#ifdef USE_M5STACK_CORE2
// handle 3 built in touch buttons
uint16_t xcenter = 80;
#define TDELTA 30
#define TYPOS 275
for (uint32_t tbut = 0; tbut < 3; tbut++) {
if (pLoc.x>(xcenter-TDELTA) && pLoc.x<(xcenter+TDELTA) && pLoc.y>(TYPOS-TDELTA) && pLoc.y<(TYPOS+TDELTA)) {
// hit a button
if (!(tbstate[tbut] & 1)) {
// pressed
tbstate[tbut] |= 1;
//AddLog_P(LOG_LEVEL_INFO, PSTR("tbut: %d pressed"), tbut);
Touch_MQTT(tbut, "BIB", tbstate[tbut] & 1);
}
}
xcenter += 100;
}
#endif
rotconvert(&pLoc.x, &pLoc.y);
//AddLog_P(LOG_LEVEL_INFO, PSTR("touch %d - %d"), pLoc.x, pLoc.y);
@ -2142,7 +2166,7 @@ uint8_t vbutt=0;
cp="PBT";
}
buttons[count]->xdrawButton(buttons[count]->vpower.on_off);
Touch_MQTT(count,cp);
Touch_MQTT(count, cp, buttons[count]->vpower.on_off);
}
}
}
@ -2156,6 +2180,16 @@ uint8_t vbutt=0;
}
} else {
// no hit
#ifdef USE_M5STACK_CORE2
for (uint32_t tbut = 0; tbut < 3; tbut++) {
if (tbstate[tbut] & 1) {
// released
tbstate[tbut] &= 0xfe;
Touch_MQTT(tbut, "BIB", tbstate[tbut] & 1);
//AddLog_P(LOG_LEVEL_INFO, PSTR("tbut: %d released"), tbut);
}
}
#endif
for (uint8_t count=0; count<MAXBUTTONS; count++) {
if (buttons[count]) {
buttons[count]->press(false);
@ -2164,7 +2198,7 @@ uint8_t vbutt=0;
if (buttons[count]->vpower.is_pushbutton) {
// push button
buttons[count]->vpower.on_off = 0;
Touch_MQTT(count,"PBT");
Touch_MQTT(count,"PBT", buttons[count]->vpower.on_off);
buttons[count]->xdrawButton(buttons[count]->vpower.on_off);
}
}

View File

@ -1214,6 +1214,13 @@ void TuyaSetTime(void) {
uint16_t payload_len = 8;
uint8_t payload_buffer[8];
uint8_t tuya_day_of_week;
if (RtcTime.day_of_week == 1) {
tuya_day_of_week = 7;
} else {
tuya_day_of_week = RtcTime.day_of_week-1;
}
payload_buffer[0] = 0x01;
payload_buffer[1] = RtcTime.year %100;
payload_buffer[2] = RtcTime.month;
@ -1221,7 +1228,7 @@ void TuyaSetTime(void) {
payload_buffer[4] = RtcTime.hour;
payload_buffer[5] = RtcTime.minute;
payload_buffer[6] = RtcTime.second;
payload_buffer[7] = RtcTime.day_of_week;
payload_buffer[7] = tuya_day_of_week; //1 for Monday in TUYA Doc
TuyaSendCmd(TUYA_CMD_SET_TIME, payload_buffer, payload_len);
}

View File

@ -104,7 +104,7 @@ void HueRespondToMSearch(void)
snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE));
}
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
PrepLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"),
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"),
message, udp_remote_ip.toString().c_str(), udp_remote_port);
udp_response_mutex = false;

View File

@ -75,7 +75,7 @@ void WemoRespondToMSearch(int echo_type)
snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE));
}
// Do not use AddLog_P( here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
PrepLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
udp_response_mutex = false;

View File

@ -234,14 +234,18 @@ private:
int _deviceId;
String WemoSerialnumber(void) {
char serial[18];
char serial[20];
snprintf_P(serial, sizeof(serial), PSTR("201612K%08X-%d"), ESP_getChipId(), _deviceId);
char index[8] = { 0 };
if (_deviceId > 1) { // Keep backward compatibility
snprintf_P(index, sizeof(index), PSTR("%02X"), _deviceId);
}
snprintf_P(serial, sizeof(serial), PSTR("201612K%08X%s"), ESP_getChipId(), index);
return String(serial);
}
String WemoUuid(void) {
char uuid[29];
char uuid[32];
snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str());
return String(uuid);
@ -297,7 +301,7 @@ public:
snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE));
}
// Do not use AddLog_P here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
PrepLog_P(LOG_LEVEL_DEBUG, PSTR("WMO: WeMo Type %d, %s to %s:%d"),
AddLog_P(LOG_LEVEL_DEBUG, PSTR("WMO: WeMo Type %d, %s to %s:%d"),
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
}

View File

@ -90,6 +90,10 @@ public:
bool recv_until = false; // ignore all messages until the received frame fully matches
bool eeprom_present = false; // is the ZBBridge EEPROM present?
bool eeprom_ready = false; // is the ZBBridge EEPROM formatted and ready?
// Zigbee mapping
bool mapping_in_progress = false; // is there a mapping in progress
bool mapping_ready = false; // do we have mapping information ready
uint32_t mapping_end_time = 0;
uint8_t on_error_goto = ZIGBEE_LABEL_ABORT; // on error goto label, 99 default to abort
uint8_t on_timeout_goto = ZIGBEE_LABEL_ABORT; // on timeout goto label, 99 default to abort

View File

@ -717,6 +717,7 @@ public:
// sequence number for Zigbee frames
uint16_t shortaddr; // unique key if not null, or unspecified if null
uint8_t seqNumber;
bool is_router; // flag used by ZbMap to distibguish routers from end-devices
bool hidden;
bool reachable;
// Light information for Hue integration integration, last known values
@ -742,6 +743,7 @@ public:
attr_list(),
shortaddr(_shortaddr),
seqNumber(0),
is_router(false),
hidden(false),
reachable(false),
data(),
@ -768,6 +770,10 @@ public:
inline bool getReachable(void) const { return reachable; }
inline bool getPower(uint8_t ep =0) const;
inline bool isRouter(void) const { return is_router; }
inline bool isCoordinator(void) const { return 0x0000 == shortaddr; }
inline void setRouter(bool router) { is_router = router; }
inline void setLQI(uint8_t _lqi) { lqi = _lqi; }
inline void setBatteryPercent(uint8_t bp) { batterypercent = bp; }

View File

@ -304,7 +304,9 @@ void loadZigbeeDevices(bool dump_only = false) {
AddLog_P(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Cannot allocate 4KB buffer"));
return;
}
ZigbeeRead(&spi_buffer, z_spi_len);
#ifdef USE_TFS
TfsLoadFile("/zb", spi_buffer, z_spi_len);
#endif
z_dev_start = spi_buffer;
#endif // ESP32
Z_Flashentry flashdata;
@ -367,7 +369,9 @@ void saveZigbeeDevices(void) {
ESP.flashRead(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE);
#endif // ESP8266
#ifdef ESP32
ZigbeeRead(&spi_buffer, z_spi_len);
#ifdef USE_TFS
TfsLoadFile("/zb", spi_buffer, z_spi_len);
#endif
#endif // ESP32
Z_Flashentry *flashdata = (Z_Flashentry*)(spi_buffer + z_block_offset);
@ -385,7 +389,9 @@ void saveZigbeeDevices(void) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data store in Flash (0x%08X - %d bytes)"), z_dev_start, buf_len);
#endif // ESP8266
#ifdef ESP32
ZigbeeWrite(&spi_buffer, z_spi_len);
#ifdef USE_TFS
TfsSaveFile("/zb", spi_buffer, z_spi_len);
#endif
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data saved in %s (%d bytes)"), PSTR("Flash"), buf_len);
#endif // ESP32
free(spi_buffer);
@ -419,7 +425,9 @@ void eraseZigbeeDevices(void) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data erased in %s"), PSTR("Flash"));
#endif // ESP8266
#ifdef ESP32
ZigbeeErase();
#ifdef USE_TFS
TfsEraseFile("/zb", z_block_len);
#endif
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data erased (%d bytes)"), z_block_len);
#endif // ESP32
}

View File

@ -130,12 +130,13 @@ const char Z_strings[] PROGMEM =
"AnalogInMaxValue" "\x00"
"AnalogInMinValue" "\x00"
"AnalogInOutOfService" "\x00"
"AqaraRotate" "\x00"
"AnalogValue" "\x00"
"AnalogInReliability" "\x00"
"AnalogInResolution" "\x00"
"AnalogInStatusFlags" "\x00"
"AnalogInEngineeringUnits" "\x00"
"AnalogInApplicationType" "\x00"
"AqaraRotate" "\x00"
"Aqara_FF05" "\x00"
"AnalogOutDescription" "\x00"
"AnalogOutMaxValue" "\x00"
@ -150,7 +151,6 @@ const char Z_strings[] PROGMEM =
"AnalogOutApplicationType" "\x00"
"AnalogDescription" "\x00"
"AnalogOutOfService" "\x00"
"AnalogValue" "\x00"
"AnalogPriorityArray" "\x00"
"AnalogReliability" "\x00"
"AnalogRelinquishDefault" "\x00"
@ -275,6 +275,11 @@ const char Z_strings[] PROGMEM =
"ValvePosition" "\x00"
"EurotronicErrors" "\x00"
"CurrentTemperatureSetPoint" "\x00"
"EurotronicHostFlags" "\x00"
"TRVMirrorDisplay" "\x00"
"TRVBoost" "\x00"
"TRVWindowOpen" "\x00"
"TRVChildProtection" "\x00"
"ThSetpoint" "\x00"
"TempTarget" "\x00"
"Hue" "\x00"
@ -395,6 +400,7 @@ const char Z_strings[] PROGMEM =
"TuyaFanMode" "\x00"
"TuyaForceMode" "\x00"
"TuyaWeekSelect" "\x00"
"OppleMode" "\x00"
"TerncyDuration" "\x00"
"TerncyRotate" "\x00"
"Identify" "\x00"
@ -545,27 +551,27 @@ enum Z_offsets {
Zo_AnalogInMaxValue = 676,
Zo_AnalogInMinValue = 693,
Zo_AnalogInOutOfService = 710,
Zo_AqaraRotate = 731,
Zo_AnalogValue = 731,
Zo_AnalogInReliability = 743,
Zo_AnalogInResolution = 763,
Zo_AnalogInStatusFlags = 782,
Zo_AnalogInEngineeringUnits = 802,
Zo_AnalogInApplicationType = 827,
Zo_Aqara_FF05 = 851,
Zo_AnalogOutDescription = 862,
Zo_AnalogOutMaxValue = 883,
Zo_AnalogOutMinValue = 901,
Zo_AnalogOutOutOfService = 919,
Zo_AnalogOutValue = 941,
Zo_AnalogOutReliability = 956,
Zo_AnalogOutRelinquishDefault = 977,
Zo_AnalogOutResolution = 1004,
Zo_AnalogOutStatusFlags = 1024,
Zo_AnalogOutEngineeringUnits = 1045,
Zo_AnalogOutApplicationType = 1071,
Zo_AnalogDescription = 1096,
Zo_AnalogOutOfService = 1114,
Zo_AnalogValue = 1133,
Zo_AqaraRotate = 851,
Zo_Aqara_FF05 = 863,
Zo_AnalogOutDescription = 874,
Zo_AnalogOutMaxValue = 895,
Zo_AnalogOutMinValue = 913,
Zo_AnalogOutOutOfService = 931,
Zo_AnalogOutValue = 953,
Zo_AnalogOutReliability = 968,
Zo_AnalogOutRelinquishDefault = 989,
Zo_AnalogOutResolution = 1016,
Zo_AnalogOutStatusFlags = 1036,
Zo_AnalogOutEngineeringUnits = 1057,
Zo_AnalogOutApplicationType = 1083,
Zo_AnalogDescription = 1108,
Zo_AnalogOutOfService = 1126,
Zo_AnalogPriorityArray = 1145,
Zo_AnalogReliability = 1165,
Zo_AnalogRelinquishDefault = 1183,
@ -690,217 +696,223 @@ enum Z_offsets {
Zo_ValvePosition = 3473,
Zo_EurotronicErrors = 3487,
Zo_CurrentTemperatureSetPoint = 3504,
Zo_ThSetpoint = 3531,
Zo_TempTarget = 3542,
Zo_Hue = 3553,
Zo_Sat = 3557,
Zo_RemainingTime = 3561,
Zo_X = 3575,
Zo_Y = 3577,
Zo_DriftCompensation = 3579,
Zo_CompensationText = 3597,
Zo_CT = 3614,
Zo_ColorMode = 3617,
Zo_NumberOfPrimaries = 3627,
Zo_Primary1X = 3645,
Zo_Primary1Y = 3655,
Zo_Primary1Intensity = 3665,
Zo_Primary2X = 3683,
Zo_Primary2Y = 3693,
Zo_Primary2Intensity = 3703,
Zo_Primary3X = 3721,
Zo_Primary3Y = 3731,
Zo_Primary3Intensity = 3741,
Zo_WhitePointX = 3759,
Zo_WhitePointY = 3771,
Zo_ColorPointRX = 3783,
Zo_ColorPointRY = 3796,
Zo_ColorPointRIntensity = 3809,
Zo_ColorPointGX = 3830,
Zo_ColorPointGY = 3843,
Zo_ColorPointGIntensity = 3856,
Zo_ColorPointBX = 3877,
Zo_ColorPointBY = 3890,
Zo_ColorPointBIntensity = 3903,
Zo_Illuminance = 3924,
Zo_IlluminanceMinMeasuredValue = 3936,
Zo_IlluminanceMaxMeasuredValue = 3964,
Zo_IlluminanceTolerance = 3992,
Zo_IlluminanceLightSensorType = 4013,
Zo_IlluminanceLevelStatus = 4040,
Zo_IlluminanceTargetLevel = 4063,
Zo_Temperature = 4086,
Zo_TemperatureMinMeasuredValue = 4098,
Zo_TemperatureMaxMeasuredValue = 4126,
Zo_TemperatureTolerance = 4154,
Zo_Pressure = 4175,
Zo_PressureMinMeasuredValue = 4184,
Zo_PressureMaxMeasuredValue = 4209,
Zo_PressureTolerance = 4234,
Zo_PressureScaledValue = 4252,
Zo_PressureMinScaledValue = 4272,
Zo_PressureMaxScaledValue = 4295,
Zo_PressureScaledTolerance = 4318,
Zo_PressureScale = 4342,
Zo_SeaPressure = 4356,
Zo_FlowRate = 4368,
Zo_FlowMinMeasuredValue = 4377,
Zo_FlowMaxMeasuredValue = 4398,
Zo_FlowTolerance = 4419,
Zo_Humidity = 4433,
Zo_HumidityMinMeasuredValue = 4442,
Zo_HumidityMaxMeasuredValue = 4467,
Zo_HumidityTolerance = 4492,
Zo_Occupancy = 4510,
Zo_OccupancySensorType = 4520,
Zo_ZoneState = 4540,
Zo_ZoneType = 4550,
Zo_ZoneStatus = 4559,
Zo_CIE = 4570,
Zo_Contact = 4574,
Zo_Fire = 4582,
Zo_Water = 4587,
Zo_CO = 4593,
Zo_PersonalAlarm = 4596,
Zo_Movement = 4610,
Zo_Panic = 4619,
Zo_GlassBreak = 4625,
Zo_EnergyTotal = 4636,
Zo_CompanyName = 4648,
Zo_MeterTypeID = 4660,
Zo_DataQualityID = 4672,
Zo_CustomerName = 4686,
Zo_Model = 4699,
Zo_PartNumber = 4705,
Zo_ProductRevision = 4716,
Zo_SoftwareRevision = 4732,
Zo_UtilityName = 4749,
Zo_POD = 4761,
Zo_AvailablePower = 4765,
Zo_PowerThreshold = 4780,
Zo_RMSVoltage = 4795,
Zo_RMSCurrent = 4806,
Zo_ActivePower = 4817,
Zo_ReactivePower = 4829,
Zo_ApparentPower = 4843,
Zo_NumberOfResets = 4857,
Zo_PersistentMemoryWrites = 4872,
Zo_LastMessageLQI = 4895,
Zo_LastMessageRSSI = 4910,
Zo_TuyaScheduleWorkdays = 4926,
Zo_TuyaScheduleHolidays = 4947,
Zo_Power2 = 4968,
Zo_Power3 = 4975,
Zo_Power4 = 4982,
Zo_TuyaChildLock = 4989,
Zo_TuyaWindowDetection = 5003,
Zo_TuyaValveDetection = 5023,
Zo_TuyaAutoLock = 5042,
Zo_TuyaTempTarget = 5055,
Zo_TuyaBattery = 5070,
Zo_TuyaMinTemp = 5082,
Zo_TuyaMaxTemp = 5094,
Zo_TuyaBoostTime = 5106,
Zo_TuyaComfortTemp = 5120,
Zo_TuyaEcoTemp = 5136,
Zo_TuyaValvePosition = 5148,
Zo_TuyaAwayTemp = 5166,
Zo_TuyaAwayDays = 5179,
Zo_TuyaPreset = 5192,
Zo_TuyaFanMode = 5203,
Zo_TuyaForceMode = 5215,
Zo_TuyaWeekSelect = 5229,
Zo_TerncyDuration = 5244,
Zo_TerncyRotate = 5259,
Zo_Identify = 5272,
Zo_xxxx = 5281,
Zo_IdentifyQuery = 5286,
Zo_AddGroup = 5300,
Zo_xxxx00 = 5309,
Zo_ViewGroup = 5316,
Zo_GetGroup = 5326,
Zo_01xxxx = 5335,
Zo_GetAllGroups = 5342,
Zo_00 = 5355,
Zo_RemoveGroup = 5358,
Zo_RemoveAllGroups = 5370,
Zo_ViewScene = 5386,
Zo_xxxxyy = 5396,
Zo_RemoveScene = 5403,
Zo_RemoveAllScenes = 5415,
Zo_RecallScene = 5431,
Zo_GetSceneMembership = 5443,
Zo_PowerOffEffect = 5462,
Zo_xxyy = 5477,
Zo_PowerOnRecall = 5482,
Zo_PowerOnTimer = 5496,
Zo_xxyyyyzzzz = 5509,
Zo_xx0A00 = 5520,
Zo_DimmerUp = 5527,
Zo_00190200 = 5536,
Zo_DimmerDown = 5545,
Zo_01190200 = 5556,
Zo_DimmerStop = 5565,
Zo_ResetAlarm = 5576,
Zo_xxyyyy = 5587,
Zo_ResetAllAlarms = 5594,
Zo_xx000A00 = 5609,
Zo_HueSat = 5618,
Zo_xxyy0A00 = 5625,
Zo_Color = 5634,
Zo_xxxxyyyy0A00 = 5640,
Zo_xxxx0A00 = 5653,
Zo_ShutterOpen = 5662,
Zo_ShutterClose = 5674,
Zo_ShutterStop = 5687,
Zo_ShutterLift = 5699,
Zo_xx = 5711,
Zo_ShutterTilt = 5714,
Zo_Shutter = 5726,
Zo_DimmerMove = 5734,
Zo_xx0A = 5745,
Zo_DimmerStepUp = 5750,
Zo_00xx0A00 = 5763,
Zo_DimmerStepDown = 5772,
Zo_01xx0A00 = 5787,
Zo_DimmerStep = 5796,
Zo_xx190A00 = 5807,
Zo_01 = 5816,
Zo_HueMove = 5819,
Zo_xx19 = 5827,
Zo_HueStepUp = 5832,
Zo_HueStepDown = 5842,
Zo_03xx0A00 = 5854,
Zo_HueStep = 5863,
Zo_SatMove = 5871,
Zo_SatStep = 5879,
Zo_xx190A = 5887,
Zo_ColorMove = 5894,
Zo_xxxxyyyy = 5904,
Zo_ColorStep = 5913,
Zo_ColorTempMoveUp = 5923,
Zo_01xxxx000000000000 = 5939,
Zo_ColorTempMoveDown = 5958,
Zo_03xxxx000000000000 = 5976,
Zo_ColorTempMoveStop = 5995,
Zo_00xxxx000000000000 = 6013,
Zo_ColorTempMove = 6032,
Zo_xxyyyy000000000000 = 6046,
Zo_ColorTempStepUp = 6065,
Zo_01xxxx0A0000000000 = 6081,
Zo_ColorTempStepDown = 6100,
Zo_03xxxx0A0000000000 = 6118,
Zo_ColorTempStep = 6137,
Zo_xxyyyy0A0000000000 = 6151,
Zo_ArrowClick = 6170,
Zo_ArrowHold = 6181,
Zo_ArrowRelease = 6191,
Zo_ZoneStatusChange = 6204,
Zo_xxxxyyzz = 6221,
Zo_xxyyzzzz = 6230,
Zo_AddScene = 6239,
Zo_xxyyyyzz = 6248,
Zo_StoreScene = 6257,
Zo_EurotronicHostFlags = 3531,
Zo_TRVMirrorDisplay = 3551,
Zo_TRVBoost = 3568,
Zo_TRVWindowOpen = 3577,
Zo_TRVChildProtection = 3591,
Zo_ThSetpoint = 3610,
Zo_TempTarget = 3621,
Zo_Hue = 3632,
Zo_Sat = 3636,
Zo_RemainingTime = 3640,
Zo_X = 3654,
Zo_Y = 3656,
Zo_DriftCompensation = 3658,
Zo_CompensationText = 3676,
Zo_CT = 3693,
Zo_ColorMode = 3696,
Zo_NumberOfPrimaries = 3706,
Zo_Primary1X = 3724,
Zo_Primary1Y = 3734,
Zo_Primary1Intensity = 3744,
Zo_Primary2X = 3762,
Zo_Primary2Y = 3772,
Zo_Primary2Intensity = 3782,
Zo_Primary3X = 3800,
Zo_Primary3Y = 3810,
Zo_Primary3Intensity = 3820,
Zo_WhitePointX = 3838,
Zo_WhitePointY = 3850,
Zo_ColorPointRX = 3862,
Zo_ColorPointRY = 3875,
Zo_ColorPointRIntensity = 3888,
Zo_ColorPointGX = 3909,
Zo_ColorPointGY = 3922,
Zo_ColorPointGIntensity = 3935,
Zo_ColorPointBX = 3956,
Zo_ColorPointBY = 3969,
Zo_ColorPointBIntensity = 3982,
Zo_Illuminance = 4003,
Zo_IlluminanceMinMeasuredValue = 4015,
Zo_IlluminanceMaxMeasuredValue = 4043,
Zo_IlluminanceTolerance = 4071,
Zo_IlluminanceLightSensorType = 4092,
Zo_IlluminanceLevelStatus = 4119,
Zo_IlluminanceTargetLevel = 4142,
Zo_Temperature = 4165,
Zo_TemperatureMinMeasuredValue = 4177,
Zo_TemperatureMaxMeasuredValue = 4205,
Zo_TemperatureTolerance = 4233,
Zo_Pressure = 4254,
Zo_PressureMinMeasuredValue = 4263,
Zo_PressureMaxMeasuredValue = 4288,
Zo_PressureTolerance = 4313,
Zo_PressureScaledValue = 4331,
Zo_PressureMinScaledValue = 4351,
Zo_PressureMaxScaledValue = 4374,
Zo_PressureScaledTolerance = 4397,
Zo_PressureScale = 4421,
Zo_SeaPressure = 4435,
Zo_FlowRate = 4447,
Zo_FlowMinMeasuredValue = 4456,
Zo_FlowMaxMeasuredValue = 4477,
Zo_FlowTolerance = 4498,
Zo_Humidity = 4512,
Zo_HumidityMinMeasuredValue = 4521,
Zo_HumidityMaxMeasuredValue = 4546,
Zo_HumidityTolerance = 4571,
Zo_Occupancy = 4589,
Zo_OccupancySensorType = 4599,
Zo_ZoneState = 4619,
Zo_ZoneType = 4629,
Zo_ZoneStatus = 4638,
Zo_CIE = 4649,
Zo_Contact = 4653,
Zo_Fire = 4661,
Zo_Water = 4666,
Zo_CO = 4672,
Zo_PersonalAlarm = 4675,
Zo_Movement = 4689,
Zo_Panic = 4698,
Zo_GlassBreak = 4704,
Zo_EnergyTotal = 4715,
Zo_CompanyName = 4727,
Zo_MeterTypeID = 4739,
Zo_DataQualityID = 4751,
Zo_CustomerName = 4765,
Zo_Model = 4778,
Zo_PartNumber = 4784,
Zo_ProductRevision = 4795,
Zo_SoftwareRevision = 4811,
Zo_UtilityName = 4828,
Zo_POD = 4840,
Zo_AvailablePower = 4844,
Zo_PowerThreshold = 4859,
Zo_RMSVoltage = 4874,
Zo_RMSCurrent = 4885,
Zo_ActivePower = 4896,
Zo_ReactivePower = 4908,
Zo_ApparentPower = 4922,
Zo_NumberOfResets = 4936,
Zo_PersistentMemoryWrites = 4951,
Zo_LastMessageLQI = 4974,
Zo_LastMessageRSSI = 4989,
Zo_TuyaScheduleWorkdays = 5005,
Zo_TuyaScheduleHolidays = 5026,
Zo_Power2 = 5047,
Zo_Power3 = 5054,
Zo_Power4 = 5061,
Zo_TuyaChildLock = 5068,
Zo_TuyaWindowDetection = 5082,
Zo_TuyaValveDetection = 5102,
Zo_TuyaAutoLock = 5121,
Zo_TuyaTempTarget = 5134,
Zo_TuyaBattery = 5149,
Zo_TuyaMinTemp = 5161,
Zo_TuyaMaxTemp = 5173,
Zo_TuyaBoostTime = 5185,
Zo_TuyaComfortTemp = 5199,
Zo_TuyaEcoTemp = 5215,
Zo_TuyaValvePosition = 5227,
Zo_TuyaAwayTemp = 5245,
Zo_TuyaAwayDays = 5258,
Zo_TuyaPreset = 5271,
Zo_TuyaFanMode = 5282,
Zo_TuyaForceMode = 5294,
Zo_TuyaWeekSelect = 5308,
Zo_OppleMode = 5323,
Zo_TerncyDuration = 5333,
Zo_TerncyRotate = 5348,
Zo_Identify = 5361,
Zo_xxxx = 5370,
Zo_IdentifyQuery = 5375,
Zo_AddGroup = 5389,
Zo_xxxx00 = 5398,
Zo_ViewGroup = 5405,
Zo_GetGroup = 5415,
Zo_01xxxx = 5424,
Zo_GetAllGroups = 5431,
Zo_00 = 5444,
Zo_RemoveGroup = 5447,
Zo_RemoveAllGroups = 5459,
Zo_ViewScene = 5475,
Zo_xxxxyy = 5485,
Zo_RemoveScene = 5492,
Zo_RemoveAllScenes = 5504,
Zo_RecallScene = 5520,
Zo_GetSceneMembership = 5532,
Zo_PowerOffEffect = 5551,
Zo_xxyy = 5566,
Zo_PowerOnRecall = 5571,
Zo_PowerOnTimer = 5585,
Zo_xxyyyyzzzz = 5598,
Zo_xx0A00 = 5609,
Zo_DimmerUp = 5616,
Zo_00190200 = 5625,
Zo_DimmerDown = 5634,
Zo_01190200 = 5645,
Zo_DimmerStop = 5654,
Zo_ResetAlarm = 5665,
Zo_xxyyyy = 5676,
Zo_ResetAllAlarms = 5683,
Zo_xx000A00 = 5698,
Zo_HueSat = 5707,
Zo_xxyy0A00 = 5714,
Zo_Color = 5723,
Zo_xxxxyyyy0A00 = 5729,
Zo_xxxx0A00 = 5742,
Zo_ShutterOpen = 5751,
Zo_ShutterClose = 5763,
Zo_ShutterStop = 5776,
Zo_ShutterLift = 5788,
Zo_xx = 5800,
Zo_ShutterTilt = 5803,
Zo_Shutter = 5815,
Zo_DimmerMove = 5823,
Zo_xx0A = 5834,
Zo_DimmerStepUp = 5839,
Zo_00xx0A00 = 5852,
Zo_DimmerStepDown = 5861,
Zo_01xx0A00 = 5876,
Zo_DimmerStep = 5885,
Zo_xx190A00 = 5896,
Zo_01 = 5905,
Zo_HueMove = 5908,
Zo_xx19 = 5916,
Zo_HueStepUp = 5921,
Zo_HueStepDown = 5931,
Zo_03xx0A00 = 5943,
Zo_HueStep = 5952,
Zo_SatMove = 5960,
Zo_SatStep = 5968,
Zo_xx190A = 5976,
Zo_ColorMove = 5983,
Zo_xxxxyyyy = 5993,
Zo_ColorStep = 6002,
Zo_ColorTempMoveUp = 6012,
Zo_01xxxx000000000000 = 6028,
Zo_ColorTempMoveDown = 6047,
Zo_03xxxx000000000000 = 6065,
Zo_ColorTempMoveStop = 6084,
Zo_00xxxx000000000000 = 6102,
Zo_ColorTempMove = 6121,
Zo_xxyyyy000000000000 = 6135,
Zo_ColorTempStepUp = 6154,
Zo_01xxxx0A0000000000 = 6170,
Zo_ColorTempStepDown = 6189,
Zo_03xxxx0A0000000000 = 6207,
Zo_ColorTempStep = 6226,
Zo_xxyyyy0A0000000000 = 6240,
Zo_ArrowClick = 6259,
Zo_ArrowHold = 6270,
Zo_ArrowRelease = 6280,
Zo_ZoneStatusChange = 6293,
Zo_xxxxyyzz = 6310,
Zo_xxyyzzzz = 6319,
Zo_AddScene = 6328,
Zo_xxyyyyzz = 6337,
Zo_StoreScene = 6346,
};

View File

@ -127,7 +127,7 @@ enum Cx_cluster_short {
Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0100,
Cx0101, Cx0102, Cx0201, Cx0300, Cx0400, Cx0401, Cx0402, Cx0403,
Cx0404, Cx0405, Cx0406, Cx0500, Cx0702, Cx0B01, Cx0B04, Cx0B05,
CxEF00, CxFCCC,
CxEF00, CxFCC0, CxFCCC,
};
const uint16_t Cx_cluster[] PROGMEM = {
@ -136,7 +136,7 @@ const uint16_t Cx_cluster[] PROGMEM = {
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0100,
0x0101, 0x0102, 0x0201, 0x0300, 0x0400, 0x0401, 0x0402, 0x0403,
0x0404, 0x0405, 0x0406, 0x0500, 0x0702, 0x0B01, 0x0B04, 0x0B05,
0xEF00, 0xFCCC,
0xEF00, 0xFCC0, 0xFCCC,
};
uint16_t CxToCluster(uint8_t cx) {
@ -466,6 +466,13 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Zuint8, Cx0201, 0x4001, Z_(ValvePosition), Cm1, 0 },
{ Zuint8, Cx0201, 0x4002, Z_(EurotronicErrors), Cm1, 0 },
{ Zint16, Cx0201, 0x4003, Z_(CurrentTemperatureSetPoint), Cm_100, 0 },
{ Zuint24, Cx0201, 0x4008, Z_(EurotronicHostFlags), Cm1, 0 },
// below are synthetic virtual attributes used to decode EurotronicHostFlags
// Last byte acts as a field mask for the lowest byte value
{ Zbool, Cx0201, 0xF002, Z_(TRVMirrorDisplay), Cm1, 0 },
{ Zbool, Cx0201, 0xF004, Z_(TRVBoost), Cm1, 0 },
{ Zbool, Cx0201, 0xF010, Z_(TRVWindowOpen), Cm1, 0 },
{ Zbool, Cx0201, 0xF080, Z_(TRVChildProtection), Cm1, 0 },
// below are virtual attributes to simplify ZbData import/export
{ Zuint8, Cx0201, 0xFFF0, Z_(ThSetpoint), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Zint16, Cx0201, 0xFFF1, Z_(TempTarget), Cm_100 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, temperature_target) },
@ -618,15 +625,15 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Ztuya1, CxEF00, 0x0112, Z_(TuyaWindowDetection), Cm1, 0 },
{ Ztuya1, CxEF00, 0x0114, Z_(TuyaValveDetection), Cm1, 0 },
{ Ztuya1, CxEF00, 0x0174, Z_(TuyaAutoLock), Cm1, 0 },
{ Ztuya2, CxEF00, 0x0202, Z_(TuyaTempTarget), Cm_10, 0 },
{ Ztuya2, CxEF00, 0x0203, Z_(LocalTemperature), Cm_10, 0 }, // will be overwritten by actual LocalTemperature
{ Zint16, CxEF00, 0x0202, Z_(TuyaTempTarget), Cm_10, Z_MAPPING(Z_Data_Thermo, temperature_target) },
{ Zint16, CxEF00, 0x0203, Z_(LocalTemperature), Cm_10, Z_MAPPING(Z_Data_Thermo, temperature) }, // will be overwritten by actual LocalTemperature
{ Ztuya2, CxEF00, 0x0215, Z_(TuyaBattery), Cm1, 0 }, // TODO check equivalent?
{ Ztuya2, CxEF00, 0x0266, Z_(TuyaMinTemp), Cm1, 0 },
{ Ztuya2, CxEF00, 0x0267, Z_(TuyaMaxTemp), Cm1, 0 },
{ Ztuya2, CxEF00, 0x0269, Z_(TuyaBoostTime), Cm1, 0 },
{ Ztuya2, CxEF00, 0x026B, Z_(TuyaComfortTemp), Cm1, 0 },
{ Ztuya2, CxEF00, 0x026C, Z_(TuyaEcoTemp), Cm1, 0 },
{ Ztuya2, CxEF00, 0x026D, Z_(TuyaValvePosition), Cm1, 0 },
{ Zuint8, CxEF00, 0x026D, Z_(TuyaValvePosition), Cm1, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Ztuya2, CxEF00, 0x0272, Z_(TuyaAwayTemp), Cm1, 0 },
{ Ztuya2, CxEF00, 0x0275, Z_(TuyaAwayDays), Cm1, 0 },
{ Ztuya4, CxEF00, 0x0404, Z_(TuyaPreset), Cm1, 0 },
@ -634,6 +641,9 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Ztuya4, CxEF00, 0x046A, Z_(TuyaForceMode), Cm1, 0 },
{ Ztuya4, CxEF00, 0x046F, Z_(TuyaWeekSelect), Cm1, 0 },
// Aqara Opple spacific
{ Zbool, CxFCC0, 0x0009, Z_(OppleMode), Cm1, 0 },
// Terncy specific - 0xFCCC
{ Zuint16, CxFCCC, 0x001A, Z_(TerncyDuration), Cm1, 0 },
{ Zint16, CxFCCC, 0x001B, Z_(TerncyRotate), Cm1, 0 },
@ -876,6 +886,11 @@ int32_t encodeSingleAttribute(class SBuffer &buf, double val_d, const char *val_
buf.add16(u32);
break;
// unisgned 32
case Zuint24:
buf.add16(u32);
buf.add8(u32 >> 16);
break;
// unisgned 24
case Zuint32: // uint32
case Zdata32: // data32
case Zmap32: // map32
@ -971,6 +986,15 @@ uint32_t parseSingleAttribute(Z_attribute & attr, const SBuffer &buf,
}
}
break;
case Zuint24:
{
uint32_t uint24_val = buf.get16(i) + (buf.get8(i+2) >> 16);
// i += 3;
if (0xFFFFFF != uint24_val) {
attr.setUInt(uint24_val);
}
}
break;
case Zuint32: // uint32
case ZUTC: // UTC
{
@ -1277,15 +1301,24 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) {
}
break;
case 0x02010008: // Pi Heating Demand - solve Eutotronic bug
case 0x02014008: // Eurotronic Host Flags decoding
{
const char * manufacturer_c = zigbee_devices.getManufacturerId(_srcaddr); // null if unknown
String manufacturerId((char*) manufacturer_c);
if (manufacturerId.equals(F("Eurotronic"))) {
if (ccccaaaa == 0x02010008) {
// Eurotronic does not report 0..100 but 0..255, including 255 which is normally an ivalid value
uint8_t valve = attr.getUInt();
if (attr.isNone()) { valve = 255; }
uint8_t valve_100 = changeUIntScale(valve, 0, 255, 0, 100);
attr.setUInt(valve_100);
} else if (ccccaaaa == 0x02014008) {
uint32_t mode = attr.getUInt();
if (mode & 0x02) { attr_list.addAttribute(0x0201, 0xF002).setUInt(1); }
if (mode & 0x04) { attr_list.addAttribute(0x0201, 0xF004).setUInt(1); }
if (mode & 0x10) { attr_list.addAttribute(0x0201, 0xF010).setUInt(1); }
if (mode & 0x80) { attr_list.addAttribute(0x0201, 0xF080).setUInt(1); }
}
}
}
break;
@ -1583,6 +1616,9 @@ void ZCLFrame::syntheticAnalogValue(Z_attribute_list &attr_list, class Z_attribu
if (modelId.startsWith(F("lumi.plug"))) {
attr.setKeyId(0x0702, 0x0000); // change to EnergyTotal
}
if (modelId.startsWith(F("lumi.ctrl"))) {
attr.setKeyId(0x0B04, 0x050B); // change to ActivePower
}
}
@ -1637,9 +1673,9 @@ void ZCLFrame::syntheticAqaraSensor(Z_attribute_list &attr_list, class Z_attribu
} else if (0x66 == attrid) {
attr_list.addAttribute(0x0403, 0x0000).setUInt((ival32 + 50) / 100); // Pressure
}
} else if (modelId.startsWith(F("lumi.plug"))) {
} else if (modelId.startsWith(F("lumi.plug")) || modelId.startsWith(F("lumi.ctrl"))) {
if (0x64 == attrid) {
attr_list.addAttribute(0x0600, 0x0000).setInt(uval32); // Power (on/off)
attr_list.addAttribute(0x0006, 0x0000).setInt(uval32); // Power (on/off)
} else if (0x98 == attrid) {
attr_list.addAttribute(0x0B04, 0x050B).setInt(ival32); // Active Power
} else if (0x95 == attrid) {
@ -1896,6 +1932,13 @@ void Z_postProcessAttributes(uint16_t shortaddr, uint16_t src_ep, class Z_attrib
uint32_t uval32 = attr.getUInt(); // call converter to uint only once
int32_t ival32 = attr.getInt(); // call converter to int only once
// AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Mapping type=%d offset=%d zigbee_type=%02X value=%d\n"), (uint8_t) map_type, map_offset, zigbee_type, ival32);
switch (ccccaaaa) {
case 0xEF000202:
case 0xEF000203: // need to convert Tuya temperatures from 1/10 to 1/00 °C
ival32 = ival32 * 10;
break;
}
switch (zigbee_type) {
case Zenum8:
case Zmap8:

View File

@ -0,0 +1,180 @@
/*
xdrv_23_zigbee_7_5_map.ino - zigbee support for Tasmota
Copyright (C) 2020 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
class Z_Mapper_Edge {
public:
// enum Edge_Type : uint8_t {
// Unknown = 0x00,
// Parent = 0x01, // node_1 is parent of node_2
// Child = 0x02, // node_1 is child of node_2
// Sibling = 0x03, // both nodes are siblings
// };
Z_Mapper_Edge(void) :
node_1(BAD_SHORTADDR),
node_2(BAD_SHORTADDR),
lqi(0x00)
// edge_type(Unknown)
{}
// Z_Mapper_Edge(uint16_t node_a, uint16_t node_b, uint8_t _lqi, Edge_Type _type) :
Z_Mapper_Edge(uint16_t node_a, uint16_t node_b, uint8_t _lqi) :
node_1(BAD_SHORTADDR),
node_2(BAD_SHORTADDR),
lqi(_lqi)
// edge_type(_type)
{
setEdges(node_a, node_b);
}
void setEdges(uint16_t node_a, uint16_t node_b);
bool sameEdge(const Z_Mapper_Edge & edge2) const;
// Edge_Type Z_Mapper_Edge_Type_Reverse(Edge_Type _type) {
// switch (_type) {
// case Parent: return Child;
// case Child: return Parent;
// default: return _type;
// }
// }
// we always orientate the edge from with shortaddresses in ascending order
// invariant: node_1 < node_2
uint16_t node_1;
uint16_t node_2;
uint8_t lqi;
// Edge_Type edge_type;
};
//
// Handles the mapping of Zigbee devices
//
class Z_Mapper {
public:
Z_Mapper(void) :
edges()
{}
void reset(void) { edges.reset(); }
Z_Mapper_Edge & findEdge(const Z_Mapper_Edge & edge2);
bool addEdge(const Z_Mapper_Edge & edge2);
void dumpInternals(void) const;
LList<Z_Mapper_Edge> edges;
};
// global
Z_Mapper zigbee_mapper;
/*********************************************************************************************\
* Implementation for Z_Mapper_Edge
\*********************************************************************************************/
void Z_Mapper_Edge::setEdges(uint16_t node_a, uint16_t node_b) {
if (node_a < node_b) {
node_1 = node_a;
node_2 = node_b;
} else if (node_a > node_b) {
node_1 = node_b;
node_2 = node_a;
} else {
// do nothing
}
}
bool Z_Mapper_Edge::sameEdge(const Z_Mapper_Edge & edge2) const {
return (node_1 == edge2.node_1) && (node_2 == edge2.node_2);
}
/*********************************************************************************************\
* Implementation for Z_Mapper
\*********************************************************************************************/
Z_Mapper_Edge & Z_Mapper::findEdge(const Z_Mapper_Edge & edge2) {
if ((edge2.node_1 == BAD_SHORTADDR) || (edge2.node_2 == BAD_SHORTADDR)) { return *(Z_Mapper_Edge*)nullptr; }
for (auto & edge : edges) {
if (edge2.sameEdge(edge)) {
return edge;
}
}
return *(Z_Mapper_Edge*)nullptr;
}
bool Z_Mapper::addEdge(const Z_Mapper_Edge & edge2) {
if ((edge2.node_1 == BAD_SHORTADDR) || (edge2.node_2 == BAD_SHORTADDR)) { return false; }
Z_Mapper_Edge & cur_edge = findEdge(edge2);
if (&cur_edge == nullptr) {
edges.addHead(edge2);
} else {
//upgrade fields
if (edge2.lqi > cur_edge.lqi) {
cur_edge.lqi = edge2.lqi;
}
// if (cur_edge.edge_type == Z_Mapper_Edge::Unknown) {
// cur_edge.edge_type = edge2.edge_type;
// } else if ((edge2.edge_type == Z_Mapper_Edge::Parent) || (edge2.edge_type == Z_Mapper_Edge::Child)) {
// // Parent or Child always has priority over Sibling
// cur_edge.edge_type = edge2.edge_type;
// }
}
return true;
}
void Z_Mapper::dumpInternals(void) const {
WSContentSend_P(PSTR("nodes:[" "{id:\"0x0000\",label:\"Coordinator\",group:\"o\",title:\"0x0000\"}"));
for (const auto & device : zigbee_devices.getDevices()) {
WSContentSend_P(PSTR(",{id:\"0x%04X\",group:\"%c\",title:\"0x%04X\",label:\""),
device.shortaddr, device.isRouter() ? 'r' : 'e', device.shortaddr);
const char *fname = device.friendlyName;
if (fname != nullptr) {
WSContentSend_P(PSTR("%s"), fname);
} else {
WSContentSend_P(PSTR("0x%04X"), device.shortaddr);
}
WSContentSend_P("\"}");
}
WSContentSend_P(PSTR("],"));
WSContentSend_P(PSTR("edges:["));
for (auto & edge : edges) {
uint32_t lqi_color = 0x000;
// if (edge.lqi >= 192) {
// lqi_color = 0x364;
// } else if (edge.lqi >= 128) {
// lqi_color = 0x346;
// } else if (edge.lqi > 0) {
// lqi_color = 0xd56;
// }
char hex[8];
snprintf(hex, sizeof(hex), PSTR("%d"), edge.lqi);
WSContentSend_P("{from:\"0x%04X\",to:\"0x%04X\",label:\"%s\",color:\"#%03X\"},",
edge.node_1, edge.node_2, (edge.lqi > 0) ? hex : "", lqi_color);
}
WSContentSend_P(PSTR("],"));
}
#endif // USE_ZIGBEE

View File

@ -229,7 +229,7 @@ void Z_Send_State_or_Map(uint16_t shortaddr, uint8_t index, uint16_t zdo_cmd) {
// This callback is registered to send ZbMap(s) to each device one at a time
void Z_Map(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
if (BAD_SHORTADDR != shortaddr) {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "sending `ZnMap 0x%04X`"), shortaddr);
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "sending `ZbMap 0x%04X`"), shortaddr);
#ifdef USE_ZIGBEE_ZNP
Z_Send_State_or_Map(shortaddr, value, ZDO_MGMT_LQI_REQ);
#endif // USE_ZIGBEE_ZNP
@ -238,6 +238,8 @@ void Z_Map(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t end
#endif // USE_ZIGBEE_EZSP
} else {
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbMap done"));
zigbee.mapping_in_progress = false;
zigbee.mapping_ready = true;
}
}
/*********************************************************************************************\
@ -1057,6 +1059,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi)
// device is reachable
zigbee_devices.deviceWasReached(shortaddr);
bool non_empty = false; // check whether the response contains relevant information
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
@ -1087,6 +1090,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi)
uint8_t m_lqi = buf.get8(idx + 21);
idx += 22;
non_empty = true;
if (i > 0) {
ResponseAppend_P(PSTR(","));
}
@ -1110,6 +1114,27 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi)
TrueFalseNull(m_permitjoin & 0x02),
m_depth,
m_lqi);
// detect any router
Z_Device & device = zigbee_devices.findShortAddr(m_shortaddr);
if (device.valid()) {
if ((m_dev_type & 0x03) == 1) { // it is a router
device.setRouter(true);
}
}
// Add information to zigbee mapper
// Z_Mapper_Edge::Edge_Type edge_type;
// switch ((m_dev_type & 0x70) >> 4) {
// case 0: edge_type = Z_Mapper_Edge::Parent; break;
// case 1: edge_type = Z_Mapper_Edge::Child; break;
// case 2: edge_type = Z_Mapper_Edge::Sibling; break;
// default: edge_type = Z_Mapper_Edge::Unknown; break;
// }
// Z_Mapper_Edge edge(m_shortaddr, shortaddr, m_lqi, edge_type);
Z_Mapper_Edge edge(m_shortaddr, shortaddr, m_lqi);
zigbee_mapper.addEdge(edge);
}
ResponseAppend_P(PSTR("]}}"));
@ -1138,6 +1163,7 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi)
break; // abort for any other value since we don't know the length of the field
}
non_empty = true;
if (i > 0) {
ResponseAppend_P(PSTR(","));
}
@ -1157,7 +1183,8 @@ int32_t Z_Mgmt_Lqi_Bind_Rsp(int32_t res, const class SBuffer &buf, boolean lqi)
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_MAP));
// Check if there are more values waiting, if so re-send a new request to get other values
if (start + len < total) {
// Only send a new request if the current was non-empty. This avoids an infinite loop if the device announces more slots that it actually has.
if ((non_empty) && (start + len < total)) {
// there are more values to read
#ifdef USE_ZIGBEE_ZNP
Z_Send_State_or_Map(shortaddr, start + len, lqi ? ZDO_MGMT_LQI_REQ : ZDO_MGMT_BIND_REQ);

View File

@ -1052,6 +1052,26 @@ void CmndZbBindState(void) {
CmndZbBindState_or_Map(false);
}
void ZigbeeMapAllDevices(void) {
// we can't abort a mapping in progress
if (zigbee.mapping_in_progress) { return; }
// defer sending ZbMap to each device
zigbee_mapper.reset(); // clear all data in Zigbee mapper
const static uint32_t DELAY_ZBMAP = 2000; // wait for 1s between commands
uint32_t wait_ms = DELAY_ZBMAP;
zigbee.mapping_in_progress = true; // mark mapping in progress
zigbee_devices.setTimer(0x0000, 0, 0 /*wait_ms*/, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
for (const auto & device : zigbee_devices.getDevices()) {
zigbee_devices.setTimer(device.shortaddr, 0, wait_ms, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
wait_ms += DELAY_ZBMAP;
}
wait_ms += DELAY_ZBMAP*2;
zigbee_devices.setTimer(BAD_SHORTADDR, 0, wait_ms, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
zigbee.mapping_end_time = wait_ms + millis();
}
//
// Command `ZbMap`
// `ZbMap<x>` as index if it does not fit. If default, `1` starts at the beginning
@ -1061,15 +1081,7 @@ void CmndZbMap(void) {
RemoveSpace(XdrvMailbox.data);
if (strlen(XdrvMailbox.data) == 0) {
// defer sending ZbMap to each device
const static uint32_t DELAY_ZBMAP = 2000; // wait for 1s between commands
uint32_t wait_ms = DELAY_ZBMAP;
zigbee_devices.setTimer(0x0000, 0, 0 /*wait_ms*/, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
for (const auto & device : zigbee_devices.getDevices()) {
zigbee_devices.setTimer(device.shortaddr, 0, wait_ms, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
wait_ms += DELAY_ZBMAP;
}
zigbee_devices.setTimer(BAD_SHORTADDR, 0, wait_ms, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
ZigbeeMapAllDevices();
ResponseCmndDone();
} else {
CmndZbBindState_or_Map(true);
@ -1317,8 +1329,8 @@ void CmndZbSave(void) {
case -10:
{ // reinit EEPROM
ZFS::erase();
break;
}
break;
#endif
default:
saveZigbeeDevices();
@ -1698,6 +1710,16 @@ extern "C" {
}
} // extern "C"
#define WEB_HANDLE_ZB_MAP "Zigbee Map"
#define WEB_HANDLE_ZB_PERMIT_JOIN "Zigbee Permit Join"
#define WEB_HANDLE_ZB_MAP_REFRESH "Zigbee Map Refresh"
const char HTTP_BTN_ZB_BUTTONS[] PROGMEM =
"<button onclick='la(\"&zbj=1\");'>" WEB_HANDLE_ZB_PERMIT_JOIN "</button>"
"<p></p>"
"<form action='zbm' method='get'><button>" WEB_HANDLE_ZB_MAP "</button></form>";
const char HTTP_AUTO_REFRESH_PAGE[] PROGMEM = "<script>setTimeout(function(){location.reload();},1990);</script>";
const char HTTP_BTN_ZB_MAP_REFRESH[] PROGMEM = "<p></p><form action='zbr' method='get'><button>" WEB_HANDLE_ZB_MAP_REFRESH "</button></form>";
void ZigbeeShow(bool json)
{
if (json) {
@ -1879,11 +1901,67 @@ void ZigbeeShow(bool json)
}
}
WSContentSend_P(PSTR("</table>{t}")); // Terminate current multi column table and open new table
WSContentSend_P(PSTR("</table>{t}<p></p>")); // Terminate current multi column table and open new table
if (zigbee.permit_end_time) {
// PermitJoin in progress
WSContentSend_P(PSTR("<p><b>[ <span style='color:#080;'>Devices allowed to join</span> ]</b></p>")); // Terminate current multi column table and open new table
}
#endif
}
}
// Web handler to refresh the map, the redirect to show map
void ZigbeeMapRefresh(void) {
if ((!zigbee.init_phase) && (!zigbee.mapping_in_progress)) {
ZigbeeMapAllDevices();
}
Webserver->sendHeader("Location","/zbm"); // Add a header to respond with a new location for the browser to go to the home page again
Webserver->send(302);
}
// Display a graphical representation of the Zigbee map using vis.js network
void ZigbeeShowMap(void) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Zigbee Mapper"));
// if no map, then launch a new mapping
if ((!zigbee.init_phase) && (!zigbee.mapping_ready) && (!zigbee.mapping_in_progress)) {
ZigbeeMapAllDevices();
}
WSContentStart_P(PSTR("Tasmota Zigbee Mapping"));
WSContentSendStyle();
if (zigbee.init_phase) {
WSContentSend_P(PSTR("Zigbee not started"));
} else if (zigbee.mapping_in_progress) {
int32_t mapping_remaining = 1 + (zigbee.mapping_end_time - millis()) / 1000;
if (mapping_remaining < 0) { mapping_remaining = 0; }
WSContentSend_P(PSTR("Mapping in progress (%d s. remaining)"), mapping_remaining);
WSContentSend_P(HTTP_AUTO_REFRESH_PAGE);
} else if (!zigbee.mapping_ready) {
WSContentSend_P(PSTR("No mapping"));
} else {
WSContentSend_P(PSTR(
"<script type=\"text/javascript\" src=\"https://unpkg.com/vis-network/standalone/umd/vis-network.min.js\"></script>"
"<div id=\"mynetwork\" style=\"background-color:#fff;color:#000;width:800px;height:400px;border:1px solid lightgray;resize:both;\">Unable to load vis.js</div>"
"<script type=\"text/javascript\">"
"var container=document.getElementById(\"mynetwork\");"
"var options={groups:{o:{shape:\"circle\",color:\"#d55\"},r:{shape:\"box\",color:\"#fb7\"},e:{shape:\"ellipse\",color:\"#adf\"}}};"
"var data={"
));
zigbee_mapper.dumpInternals();
WSContentSend_P(PSTR(
"};"
"var network=new vis.Network(container,data,options);</script>"
));
WSContentSend_P(HTTP_BTN_ZB_MAP_REFRESH);
}
WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
@ -1920,12 +1998,17 @@ bool Xdrv23(uint8_t function)
case FUNC_WEB_SENSOR:
ZigbeeShow(false);
break;
#ifdef USE_ZIGBEE_EZSP
// GUI xmodem
case FUNC_WEB_ADD_HANDLER:
#ifdef USE_ZIGBEE_EZSP
WebServer_on(PSTR("/" WEB_HANDLE_ZIGBEE_XFER), HandleZigbeeXfer);
break;
#endif // USE_ZIGBEE_EZSP
WebServer_on(PSTR("/zbm"), ZigbeeShowMap, HTTP_GET); // add web handler for Zigbee map
WebServer_on(PSTR("/zbr"), ZigbeeMapRefresh, HTTP_GET); // add web handler for Zigbee map refresh
break;
case FUNC_WEB_ADD_MAIN_BUTTON:
WSContentSend_P(HTTP_BTN_ZB_BUTTONS);
break;
#endif // USE_WEBSERVER
case FUNC_PRE_INIT:
ZigbeeInit();

View File

@ -160,7 +160,7 @@ int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index)
if (Settings.shutter_set50percent[index] != 50) {
return (percent <= 5) ? Settings.shuttercoeff[2][index] * percent*10 : (Settings.shuttercoeff[1][index] * percent + (Settings.shuttercoeff[0][index]*10))*10;
} else {
uint32_t realpos;
int64_t realpos;
// check against DIV 0
for (uint32_t j = 0; j < 5; j++) {
if (0 == Settings.shuttercoeff[j][index]) {
@ -173,13 +173,15 @@ int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index)
for (uint32_t k = 0; k < 5; k++) {
if ((percent * 10) >= Settings.shuttercoeff[k][index]) {
realpos = SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[k+1], 100);
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("Realposition TEMP1: %d, %% %d, coeff %d"), realpos, percent, Settings.shuttercoeff[i][index]);
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Realposition TEMP1: %d, %d %%, coeff %d"), realpos, percent, Settings.shuttercoeff[k][index]);
} else {
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Shutter[%d].open_max: %d"),index, Shutter[index].open_max);
if (0 == k) {
realpos = SHT_DIV_ROUND(SHT_DIV_ROUND(percent * Shutter[index].open_max * calibrate_pos[k+1], Settings.shuttercoeff[k][index]), 10);
realpos = SHT_DIV_ROUND(SHT_DIV_ROUND(percent * Shutter[index].open_max * calibrate_pos[k+1], Settings.shuttercoeff[k][index]), 10 );
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Realposition TEMP3: %d, %d %%, coeff %d"), realpos, percent, Settings.shuttercoeff[k][index]);
} else {
//uint16_t addon = ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter_Open_Max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100;
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("Realposition TEMP2: %d, %% %d, coeff %d"), addon, (calibrate_pos[i+1] - calibrate_pos[i]), (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]));
//uint32_t addon = ( percent*10 - Settings.shuttercoeff[k-1][index] ) * Shutter[index].open_max * (calibrate_pos[k+1] - calibrate_pos[k]) / (Settings.shuttercoeff[k][index] -Settings.shuttercoeff[k-1][index]) / 100;
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Realposition TEMP2: %d, %d %%, coeff %d"), addon, (calibrate_pos[k+1] - calibrate_pos[k]), (Settings.shuttercoeff[k][index] -Settings.shuttercoeff[k-1][index]));
realpos += SHT_DIV_ROUND(SHT_DIV_ROUND((percent*10 - Settings.shuttercoeff[k-1][index] ) * Shutter[index].open_max * (calibrate_pos[k+1] - calibrate_pos[k]), Settings.shuttercoeff[k][index] - Settings.shuttercoeff[k-1][index]), 100);
}
break;
@ -189,25 +191,26 @@ int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index)
}
}
uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index)
uint8_t ShutterRealToPercentPosition(int64_t realpos, uint32_t index)
{
if (Settings.shutter_set50percent[index] != 50) {
return (Settings.shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, Settings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-Settings.shuttercoeff[0][index]*10, Settings.shuttercoeff[1][index]);
} else {
uint16_t realpercent;
uint64_t realpercent;
for (uint32_t j = 0; j < 5; j++) {
if (realpos >= Shutter[index].open_max * calibrate_pos[j+1] / 100) {
realpercent = SHT_DIV_ROUND(Settings.shuttercoeff[j][index], 10);
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("Realpercent TEMP1: %d, %% %d, coeff %d"), realpercent, realpos, Shutter_Open_Max[index] * calibrate_pos[i+1] / 100);
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Realpercent TEMP1: %d %%, %d, coeff %d"), realpercent, realpos, Shutter[index].open_max * calibrate_pos[j+1] / 100);
} else {
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Shutter[%d].open_max: %d"),index, Shutter[index].open_max);
if (0 == j) {
realpercent = SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[j], 100)) * 10 * Settings.shuttercoeff[j][index], calibrate_pos[j+1]), Shutter[index].open_max);
realpercent = SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[j], 100)) * Settings.shuttercoeff[j][index], calibrate_pos[j+1]/10), Shutter[index].open_max);
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Realpercent TEMP3: %d %%, %d, coeff %d"), realpercent, realpos, Shutter[index].open_max * calibrate_pos[j+1] / 100);
} else {
//uint16_t addon = ( realpos - (Shutter_Open_Max[index] * calibrate_pos[i] / 100) ) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]) / (calibrate_pos[i+1] - calibrate_pos[i])/ Shutter_Open_Max[index];
//uint16_t addon = ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter_Open_Max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100;
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("Realpercent TEMP2: %d, delta %d, %% %d, coeff %d"), addon,( realpos - (Shutter_Open_Max[index] * calibrate_pos[i] / 100) ) , (calibrate_pos[i+1] - calibrate_pos[i])* Shutter_Open_Max[index]/100, (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]));
realpercent += SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[j], 100)) * 10 * (Settings.shuttercoeff[j][index] - Settings.shuttercoeff[j-1][index]), (calibrate_pos[j+1] - calibrate_pos[j])), Shutter[index].open_max) ;
//uint16_t addon = ( realpos - (Shutter[index].open_max * calibrate_pos[j] / 100) ) * 10 * (Settings.shuttercoeff[j][index] - Settings.shuttercoeff[j-1][index]) / (calibrate_pos[j+1] - calibrate_pos[j])/Shutter[index].open_max;
//uint16_t addon = ( realpercent*10 - Settings.shuttercoeff[j-1][index] ) * Shutter[index].open_max * (calibrate_pos[j+1] - calibrate_pos[j]) / (Settings.shuttercoeff[j][index] -Settings.shuttercoeff[j-1][index]) / 100;
//AddLog_P(LOG_LEVEL_ERROR, PSTR("Realpercent TEMP2: %d %%, delta %d, %d, coeff %d"), addon,( realpos - (Shutter[index].open_max * calibrate_pos[j] / 100) ) , (calibrate_pos[j+1] - calibrate_pos[j])* Shutter[index].open_max/100, (Settings.shuttercoeff[j][index] -Settings.shuttercoeff[j-1][index]));
realpercent += SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[j], 100)) * (Settings.shuttercoeff[j][index] - Settings.shuttercoeff[j-1][index]), (calibrate_pos[j+1] - calibrate_pos[j])/10), Shutter[index].open_max) ;
}
break;
}
@ -430,10 +433,6 @@ void ShutterDecellerateForStop(uint8_t i)
void ShutterPowerOff(uint8_t i) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SHT: Stop Shutter %d. Switchmode %d"), i,Shutter[i].switch_mode);
ShutterDecellerateForStop(i);
if (Shutter[i].direction !=0) {
Shutter[i].direction = 0;
delay(MOTOR_STOP_TIME);
}
switch (Shutter[i].switch_mode) {
case SHT_SWITCH:
if ((1 << (Settings.shutter_startrelay[i]-1)) & TasmotaGlobal.power) {
@ -449,7 +448,7 @@ void ShutterPowerOff(uint8_t i) {
if ((SRC_PULSETIMER == TasmotaGlobal.last_source || SRC_SHUTTER == TasmotaGlobal.last_source || SRC_WEBGUI == TasmotaGlobal.last_source)) {
ExecuteCommandPowerShutter(cur_relay, 1, SRC_SHUTTER);
// switch off direction relay to make it power less
if ((1 << (Settings.shutter_startrelay[i])) & TasmotaGlobal.power) {
if (((1 << (Settings.shutter_startrelay[i])) & TasmotaGlobal.power) && Settings.shutter_startrelay[i]+1 != cur_relay) {
ExecuteCommandPowerShutter(Settings.shutter_startrelay[i]+1, 0, SRC_SHUTTER);
}
} else {
@ -465,6 +464,10 @@ void ShutterPowerOff(uint8_t i) {
ExecuteCommand(scmnd, SRC_BUTTON);
break;
}
if (Shutter[i].direction !=0) {
Shutter[i].direction = 0;
delay(MOTOR_STOP_TIME);
}
}
void ShutterUpdatePosition(void)
@ -616,7 +619,7 @@ void ShutterRelayChanged(void)
break;
default:
TasmotaGlobal.last_source = SRC_SHUTTER; // avoid switch off in the next loop
if (Shutter[i].direction != 0 ) ShutterPowerOff(i);
if (Shutter[i].direction != 0 ) Shutter[i].target_position = Shutter[i].real_position;
}
switch (ShutterGlobal.position_mode) {
// enum Shutterposition_mode {SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,};
@ -981,15 +984,10 @@ void CmndShutterStop(void)
if (Shutter[i].direction != 0) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SHT: Stop moving %d: dir: %d"), XdrvMailbox.index, Shutter[i].direction);
int32_t temp_realpos = ShutterCalculatePosition(i);
XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i);
TasmotaGlobal.last_source = SRC_WEBGUI;
CmndShutterPosition();
} else {
Shutter[i].target_position = Shutter[i].real_position;
}
if (XdrvMailbox.command)
ResponseCmndDone();
}
} else {
if (XdrvMailbox.command)
ResponseCmndIdxChar("Locked");

View File

@ -76,6 +76,7 @@ bool tap_handled = false;
bool invert_power_button_bri_direction = false;
bool button_pressed[3] = { false, false, false };
bool button_held[3];
bool button_unprocessed[3] = { false, false, false };
#ifdef USE_PWM_DIMMER_REMOTE
struct remote_pwm_dimmer remote_pwm_dimmers[MAX_PWM_DIMMER_KEYS];
struct remote_pwm_dimmer * active_remote_pwm_dimmer;
@ -284,8 +285,18 @@ void PWMDimmerHandleButton(uint32_t button_index, bool pressed)
if (pressed) {
uint32_t now = millis();
// If this is about the power button, ...
if (is_power_button) {
// If the button was pressed and released but was not processed by support_button because the
// button interval had not elapsed,
if (button_unprocessed[button_index]) {
mqtt_trigger = 5;
#ifdef USE_PWM_DIMMER_REMOTE
if (!active_remote_pwm_dimmer) mqtt_trigger += button_index;
#endif // USE_PWM_DIMMER_REMOTE
button_hold_time[button_index] = now + 750;
}
// Otherwise, if this is about the power button, ...
else if (is_power_button) {
// If we're not ignoring the power button and no other buttons are pressed, ...
if (!ignore_power_button && buttons_pressed == 1) {
@ -325,8 +336,8 @@ void PWMDimmerHandleButton(uint32_t button_index, bool pressed)
// If the up or down button was tapped while holding the power button before this, handle
// the operation below.
if (button_tapped) {
handle_tap = true;
button_hold_time[button_index] = now + 500;
handle_tap = ignore_power_button = true;
button_hold_time[button_index] = now + 750;
}
// Otherwise, if the power is on and remote mode is enabled, adjust the brightness. Set the
@ -568,7 +579,7 @@ void PWMDimmerHandleButton(uint32_t button_index, bool pressed)
// If the up or down button was tapped while holding the power button and the up or down button
// is being held or was just released after not being held, handle the operation.
if (handle_tap) {
ignore_power_button = tap_handled = true;
tap_handled = true;
// If the down button was tapped while holding the power button, send a device group update to
// select the previous/next fixed color.
@ -591,9 +602,10 @@ void PWMDimmerHandleButton(uint32_t button_index, bool pressed)
#endif // USE_DEVICE_GROUPS
;
}
// If the down button was tapped while holding the power button, publish an MQTT Event Trigger#.
// If the up button was tapped while holding the power button, publish an MQTT Event Trigger#.
else {
mqtt_trigger = (is_down_button ? 3 : 4);
mqtt_trigger = 3;
if (is_down_button) mqtt_trigger = 4;
}
}
@ -739,7 +751,15 @@ bool Xdrv35(uint8_t function)
// increment the buttons pressed count.
if (!button_pressed[button_index]) {
button_pressed[button_index] = true;
button_hold_time[button_index] = now + (button_index == power_button_index ? 500 : 250);
uint32_t hold_delay = 250;
if (button_index == power_button_index) {
#ifdef USE_PWM_DIMMER_REMOTE
if (!(active_remote_pwm_dimmer ? active_remote_pwm_dimmer->power_on : TasmotaGlobal.power)) hold_delay = 500;
#else // USE_PWM_DIMMER_REMOTE
if (!TasmotaGlobal.power) hold_delay = 500;
#endif // USE_PWM_DIMMER_REMOTE
}
button_hold_time[button_index] = now + hold_delay;
buttons_pressed++;
if (buttons_pressed > 1) multibutton_in_progress = true;
@ -796,6 +816,16 @@ bool Xdrv35(uint8_t function)
// Set a timer so FUNC_ANY_KEY ignores the button if support_button winds up sending a
// key because of this.
ignore_any_key_time = now + 500;
// If a multi-button operation is in progress or the button was pressed, released and
// then held, tell support_button that we've handled it.
result = true;
Button.press_counter[button_index] = 0;
if (buttons_pressed == 0) multibutton_in_progress = false;
button_unprocessed[button_index] = false;
}
else {
button_unprocessed[button_index] = true;
}
// If the power button was just released, clear the flags associated with it.
@ -806,12 +836,6 @@ bool Xdrv35(uint8_t function)
}
button_held[button_index] = false;
}
// If a multi-button operation is in progress, tell support_button that we've handled it.
if (multibutton_in_progress) {
result = true;
if (buttons_pressed == 0) multibutton_in_progress = false;
}
}
break;
@ -819,7 +843,9 @@ bool Xdrv35(uint8_t function)
{
uint32_t state = (XdrvMailbox.payload >> 8) & 0xFF; // 0 = Off, 1 = On, 2 = Toggle, 3 = Hold, 10,11,12,13 and 14 for Button Multipress
if ((state == 2 || state == 10) && ignore_any_key_time < millis()) {
PWMDimmerHandleButton((XdrvMailbox.payload & 0xFF) - 1, false);
uint32_t button_index = (XdrvMailbox.payload & 0xFF) - 1;
button_unprocessed[button_index] = false;
PWMDimmerHandleButton(button_index, false);
}
}
break;

View File

@ -289,21 +289,19 @@ void TelegramSendGetMe(void) {
String TelegramExecuteCommand(const char *svalue) {
String response = "";
uint32_t curridx = TasmotaGlobal.web_log_index;
uint32_t curridx = TasmotaGlobal.log_buffer_pointer;
ExecuteCommand(svalue, SRC_CHAT);
if (TasmotaGlobal.web_log_index != curridx) {
uint32_t counter = curridx;
if (TasmotaGlobal.log_buffer_pointer != curridx) {
response = F("{");
bool cflg = false;
do {
char* tmp;
uint32_t index = curridx;
char* line;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(tmp, '{', len);
while (GetLog(Settings.weblog_level, &index, &line, &len)) {
// [14:49:36.123 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(line, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - (JSON - tmp);
size_t JSONlen = len - (JSON - line);
if (JSONlen > sizeof(TasmotaGlobal.mqtt_data)) { JSONlen = sizeof(TasmotaGlobal.mqtt_data); }
char stemp[JSONlen];
strlcpy(stemp, JSON +1, JSONlen -2);
@ -312,10 +310,6 @@ String TelegramExecuteCommand(const char *svalue) {
cflg = true;
}
}
counter++;
counter &= 0xFF;
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != TasmotaGlobal.web_log_index);
response += F("}");
} else {
response = F("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}");

View File

@ -90,16 +90,16 @@ AudioGeneratorTalkie *talkie = nullptr;
#define TWATCH_DAC_IIS_DOUT 3
#endif // ESP8266
#ifdef ESP32
#undef TWATCH_DAC_IIS_BCK
#undef TWATCH_DAC_IIS_WS
#undef TWATCH_DAC_IIS_DOUT
#ifndef TWATCH_DAC_IIS_BCK
#undef TWATCH_DAC_IIS_BCK
#define TWATCH_DAC_IIS_BCK 26
#endif
#ifndef TWATCH_DAC_IIS_WS
#undef TWATCH_DAC_IIS_WS
#define TWATCH_DAC_IIS_WS 25
#endif
#ifndef TWATCH_DAC_IIS_DOUT
#undef TWATCH_DAC_IIS_DOUT
#define TWATCH_DAC_IIS_DOUT 33
#endif
#endif // ESP32

View File

@ -626,9 +626,9 @@ bool ShdSendVersion(void)
void ShdGetSettings(void)
{
char parameters[32];
Shd.req_brightness = 0;
// Shd.req_brightness = 0;
Shd.leading_edge = 0;
Shd.req_fade_rate = 0;
// Shd.req_fade_rate = 0;
Shd.warmup_brightness = 0;
Shd.warmup_time = 0;
if (strstr(SettingsText(SET_SHD_PARAM), ",") != nullptr)
@ -636,9 +636,9 @@ void ShdGetSettings(void)
#ifdef SHELLY_DIMMER_DEBUG
AddLog_P(LOG_LEVEL_INFO, PSTR(SHD_LOGNAME "Loading params: %s"), SettingsText(SET_SHD_PARAM));
#endif // SHELLY_DIMMER_DEBUG
Shd.req_brightness = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 1));
// Shd.req_brightness = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 1));
Shd.leading_edge = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 2));
Shd.req_fade_rate = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 3));
// Shd.req_fade_rate = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 3));
Shd.warmup_brightness = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 4));
Shd.warmup_time = atoi(subStr(parameters, SettingsText(SET_SHD_PARAM), ",", 5));
}

266
tasmota/xdrv_84_core2.ino Normal file
View File

@ -0,0 +1,266 @@
/*
xdrv_84_core2.ino - ESP32 m5stack core2 support for Tasmota
Copyright (C) 2020 Gerhard Mutz and Theo Arends
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/>.
*/
/* remaining work:
i2s microphone, at least as loudness sensor
rtc use after reboot, sync with internet on regular intervals.
*/
#ifdef ESP32
#ifdef USE_M5STACK_CORE2
#include <AXP192.h>
#include <MPU6886.h>
#include <BM8563_RTC.h>
#include <i2c_bus.h>
#include <soc/rtc.h>
#define XDRV_84 84
struct CORE2_globs {
AXP192 Axp;
MPU6886 Mpu;
BM8563_RTC Rtc;
bool ready;
bool tset;
uint32_t shutdownseconds;
uint8_t shutdowndelay;
} core2_globs;
struct CORE2_ADC {
float vbus_v;
float batt_v;
float temp;
int16_t x;
int16_t y;
int16_t z;
} core2_adc;
// cause SC card is needed by scripter
void CORE2_Module_Init(void) {
// m5stack uses pin 38 not selectable in tasmota
SPI.setFrequency(40000000);
SPI.begin(18, 38, 23, -1);
// establish power chip on wire1 SDA 21, SCL 22
core2_globs.Axp.begin();
I2cSetActiveFound(AXP_ADDR, "AXP192");
core2_globs.Axp.SetAdcState(true);
core2_globs.Mpu.Init();
I2cSetActiveFound(MPU6886_ADDRESS, "MPU6886");
core2_globs.Rtc.begin();
I2cSetActiveFound(RTC_ADRESS, "RTC");
core2_globs.ready = true;
}
void CORE2_Init(void) {
}
void CORE2_audio_power(bool power) {
core2_globs.Axp.SetSpkEnable(power);
}
#ifdef USE_WEBSERVER
const char HTTP_CORE2[] PROGMEM =
"{s}VBUS Voltage" "{m}%s V" "{e}"
"{s}BATT Voltage" "{m}%s V" "{e}"
"{s}Chip Temperature" "{m}%s C" "{e}";
#ifdef USE_MPU6886
const char HTTP_CORE2_MPU[] PROGMEM =
"{s}MPU x" "{m}%d mg" "{e}"
"{s}MPU y" "{m}%d mg" "{e}"
"{s}MPU z" "{m}%d mg" "{e}";
#endif // USE_MPU6886
#endif // USE_WEBSERVER
void CORE2_loop(uint32_t flg) {
}
void CORE2_WebShow(uint32_t json) {
char vstring[32];
char bvstring[32];
char tstring[32];
dtostrfd(core2_adc.vbus_v, 3, vstring);
dtostrfd(core2_adc.batt_v, 3, bvstring);
dtostrfd(core2_adc.temp, 2, tstring);
if (json) {
ResponseAppend_P(PSTR(",\"CORE2\":{\"VBV\":%s,\"BV\":%s,\"CT\":%s"), vstring, bvstring, tstring);
#ifdef USE_MPU6886
ResponseAppend_P(PSTR(",\"MPUX\":%d,\"MPUY\":%d,\"MPUZ\":%d"), core2_adc.x, core2_adc.y, core2_adc.z);
#endif
ResponseJsonEnd();
} else {
WSContentSend_PD(HTTP_CORE2, vstring, bvstring, tstring);
#ifdef USE_MPU6886
WSContentSend_PD(HTTP_CORE2_MPU, core2_adc.x, core2_adc.y, core2_adc.z);
#endif // USE_MPU6886
}
}
const char CORE2_Commands[] PROGMEM = "CORE2|"
"SHUTDOWN";
void (* const CORE2_Command[])(void) PROGMEM = {
&CORE2_Shutdown};
void CORE2_Shutdown(void) {
if (XdrvMailbox.payload >= 30) {
core2_globs.shutdownseconds = XdrvMailbox.payload;
core2_globs.shutdowndelay = 10;
}
ResponseCmndNumber(XdrvMailbox.payload -2);
}
void CORE2_DoShutdown(void) {
SettingsSaveAll();
RtcSettingsSave();
core2_globs.Rtc.clearIRQ();
core2_globs.Rtc.SetAlarmIRQ(core2_globs.shutdownseconds);
delay(10);
core2_globs.Axp.PowerOff();
}
extern uint8_t tbstate[3];
float core2_setaxppin(uint32_t sel, uint32_t val) {
switch (sel) {
case 0:
core2_globs.Axp.SetLed(val);
break;
case 1:
core2_globs.Axp.SetLDOEnable(3, val);
break;
case 2:
if (val<1 || val>3) val = 1;
return tbstate[val - 1] & 1;
break;
}
return 0;
}
void core2_disp_pwr(uint8_t on) {
core2_globs.Axp.SetDCDC3(on);
}
// display dimmer ranges from 0-15
// very little effect
void core2_disp_dim(uint8_t dim) {
uint16_t voltage = 2200;
voltage += ((uint32_t)dim*1200)/15;
core2_globs.Axp.SetLcdVoltage(voltage);
// core2_globs.Axp.ScreenBreath(dim);
}
void CORE2_EverySecond(void) {
if (core2_globs.ready) {
CORE2_GetADC();
if (RtcTime.year>2000 && core2_globs.tset==false) {
RTC_TimeTypeDef RTCtime;
RTCtime.Hours = RtcTime.hour;
RTCtime.Minutes = RtcTime.minute;
RTCtime.Seconds = RtcTime.second;
core2_globs.Rtc.SetTime(&RTCtime);
core2_globs.tset = true;
}
if (core2_globs.shutdowndelay) {
core2_globs.shutdowndelay--;
if (!core2_globs.shutdowndelay) {
CORE2_DoShutdown();
}
}
}
}
// currents are not supported by hardware implementation
void CORE2_GetADC(void) {
core2_adc.vbus_v = core2_globs.Axp.GetVBusVoltage();
core2_adc.batt_v = core2_globs.Axp.GetBatVoltage();
core2_adc.temp = core2_globs.Axp.GetTempInAXP192();
#ifdef USE_MPU6886
float x;
float y;
float z;
core2_globs.Mpu.getAccelData(&x, &y, &z);
core2_adc.x=x*1000;
core2_adc.y=y*1000;
core2_adc.z=z*1000;
#endif // USE_MPU6886
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv84(uint8_t function) {
bool result = false;
switch (function) {
case FUNC_WEB_SENSOR:
#ifdef USE_WEBSERVER
CORE2_WebShow(0);
#endif
break;
case FUNC_JSON_APPEND:
CORE2_WebShow(1);
break;
case FUNC_COMMAND:
result = DecodeCommand(CORE2_Commands, CORE2_Command);
break;
case FUNC_MODULE_INIT:
CORE2_Module_Init();
break;
case FUNC_INIT:
CORE2_Init();
break;
case FUNC_EVERY_SECOND:
CORE2_EverySecond();
break;
case FUNC_LOOP:
CORE2_loop(1);
break;
}
return result;
}
#endif // USE_M5STACK_CORE2
#endif // ESP32

View File

@ -20,7 +20,7 @@
//#ifdef USE_SPI
#ifdef USE_SPI
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_ILI9341_2
#if (defined(USE_DISPLAY_ILI9341_2) || defined(USE_DISPLAY_ILI9342))
#define XDSP_13 13
@ -42,9 +42,13 @@ extern uint8_t *buffer;
extern uint8_t color_type;
ILI9341_2 *ili9341_2;
#ifdef USE_FT5206
#include <FT5206.h>
#undef FT6336_address
#define FT6336_address 0x38
uint8_t ili9342_ctouch_counter = 0;
#endif // USE_FT5206
#undef BACKPLANE_PIN
#define BACKPLANE_PIN 4
/*********************************************************************************************/
@ -54,6 +58,7 @@ void ILI9341_2_InitDriver()
Settings.display_model = XDSP_13;
}
if (XDSP_13 == Settings.display_model) {
if (Settings.display_width != ILI9341_2_TFTWIDTH) {
@ -70,13 +75,17 @@ void ILI9341_2_InitDriver()
fg_color = ILI9341_2_WHITE;
bg_color = ILI9341_2_BLACK;
#ifdef USE_M5STACK_CORE2
ili9341_2 = new ILI9341_2(5, -2, 15, -2);
#else
// init renderer, may use hardware spi, however we use SSPI defintion because SD card uses SPI definition (2 spi busses)
if (PinUsed(GPIO_SSPI_CS) && PinUsed(GPIO_OLED_RESET) && PinUsed(GPIO_BACKLIGHT) && PinUsed(GPIO_SSPI_MOSI) && PinUsed(GPIO_SSPI_MISO) && PinUsed(GPIO_SSPI_SCLK) && PinUsed(GPIO_SSPI_DC)) {
ili9341_2 = new ILI9341_2(Pin(GPIO_SSPI_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_MISO), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET), Pin(GPIO_SSPI_DC), Pin(GPIO_BACKLIGHT));
} else {
return;
}
#endif
ili9341_2->init(Settings.display_width,Settings.display_height);
renderer = ili9341_2;
renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font);
@ -92,9 +101,79 @@ void ILI9341_2_InitDriver()
color_type = COLOR_COLOR;
#ifdef ESP32
#ifdef USE_FT5206
// start digitizer with fixed adress and pins for esp32
#define SDA_2 21
#define SCL_2 22
Wire1.begin(SDA_2, SCL_2, 400000);
Touch_Init(Wire1);
#endif // USE_FT5206
#endif // ESP32
}
}
void core2_disp_pwr(uint8_t on);
void core2_disp_dim(uint8_t dim);
void ili9342_bpwr(uint8_t on) {
#ifdef USE_M5STACK_CORE2
core2_disp_pwr(on);
#endif
}
void ili9342_dimm(uint8_t dim) {
#ifdef USE_M5STACK_CORE2
core2_disp_dim(dim);
#endif
}
#ifdef ESP32
#ifdef USE_FT5206
#ifdef USE_TOUCH_BUTTONS
void ili9342_RotConvert(int16_t *x, int16_t *y) {
int16_t temp;
if (renderer) {
uint8_t rot=renderer->getRotation();
switch (rot) {
case 0:
break;
case 1:
temp=*y;
*y=renderer->height()-*x;
*x=temp;
break;
case 2:
*x=renderer->width()-*x;
*y=renderer->height()-*y;
break;
case 3:
temp=*y;
*y=*x;
*x=renderer->width()-temp;
break;
}
}
}
// check digitizer hit
void ili9342_CheckTouch() {
ili9342_ctouch_counter++;
if (2 == ili9342_ctouch_counter) {
// every 100 ms should be enough
ili9342_ctouch_counter = 0;
Touch_Check(ili9342_RotConvert);
}
}
#endif // USE_TOUCH_BUTTONS
#endif // USE_FT5206
#endif // ESP32
/*********************************************************************************************/
/*********************************************************************************************\
* Interface
@ -111,6 +190,15 @@ bool Xdsp13(uint8_t function)
case FUNC_DISPLAY_MODEL:
result = true;
break;
#ifdef USE_FT5206
#ifdef USE_TOUCH_BUTTONS
case FUNC_DISPLAY_EVERY_50_MSECOND:
if (FT5206_found) {
ili9342_CheckTouch();
}
break;
#endif // USE_TOUCH_BUTTONS
#endif // USE_FT5206
}
}
return result;

View File

@ -47,7 +47,11 @@ void (* const Ws2812Command[])(void) PROGMEM = {
#include <NeoPixelBus.h>
#if (USE_WS2812_CTYPE == NEO_GRB)
#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
typedef P9813BgrFeature selectedNeoFeatureType;
#undef USE_WS2812_DMA
#undef USE_WS2812_INVERTED
#elif (USE_WS2812_CTYPE == NEO_GRB)
typedef NeoGrbFeature selectedNeoFeatureType;
#elif (USE_WS2812_CTYPE == NEO_BRG)
typedef NeoBrgFeature selectedNeoFeatureType;
@ -105,7 +109,9 @@ void (* const Ws2812Command[])(void) PROGMEM = {
#else // No USE_WS2812_INVERTED
#if (USE_WS2812_HARDWARE == NEO_HW_WS2812X)
#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
typedef P9813Method selectedNeoSpeedType;
#elif (USE_WS2812_HARDWARE == NEO_HW_WS2812X)
typedef NeoEsp8266BitBangWs2812xMethod selectedNeoSpeedType;
#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812)
typedef NeoEsp8266BitBangSk6812Method selectedNeoSpeedType;
@ -472,10 +478,14 @@ void Ws2812ShowScheme(void)
void Ws2812ModuleSelected(void)
{
#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
if (PinUsed(GPIO_P9813_CLK) && PinUsed(GPIO_P9813_DAT)) { // RGB led
strip = new NeoPixelBus<selectedNeoFeatureType, selectedNeoSpeedType>(WS2812_MAX_LEDS, Pin(GPIO_P9813_CLK), Pin(GPIO_P9813_DAT));
#else
if (PinUsed(GPIO_WS2812)) { // RGB led
// For DMA, the Pin is ignored as it uses GPIO3 due to DMA hardware use.
strip = new NeoPixelBus<selectedNeoFeatureType, selectedNeoSpeedType>(WS2812_MAX_LEDS, Pin(GPIO_WS2812));
#endif // NEO_HW_P9813
strip->Begin();
Ws2812Clear();

View File

@ -24,8 +24,13 @@
*
* Action LSC SmartLed (GreenRedBlue)
* {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18}
* {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,4064,0,4032,0,0,0],"FLAG":0,"BASE":18}
* Polux E14 (BlueGreenRed) - Notice GPIO00 = 9 (Switch1)
* {"NAME":"Polux RGBCW E14","GPIO":[9,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18}
* Polux E14 (BlueGreenRed)
* {"NAME":"Polux RGBCW E14","GPIO":[0,0,0,0,0,0,0,0,4065,0,4032,0,0,0],"FLAG":0,"BASE":18}
* LE LampUX 907001-US
* {"NAME":"LE LampUX 907001-US","GPIO":[0,0,0,0,0,0,0,0,4066,0,4032,0,0,0],"FLAG":0,"BASE":18}
\*********************************************************************************************/
#define XLGT_04 4
@ -53,14 +58,12 @@
#define SM2135_55MA 0x09
#define SM2135_60MA 0x0A
enum Sm2135Color { SM2135_WCGRB, SM2135_WCBGR };
// RGB current CW current
const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_15MA; // See https://github.com/arendst/Tasmota/issues/6495#issuecomment-549121683
enum Sm2135Color { SM2135_WCGRB, SM2135_WCBGR, SM2135_WCGRBHI, SM2135_WCBGRHI };
struct SM2135 {
uint8_t clk = 0;
uint8_t data = 0;
uint8_t current;
uint8_t model = SM2135_WCGRB;
} Sm2135;
@ -135,50 +138,69 @@ bool Sm2135SetChannels(void) {
uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
uint8_t data[6];
Sm2135Start(SM2135_ADDR_MC);
Sm2135Write(SM2135_CURRENT);
uint32_t light_type = 3; // RGB and CW
if (Sm2135.model < 2) {
if ((0 == cur_col[0]) && (0 == cur_col[1]) && (0 == cur_col[2])) {
light_type = 1; // CW only
} else {
light_type = 2; // RGB only
}
}
if (light_type &2) { // Set RGB
Sm2135Start(SM2135_ADDR_MC);
Sm2135Write(Sm2135.current);
Sm2135Write(SM2135_RGB);
if (Sm2135.model &1) { // SM2135_WCBGR
Sm2135Write(cur_col[2]); // Blue
Sm2135Write(cur_col[1]); // Green
Sm2135Write(cur_col[0]); // Red
} else { // SM2135_WCGRB
Sm2135Write(cur_col[1]); // Green
Sm2135Write(cur_col[0]); // Red
Sm2135Write(cur_col[2]); // Blue
}
Sm2135Stop();
}
if (light_type &1) { // Set CW
Sm2135Start(SM2135_ADDR_MC);
Sm2135Write(Sm2135.current);
Sm2135Write(SM2135_CW);
Sm2135Stop();
delay(1);
Sm2135Start(SM2135_ADDR_C);
Sm2135Write(cur_col[4]); // Warm
Sm2135Write(cur_col[3]); // Cold
} else {
Sm2135Write(SM2135_RGB);
if (SM2135_WCBGR == Sm2135.model) {
Sm2135Write(cur_col[2]); // Blue
Sm2135Write(cur_col[1]); // Green
Sm2135Write(cur_col[0]); // Red
} else {
Sm2135Write(cur_col[1]); // Green
Sm2135Write(cur_col[0]); // Red
Sm2135Write(cur_col[2]); // Blue
}
}
Sm2135Stop();
}
return true;
}
void Sm2135ModuleSelected(void)
{
if (PinUsed(GPIO_SM2135_CLK) && PinUsed(GPIO_SM2135_DAT)) {
if (PinUsed(GPIO_SM2135_CLK) && PinUsed(GPIO_SM2135_DAT, GPIO_ANY)) {
Sm2135.clk = Pin(GPIO_SM2135_CLK);
Sm2135.data = Pin(GPIO_SM2135_DAT);
Sm2135.data = Pin(GPIO_SM2135_DAT, GPIO_ANY);
Sm2135.model = SM2135_WCGRB;
Sm2135.model = GetPin(Sm2135.data) - AGPIO(GPIO_SM2135_DAT); // 0 .. 3
if (PinUsed(GPIO_SWT1)) {
Sm2135.model = SM2135_WCBGR;
pinMode(Pin(GPIO_SWT1), INPUT); // Discard GPIO_SWT functionality
SetPin(Pin(GPIO_SWT1), AGPIO(GPIO_NONE));
}
// RGB current CW current
Sm2135.current = (SM2135_20MA << 4) | SM2135_15MA; // See https://github.com/arendst/Tasmota/issues/6495#issuecomment-549121683
if (Sm2135.model > SM2135_WCBGR) {
Sm2135.current = (SM2135_20MA << 4) | SM2135_30MA;
}
Sm2135Init();
TasmotaGlobal.light_type = LT_RGBWC;
TasmotaGlobal.light_driver = XLGT_04;
AddLog_P(LOG_LEVEL_DEBUG, PSTR("DBG: SM2135 (%s) Found"), (SM2135_WCBGR == Sm2135.model) ? PSTR("BGR") : PSTR("GRB"));
AddLog_P(LOG_LEVEL_DEBUG, PSTR("LGT: SM2135 (%s-%s current) Found"),
(SM2135_WCBGR == (Sm2135.model &1)) ? PSTR("BGR") : PSTR("GRB"), (Sm2135.model > SM2135_WCBGR) ? PSTR("High") : PSTR("Low"));
}
}

View File

@ -27,12 +27,15 @@
#ifdef ESP8266
#define ANALOG_RESOLUTION 10 // 12 = 4095, 11 = 2047, 10 = 1023
#define ANALOG_RANGE 1023 // 4095 = 12, 2047 = 11, 1023 = 10
#define ANALOG_PERCENT 10 // backward compatible div10 range
#endif // ESP8266
#ifdef ESP32
#undef ANALOG_RESOLUTION
#define ANALOG_RESOLUTION 12 // 12 = 4095, 11 = 2047, 10 = 1023
#undef ANALOG_RANGE
#define ANALOG_RANGE 4095 // 4095 = 12, 2047 = 11, 1023 = 10
#undef ANALOG_PERCENT
#define ANALOG_PERCENT ((ANALOG_RANGE + 50) / 100) // approximation to 1% ADC range
#endif // ESP32
#define TO_CELSIUS(x) ((x) - 273.15)
@ -259,9 +262,9 @@ void AdcEvery250ms(void) {
#endif
if (ADC_INPUT == Adc[idx].type) {
uint16_t new_value = AdcRead(Adc[idx].pin, 5);
if ((new_value < Adc[idx].last_value -10) || (new_value > Adc[idx].last_value +10)) {
if ((new_value < Adc[idx].last_value -ANALOG_PERCENT) || (new_value > Adc[idx].last_value +ANALOG_PERCENT)) {
Adc[idx].last_value = new_value;
uint16_t value = Adc[idx].last_value / 10;
uint16_t value = Adc[idx].last_value / ANALOG_PERCENT;
Response_P(PSTR("{\"ANALOG\":{\"A%ddiv10\":%d}}"), idx + offset, (value > 99) ? 100 : value);
XdrvRulesProcess();
}

View File

@ -38,7 +38,9 @@
#define W1_WRITE_SCRATCHPAD 0x4E
#define W1_READ_SCRATCHPAD 0xBE
#ifndef DS18X20_MAX_SENSORS // DS18X20_MAX_SENSORS fallback to 8 if not defined in user_config_override.h
#define DS18X20_MAX_SENSORS 8
#endif
const char kDs18x20Types[] PROGMEM = "DS18x20|DS18S20|DS1822|DS18B20|MAX31850";

View File

@ -52,7 +52,7 @@ bool DhtWaitState(uint32_t sensor, uint32_t level)
unsigned long timeout = micros() + 100;
while (digitalRead(Dht[sensor].pin) != level) {
if (TimeReachedUsec(timeout)) {
PrepLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " %s " D_PULSE),
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " %s " D_PULSE),
(level) ? D_START_SIGNAL_HIGH : D_START_SIGNAL_LOW);
return false;
}

View File

@ -69,7 +69,8 @@ const char HTTP_MGC_3130_SNS[] PROGMEM =
"{s}" "%s" "{m}%s{e}"
"{s}" "HwRev" "{m}%u.%u{e}"
"{s}" "loaderVer" "{m}%u.%u{e}"
"{s}" "platVer" "{m}%u{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
"{s}" "platVer" "{m}%u{e}"
"{s}" "NoisePower" "{m}%s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
@ -152,17 +153,18 @@ union MGC3130_Union{
float SDData[4]; // signal deviation
} out;
struct {
uint8_t header[3];
uint8_t header[4];
// payload
uint8_t valid;
uint8_t valid; // 0xAA is valid
uint8_t hwRev[2];
uint8_t parameterStartAddr;
uint8_t loaderVersion[2];
uint8_t loaderPlatform;
uint8_t fwStartAddr;
uint8_t fwStartAddr; // should be 0x20
char fwVersion[120];
} fw;
struct{
uint8_t header[4];
uint8_t id;
uint8_t size;
uint16_t error;
@ -180,7 +182,7 @@ int16_t MGC3130_rotValue, MGC3130_lastSentRotValue = 0;
uint16_t MGC3130_lastSentX, MGC3130_lastSentY, MGC3130_lastSentZ = 0;
uint8_t hwRev[2], loaderVersion[2], loaderPlatform = 0;
char MGC3130_firmwareInfo[20];
float MGC3130_noisePower = -1;
uint8_t MGC3130_touchTimeout = 0;
uint16_t MGC3130_touchCounter = 1; // measure how long you touch the surface in loop cycles
@ -194,6 +196,7 @@ uint8_t MGC3130_mode = 1; // 1-gesture; 2-airwheel; 3-position
uint8_t MGC3130autoCal[] = {0x10, 0x00, 0x00, 0xA2, 0x80, 0x00 , 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t MGC3130disableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
uint8_t MGC3130enableAirwheel[] = {0x10, 0x00, 0x00, 0xA2, 0x90, 0x00 , 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
uint8_t MGC3130enableAll[] = {0x10, 0x00, 0x00, 0xA2, 0xA0, 0x00 , 0x00, 0x00, 0x3f, 0x18, 0x00, 0x00, 0x3f, 0x18, 0x00, 0x00};
void MGC3130_handleSensorData(){
if ( MGC_data.out.outputConfigMask.touchInfo && MGC3130_touchTimeout == 0){
@ -220,6 +223,9 @@ void MGC3130_handleSensorData(){
MqttPublishSensor();
}
}
if(MGC_data.out.systemInfo.noisePowerValid){
MGC3130_noisePower = MGC_data.out.noisePower;
}
}
void MGC3130_sendMessage(uint8_t data[], uint8_t length){
@ -394,7 +400,7 @@ void MGC3130_handleAirWheel(){
}
void MGC3130_handleSystemStatus(){
//Serial.println("Got System status");
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MGC3130: system_status: response to ID:%02x, error code: %04x"),MGC_data.status.id, MGC_data.status.error);
}
bool MGC3130_receiveMessage(){
@ -407,16 +413,15 @@ bool MGC3130_receiveMessage(){
MGC3130_handleSystemStatus();
break;
case MGC3130_FW_VERSION:
hwRev[0] = MGC_data.fw.hwRev[1];
hwRev[1] = MGC_data.fw.hwRev[0];
loaderVersion[0] = MGC_data.fw.loaderVersion[0];
loaderVersion[1] = MGC_data.fw.loaderVersion[1];
hwRev[1] = MGC_data.fw.hwRev[1];
hwRev[0] = MGC_data.fw.hwRev[0];
loaderVersion[1] = MGC_data.fw.loaderVersion[0];
loaderVersion[0] = MGC_data.fw.loaderVersion[1];
loaderPlatform = MGC_data.fw.loaderPlatform;
snprintf_P(MGC3130_firmwareInfo, sizeof(MGC3130_firmwareInfo), PSTR("FW: %s"), MGC_data.fw.fwVersion);
MGC3130_firmwareInfo[20] = '\0';
// Serial.print(MGC3130_firmwareInfo);
AddLog_P(LOG_LEVEL_INFO,PSTR("MGC3130: GestIC:%s"),MGC_data.fw.fwVersion);
break;
}
MGC_data.out.id = 0;
return true;
}
return false;
@ -424,11 +429,12 @@ bool MGC3130_receiveMessage(){
bool MGC3130_readData()
{
static uint8_t _lastCounter = 0;
bool success = false;
if (!digitalRead(MGC3130_xfer)){
pinMode(MGC3130_xfer, OUTPUT);
digitalWrite(MGC3130_xfer, LOW);
Wire.requestFrom(MGC3130_I2C_ADDR, (uint16_t)32); // request usual data output
Wire.requestFrom(MGC3130_I2C_ADDR, (uint16_t)132); // request maximal data output
MGC_data.buffer[0] = 4; // read at least header, but update after first read anyway
unsigned char i = 0;
@ -438,6 +444,14 @@ bool MGC3130_readData()
}
digitalWrite(MGC3130_xfer, HIGH);
pinMode(MGC3130_xfer, INPUT);
uint8_t _mismatch = MGC_data.out.counter - _lastCounter;
if(_mismatch != 1){
if(i>4 && MGC_data.out.id != MGC3130_FW_VERSION){
AddLog_P(LOG_LEVEL_DEBUG,PSTR("MGC3130: missed a packet, mismatch: %u"), _mismatch - 1);
AddLogBuffer(LOG_LEVEL_DEBUG,MGC_data.buffer,i);
}
}
_lastCounter = MGC_data.out.counter;
success = true;
}
return success;
@ -537,7 +551,9 @@ void MGC3130_show(bool json)
}
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_MGC_3130_SNS, MGC3130stype, status_chr, hwRev[0], hwRev[1], loaderVersion[0], loaderVersion[1], loaderPlatform );
char _noise[FLOATSZ];
dtostrfd(MGC3130_noisePower, 2, _noise);
WSContentSend_PD(HTTP_MGC_3130_SNS, MGC3130stype, status_chr, hwRev[0], hwRev[1], loaderVersion[0], loaderVersion[1], loaderPlatform, _noise);
#endif // USE_WEBSERVER
}
}
@ -552,6 +568,7 @@ void MGC3130_show(bool json)
* Sensor36 | 1 | Gesture Mode
* Sensor36 | 2 | Airwheel Mode
* Sensor36 | 3 | Position Mode with x,y,z - z must be higher than half of the max. sensing height
* Sensor36 | 4 | Enable all data for debugging (noise level in web GUI)
\*********************************************************************************************/
bool MGC3130CommandSensor()
@ -574,7 +591,11 @@ bool MGC3130CommandSensor()
MGC3130_mode = 3;
MGC3130_sendMessage(MGC3130disableAirwheel,16);
break;
case 4: // enable all readings for noise level for web GUI
MGC3130_sendMessage(MGC3130enableAll,16);
break;
}
Response_P(PSTR("{\"MGC3130\":{\"mode\":%d}}"), MGC3130_mode);
return serviced;
}

View File

@ -24,6 +24,61 @@
#define XSNS_75 75
const char *UnitfromType(const char *type) // find unit for measurment type
{
if (strcmp(type, "time") == 0)
{
return "_seconds";
}
if (strcmp(type, "temperature") == 0 || strcmp(type, "dewpoint") == 0)
{
return "_celsius";
}
if (strcmp(type, "pressure") == 0)
{
return "_hpa";
}
if (strcmp(type, "voltage") == 0)
{
return "_volts";
}
if (strcmp(type, "current") == 0)
{
return "_amperes";
}
if (strcmp(type, "mass") == 0)
{
return "_grams";
}
if (strcmp(type, "carbondioxide") == 0)
{
return "_ppm";
}
if (strcmp(type, "humidity") == 0)
{
return "_percentage";
}
return "";
}
const char *FormatMetricName(const char *metric) // cleanup spaces and uppercases for Prmetheus metrics conventions
{
char *formated = (char *)malloc(strlen(metric)+1);
uint32_t cnt = 0;
for (cnt; cnt < strlen(metric)+1; cnt++)
{
if (metric[cnt] == ' ')
{
formated[cnt] = '_';
}
else
{
formated[cnt] = tolower(metric[cnt]);
}
}
return formated;
}
void HandleMetrics(void)
{
if (!HttpCheckPriviledgedAccess()) { return; }
@ -75,19 +130,68 @@ void HandleMetrics(void)
WSContentSend_P(PSTR("# TYPE energy_power_kilowatts_total counter\nenergy_power_kilowatts_total %s\n"), parameter);
#endif
/*
// Alternative method using the complete sensor JSON data
// For prometheus it may need to be decoded to # TYPE messages
for (uint32_t device = 0; device < TasmotaGlobal.devices_present; device++) {
power_t mask = 1 << device;
WSContentSend_P(PSTR("# TYPE relay%d_state gauge\nrelay%d_state %d\n"), device+1, device+1, (TasmotaGlobal.power & mask));
}
ResponseClear();
MqttShowSensor();
char json[strlen(TasmotaGlobal.mqtt_data) +1];
MqttShowSensor(); //Pull sensor data
char json[strlen(TasmotaGlobal.mqtt_data)+1];
snprintf_P(json, sizeof(json), TasmotaGlobal.mqtt_data);
// Do your Prometheus specific processing here.
// Look at function DisplayAnalyzeJson() in file xdrv_13_display.ino as an example how to decode the JSON message
WSContentSend_P(json);
*/
String jsonStr = json;
JsonParser parser((char *)jsonStr.c_str());
JsonParserObject root = parser.getRootObject();
if (root)
{ // did JSON parsing went ok?
for (auto key1 : root)
{
JsonParserToken value1 = key1.getValue();
if (value1.isObject())
{
JsonParserObject Object2 = value1.getObject();
for (auto key2 : Object2)
{
JsonParserToken value2 = key2.getValue();
if (value2.isObject())
{
JsonParserObject Object3 = value2.getObject();
for (auto key3 : Object3)
{
const char *value = key3.getValue().getStr(nullptr);
if (value != nullptr && isdigit(value[0]))
{
const char *sensor = FormatMetricName(key2.getStr()); //cleanup sensor name
const char *type = FormatMetricName(key3.getStr()); //cleanup sensor type
const char *unit = UnitfromType(type); //grab base unit corresponding to type
WSContentSend_P(PSTR("# TYPE tasmota_sensors_%s%s gauge\ntasmota_sensors_%s%s{sensor=\"%s\"} %s\n"), type, unit, type, unit, sensor, value); //build metric as "# TYPE tasmota_sensors_%type%_%unit% gauge\ntasmotasensors_%type%_%unit%{sensor=%sensor%"} %value%""
}
}
}
else
{
const char *value = value2.getStr(nullptr);
if (value != nullptr && isdigit(value[0]))
{
const char *sensor = FormatMetricName(key1.getStr());
const char *type = FormatMetricName(key2.getStr());
const char *unit = UnitfromType(type);
WSContentSend_P(PSTR("# TYPE tasmota_sensors_%s%s gauge\ntasmota_sensors_%s%s{sensor=\"%s\"} %s\n"), type, unit, type, unit, sensor, value);
}
}
}
}
else
{
const char *value = value1.getStr(nullptr);
if (value != nullptr && isdigit(value[0] && strcmp(key1.getStr(), "Time") != 0)) //remove false 'time' metric
{
const char *sensor = FormatMetricName(key1.getStr());
WSContentSend_P(PSTR("# TYPE tasmota_sensors_%s gauge\ntasmota_sensors{sensor=\"%s\"} %s\n"), sensor, sensor, value);
}
}
}
}
WSContentEnd();
}