Merge branch 'development' into pre-release-11.0

This commit is contained in:
Theo Arends 2022-02-12 14:50:30 +01:00
commit c22d936f8c
37 changed files with 2016 additions and 4300 deletions

View File

@ -33,7 +33,6 @@ jobs:
- tasmota32
- tasmota32-webcam
- tasmota32-bluetooth
- tasmota32-core2
- tasmota32-display
- tasmota32-ir
- tasmota32-lvgl

File diff suppressed because it is too large Load Diff

View File

@ -1,614 +0,0 @@
#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

@ -1,106 +0,0 @@
#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

@ -1,353 +0,0 @@
#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

@ -1,76 +0,0 @@
#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

@ -1,8 +0,0 @@
{
"name": "M5 Stack Core2 library",
"keywords": "esp32, sensor, mqtt, m2m, iot",
"description": "M5 Stack Core2 library",
"version": "1.0",
"frameworks": "arduino",
"platforms": "espressif32"
}

View File

@ -1,9 +0,0 @@
name=M5 Stack Core2 library
version=1.0
author=Gerhard Mutz
maintainer=Gerhard Mutz
sentence=Allows Tasmota to use Core2
paragraph=Allows Tasmota to Core2 for esp32
category=ESP32
url=
architectures=esp32

View File

@ -12,6 +12,7 @@ extern const bcstring be_const_str_AudioOutputI2S;
extern const bcstring be_const_str_Auto_X2Dconfiguration;
extern const bcstring be_const_str_BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20;
extern const bcstring be_const_str_BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s;
extern const bcstring be_const_str_BRY_X3A_X20argument_X20must_X20be_X20a_X20function;
extern const bcstring be_const_str_BRY_X3A_X20could_X20not_X20save_X20compiled_X20file_X20_X25s_X20_X28_X25s_X29;
extern const bcstring be_const_str_BRY_X3A_X20failed_X20to_X20load_X20_persist_X2Ejson;
extern const bcstring be_const_str_BRY_X3A_X20method_X20not_X20allowed_X2C_X20use_X20a_X20closure_X20like_X20_X27_X2F_X20args_X20_X2D_X3E_X20obj_X2Efunc_X28args_X29_X27;
@ -123,6 +124,7 @@ extern const bcstring be_const_str__X26lt_X3BNone_X26gt_X3B;
extern const bcstring be_const_str__X28_X29;
extern const bcstring be_const_str__X2B;
extern const bcstring be_const_str__X2C;
extern const bcstring be_const_str__X2C_X22AXP192_X22_X3A_X7B_X22VBusVoltage_X22_X3A_X25_X2E3f_X2C_X22VBusCurrent_X22_X3A_X25_X2E1f_X2C_X22BattVoltage_X22_X3A_X25_X2E3f_X2C_X22BattCurrent_X22_X3A_X25_X2E1f_X2C_X22Temperature_X22_X3A_X25_X2E1f_X7D;
extern const bcstring be_const_str__X2D_X2D_X3A_X2D_X2D;
extern const bcstring be_const_str__X2E;
extern const bcstring be_const_str__X2E_X2E;
@ -745,6 +747,7 @@ extern const bcstring be_const_str_tomap;
extern const bcstring be_const_str_top;
extern const bcstring be_const_str_toptr;
extern const bcstring be_const_str_tostring;
extern const bcstring be_const_str_touch_update;
extern const bcstring be_const_str_toupper;
extern const bcstring be_const_str_tr;
extern const bcstring be_const_str_traceback;

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,14 @@
#include "be_constobj.h"
static be_define_const_map_slots(m_libdisplay_map) {
{ be_const_key(touch_update, -1), be_const_ctype_func(be_ntv_display_touch_update) },
{ be_const_key(dimmer, -1), be_const_func(be_ntv_display_dimmer) },
{ be_const_key(start, 0), be_const_func(be_ntv_display_start) },
{ be_const_key(start, -1), be_const_func(be_ntv_display_start) },
};
static be_define_const_map(
m_libdisplay_map,
2
3
);
static be_define_const_module(

View File

@ -6,16 +6,20 @@
* Initialize Universal Display driver
*******************************************************************/
#include "be_constobj.h"
#include "be_mapping.h"
#ifdef USE_DISPLAY
extern int be_ntv_display_start(bvm *vm);
extern int be_ntv_display_dimmer(bvm *vm);
extern void be_ntv_display_touch_update(int32_t touches, int32_t raw_x, int32_t raw_y, int32_t gesture);
BE_FUNC_CTYPE_DECLARE(be_ntv_display_touch_update, "", "iiii[ii]")
/* @const_object_info_begin
module display (scope: global) {
start, func(be_ntv_display_start)
dimmer, func(be_ntv_display_dimmer)
touch_update, ctype_func(be_ntv_display_touch_update)
}
@const_object_info_end */
#include "be_fixed_display.h"

View File

@ -8,7 +8,7 @@
********************************************************************/
be_local_closure(AXP192_json_append, /* name */
be_nested_proto(
2, /* nstack */
11, /* nstack */
1, /* argc */
2, /* varg */
0, /* has upvals */
@ -16,17 +16,44 @@ be_local_closure(AXP192_json_append, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 1]) { /* constants */
( &(const bvalue[10]) { /* constants */
/* K0 */ be_nested_str(wire),
/* K1 */ be_nested_str(string),
/* K2 */ be_nested_str(format),
/* K3 */ be_nested_str(_X2C_X22AXP192_X22_X3A_X7B_X22VBusVoltage_X22_X3A_X25_X2E3f_X2C_X22VBusCurrent_X22_X3A_X25_X2E1f_X2C_X22BattVoltage_X22_X3A_X25_X2E3f_X2C_X22BattCurrent_X22_X3A_X25_X2E1f_X2C_X22Temperature_X22_X3A_X25_X2E1f_X7D),
/* K4 */ be_nested_str(get_vbus_voltage),
/* K5 */ be_nested_str(get_bat_voltage),
/* K6 */ be_nested_str(get_bat_current),
/* K7 */ be_nested_str(get_temp),
/* K8 */ be_nested_str(tasmota),
/* K9 */ be_nested_str(response_append),
}),
&be_const_str_json_append,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
( &(const binstruction[23]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x74060001, // 0001 JMPT R1 #0004
0x4C040000, // 0002 LDNIL R1
0x80040200, // 0003 RET 1 R1
0x80000000, // 0004 RET 0
0xA4060200, // 0004 IMPORT R1 K1
0x8C080302, // 0005 GETMET R2 R1 K2
0x58100003, // 0006 LDCONST R4 K3
0x8C140104, // 0007 GETMET R5 R0 K4
0x7C140200, // 0008 CALL R5 1
0x8C180104, // 0009 GETMET R6 R0 K4
0x7C180200, // 000A CALL R6 1
0x8C1C0105, // 000B GETMET R7 R0 K5
0x7C1C0200, // 000C CALL R7 1
0x8C200106, // 000D GETMET R8 R0 K6
0x7C200200, // 000E CALL R8 1
0x8C240107, // 000F GETMET R9 R0 K7
0x7C240200, // 0010 CALL R9 1
0x7C080E00, // 0011 CALL R2 7
0xB80E1000, // 0012 GETNGBL R3 K8
0x8C0C0709, // 0013 GETMET R3 R3 K9
0x5C140400, // 0014 MOVE R5 R2
0x7C0C0400, // 0015 CALL R3 2
0x80000000, // 0016 RET 0
})
)
);

View File

@ -2103,24 +2103,32 @@ be_local_closure(Tasmota_check_not_method, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 4]) { /* constants */
( &(const bvalue[ 6]) { /* constants */
/* K0 */ be_nested_str(introspect),
/* K1 */ be_nested_str(ismethod),
/* K1 */ be_nested_str(function),
/* K2 */ be_nested_str(type_error),
/* K3 */ be_nested_str(BRY_X3A_X20method_X20not_X20allowed_X2C_X20use_X20a_X20closure_X20like_X20_X27_X2F_X20args_X20_X2D_X3E_X20obj_X2Efunc_X28args_X29_X27),
/* K3 */ be_nested_str(BRY_X3A_X20argument_X20must_X20be_X20a_X20function),
/* K4 */ be_nested_str(ismethod),
/* K5 */ be_nested_str(BRY_X3A_X20method_X20not_X20allowed_X2C_X20use_X20a_X20closure_X20like_X20_X27_X2F_X20args_X20_X2D_X3E_X20obj_X2Efunc_X28args_X29_X27),
}),
&be_const_str_check_not_method,
&be_const_str_solidified,
( &(const binstruction[ 9]) { /* code */
( &(const binstruction[15]) { /* code */
0xA40A0000, // 0000 IMPORT R2 K0
0x8C0C0501, // 0001 GETMET R3 R2 K1
0x5C140200, // 0002 MOVE R5 R1
0x7C0C0400, // 0003 CALL R3 2
0x50100200, // 0004 LDBOOL R4 1 0
0x1C0C0604, // 0005 EQ R3 R3 R4
0x780E0000, // 0006 JMPF R3 #0008
0xB0060503, // 0007 RAISE 1 K2 K3
0x80000000, // 0008 RET 0
0x600C0004, // 0001 GETGBL R3 G4
0x5C100200, // 0002 MOVE R4 R1
0x7C0C0200, // 0003 CALL R3 1
0x200C0701, // 0004 NE R3 R3 K1
0x780E0000, // 0005 JMPF R3 #0007
0xB0060503, // 0006 RAISE 1 K2 K3
0x8C0C0504, // 0007 GETMET R3 R2 K4
0x5C140200, // 0008 MOVE R5 R1
0x7C0C0400, // 0009 CALL R3 2
0x50100200, // 000A LDBOOL R4 1 0
0x1C0C0604, // 000B EQ R3 R3 R4
0x780E0000, // 000C JMPF R3 #000E
0xB0060505, // 000D RAISE 1 K2 K5
0x80000000, // 000E RET 0
})
)
);

View File

@ -50,6 +50,9 @@ class Tasmota
# check that the parameter is not a method, it would require a closure instead
def check_not_method(f)
import introspect
if type(f) != 'function'
raise "type_error", "BRY: argument must be a function"
end
if introspect.ismethod(f) == true
raise "type_error", "BRY: method not allowed, use a closure like '/ args -> obj.func(args)'"
end

View File

@ -170,12 +170,14 @@ class AXP192 : I2C_Driver
#- add sensor value to teleperiod -#
def json_append()
if !self.wire return nil end #- exit if not initialized -#
# import string
# var ax = int(self.accel[0] * 1000)
# var ay = int(self.accel[1] * 1000)
# var az = int(self.accel[2] * 1000)
# var msg = string.format(",\"MPU6886\":{\"AX\":%i,\"AY\":%i,\"AZ\":%i,\"GX\":%i,\"GY\":%i,\"GZ\":%i}",
# ax, ay, az, self.gyro[0], self.gyro[1], self.gyro[2])
# tasmota.response_append(msg)
import string
var msg = string.format(",\"AXP192\":{\"VBusVoltage\":%.3f,\"VBusCurrent\":%.1f,\"BattVoltage\":%.3f,\"BattCurrent\":%.1f,\"Temperature\":%.1f}",
self.get_vbus_voltage(), self.get_vbus_voltage(),
self.get_bat_voltage(), self.get_bat_current(),
#self.get_bat_power(),
self.get_temp()
)
tasmota.response_append(msg)
end
end

View File

@ -0,0 +1,190 @@
#-------------------------------------------------------------
- Generic driver for AXP202 - solidified
-------------------------------------------------------------#
class AXP202 : I2C_Driver
def init()
super(self, I2C_Driver).init("AXP202", 0x35)
end
# Return True = Battery Exist
def battery_present()
if self.wire.read(self.addr, 0x01, 1) & 0x20 return true
else return false
end
end
# Input Power Status ???
def get_input_power_status()
return self.wire.read(self.addr, 0x00, 1)
end
# Battery Charging Status
def get_battery_chargin_status()
return self.wire.read(self.addr, 0x01, 1)
end
# AXP chip temperature in °C
def get_temp()
return self.read12(0x5E) * 0.1 - 144.7
end
def get_bat_power()
return self.read24(0x70) * 0.00055
end
def get_bat_voltage()
return self.read12(0x78) * 0.0011
end
def get_bat_current()
return (self.read13(0x7A) - self.read13(0x7C)) * 0.5
end
def get_bat_charge_current()
return self.read13(0x7A) * 0.5
end
def get_aps_voltage()
return self.read12(0x7E) * 0.0014
end
def get_vbus_voltage()
return self.read12(0x5A) * 0.0017
end
def get_vbus_current()
return self.read12(0x5C) * 0.375
end
# set LDO voltage
# ldo: 2/3/4
# voltage: (mV) 1800mV - 3300mV in 100mV steps
def set_ldo_voltage(ldo, voltage)
if voltage > 3300 voltage = 15 end
if ldo == 2 || ldo == 4
voltage = (voltage / 100) - 18
if ldo == 2
self.write8(0x28, self.read8(0x28) & 0x0F | ((voltage & 0x0F) << 4))
else
self.write8(0x28, self.read8(0x28) & 0xF0 | (voltage & 0x0F))
end
else
# ldo 3, range is 0v7~3v3
voltage = (voltage / 25) - 28
self.write8(0x28, self.read8(0x29) & 0x80 | (voltage & 0x7F))
end
end
# set EXTEN which enables external power on M5Stack, powering Hat with 5V
def set_exten(state)
self.write_bit(0x12, 0, state)
end
# VBUS current-limit selection set to not limit
def set_limiting_off()
self.write8(0x30, self.read8(0x30) | 0x03)
end
# set DCDC enable, 2/3
def set_dcdc_enable(dcdc, state)
# if dcdc == 1 self.write_bit(0x12, 0, state) end # no dcdc1 on AXP202
if dcdc == 2 self.write_bit(0x12, 4, state) end
if dcdc == 3 self.write_bit(0x12, 1, state) end
end
# set LDO enable, 2/3/4 (LDO 1 is always on)
def set_ldo_enable(ldo, state)
if ldo == 2 self.write_bit(0x12, 2, state) end
if ldo == 3 self.write_bit(0x12, 6, state) end
if ldo == 4 self.write_bit(0x12, 3, state) end
end
# # set GPIO output state 0/1/2 and 3/4
# def write_gpio(gpio, state)
# if gpio >= 0 && gpio <= 2
# self.write_bit(0x94, gpio, state)
# elif gpio >= 3 && gpio <= 4
# self.write_bit(0x96, gpio - 3, state)
# end
# end
# Set voltage on DC-DC 2/3
# dcdc: 2/3 (warning some C libs start at 0)
# voltage:
def set_dc_voltage(dcdc, voltage)
if dcdc < 2 || dcdc > 3 return end
var v
if voltage < 700 v = 0
elif voltage > 3500 v = 112
elif dcdc == 2 && voltage > 2275 v = 63 # dcdc2 is limited to 2.275V
else v = (voltage - 700) / 25
end
var addr = 0x23
if dcdc == 3 addr = 0x27
# elif dcdc == 2 addr = 0x23
end
self.write8(addr, self.read8(addr) & 0x80 | (v & 0x7F))
end
# Set charging current
# current = 300+(val)*100 mA, range 300-1800
def set_chg_current_ma(ma)
var current_code = (ma - 300) / 100
self.write8(0x33, self.read8(0x33) & 0xF0 | (current_code & 0x0F))
end
# set shutdown time, possible values: 4, 6, 8, 10
def set_shutdown_time(st)
var val = 0 # 4s
if st == 6 val = 1 end
if st == 8 val = 2 end
if st == 10 val = 3 end
self.write8(0x36, self.read8(0x36) & 0xFC | (val & 0x03))
end
# change charging led mode
# 0=off, 1=blink_1Hz, 2=blink_4Hz, 3=low_level
def set_chg_led_mode(mode)
var val = self.read8(0x32)
val = (val & 0xCF) | 0x08
val = val | ((mode & 0x03) << 4)
self.write8(0x32, val)
end
# # // Low Volt Level 1, when APS Volt Output < 3.4496 V
# # // Low Volt Level 2, when APS Volt Output < 3.3992 V, then this flag is SET (0x01)
# # // Flag will reset once battery volt is charged above Low Volt Level 1
# # // Note: now AXP192 have the Shutdown Voltage of 3.0V (B100) Def in REG 31H
# def get_warning_level()
# return self.read12(0x47) & 1
# end
# #- display sensor value in the web UI -#
# def web_sensor()
# if !self.wire return nil end #- exit if not initialized -#
# import string
# var msg = string.format(
# "{s}VBus Voltage{m}%.3f V{e}"..
# "{s}VBus Current{m}%.1f mA{e}"..
# "{s}Batt Voltage{m}%.3f V{e}"..
# "{s}Batt Current{m}%.1f mA{e}"..
# #"{s}Batt Power{m}%.3f{e}"..
# "{s}Temp AXP{m}%.1f &deg;C{e}",
# self.get_vbus_voltage(), self.get_vbus_voltage(),
# self.get_bat_voltage(), self.get_bat_current(),
# #self.get_bat_power(),
# self.get_temp()
# )
# tasmota.web_send_decimal(msg)
# end
# #- add sensor value to teleperiod -#
# def json_append()
# if !self.wire return nil end #- exit if not initialized -#
# # import string
# # var ax = int(self.accel[0] * 1000)
# # var ay = int(self.accel[1] * 1000)
# # var az = int(self.accel[2] * 1000)
# # var msg = string.format(",\"MPU6886\":{\"AX\":%i,\"AY\":%i,\"AZ\":%i,\"GX\":%i,\"GY\":%i,\"GZ\":%i}",
# # ax, ay, az, self.gyro[0], self.gyro[1], self.gyro[2])
# # tasmota.response_append(msg)
# end
end

View File

@ -0,0 +1,91 @@
#-------------------------------------------------------------
- Driver for FT3663 - Capacitive Touch Screen
-------------------------------------------------------------#
class FT3663 : I2C_Driver
static gest_id_codes = {
0x00: 0x00,
0x10: 0x10, # Move Up
0x14: 0x13, # Move Right
0x18: 0x11, # Move Down
0x1C: 0x12, # Move Left
0x48: 0x20, # Zoom In
0x49: 0x21, # Zoom Out
# 0x10 Move Up
# 0x14 Move Right
# 0x18 Move Down
# 0x1C Move Left
# 0x48 Zoom In
# 0x49 Zoom Out
# 0x00 No Gesture
#
# TS_Gest_None = 0,
# TS_Gest_Move_Up = 0x10,
# TS_Gest_Move_Down = 0x11,
# TS_Gest_Move_Left = 0x12,
# TS_Gest_Move_Right = 0x13,
# TS_Gest_Zoom_In = 0x20,
# TS_Gest_Zoom_Out = 0x21,
}
def init()
super(self).init("FT3663", 0x38)
# check that ID from register 0xA8 is 0x11
var vendid = self.read8(0xA8)
var chipid = self.read8(0xA3)
if vendid != 0x11 || chipid != 0x64
tasmota.log("I2C: ignoring address 0x38, not FT3663", 2)
self.wire = nil
return
end
# FT3663 is now confirmed
tasmota.log("TS : FT3663 Touch Screen detected")
self.write8(0x00, 0x00) # writeRegister8(FT6X36_REG_DEVICE_MODE, 0x00);
self.write8(0x80, 22) # writeRegister8(FT6X36_REG_THRESHHOLD, FT6X36_DEFAULT_THRESHOLD);
self.write8(0x88, 0x0E) # writeRegister8(FT6X36_REG_TOUCHRATE_ACTIVE, 0x0E);
# register ourself
tasmota.add_driver(self)
end
# read touch screen and publish result
def ts_loop()
if !self.wire return end
import display
var data = self.wire.read_bytes(self.addr, 0, 15)
# ex: data = bytes('0000018098009B0000FFFFFFFFFFFF')
var touches = data[0x02] & 0x0F # number of touches
var x1 = (data[0x03] & 0x0F) << 8 | data[0x04]
var y1 = (data[0x05] & 0x0F) << 8 | data[0x06]
var pressure1 = data[0x07]
var x2 = (data[0x03] & 0x09) << 8 | data[0x0A]
var y2 = (data[0x05] & 0x0B) << 8 | data[0x0C]
var pressure2 = data[0x0D]
var gesture = self.gest_id_codes.find(data[0x01], 0x00)
#define FT6X36_REG_DEVICE_MODE 0x00
#define FT6X36_REG_GESTURE_ID 0x01
#define FT6X36_REG_NUM_TOUCHES 0x02
#define FT6X36_REG_P1_XH 0x03
#define FT6X36_REG_P1_XL 0x04
#define FT6X36_REG_P1_YH 0x05
#define FT6X36_REG_P1_YL 0x06
#define FT6X36_REG_P1_WEIGHT 0x07
#define FT6X36_REG_P1_MISC 0x08
#define FT6X36_REG_P2_XH 0x09
#define FT6X36_REG_P2_XL 0x0A
#define FT6X36_REG_P2_YH 0x0B
#define FT6X36_REG_P2_YL 0x0C
#define FT6X36_REG_P2_WEIGHT 0x0D
#define FT6X36_REG_P2_MISC 0x0E
display.touch_update(touches, x1, y1, gesture)
end
def every_100ms()
if self.wire self.ts_loop() end
end
end
ts = FT3663()

View File

@ -57,7 +57,7 @@ monitor_filters = esp32_exception_decoder
[env:tasmota32s3]
extends = env:tasmota32_base
platform = https://github.com/Jason2866/platform-espressif32.git#IDF44/ESP32-S3
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/622/framework-arduinoespressif32-v4.4_dev-a829191c37.tar.gz
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/644/framework-arduinoespressif32-v4.4_dev-33b5ac5075.tar.gz
board = esp32s3
build_flags = ${env:tasmota32_base.build_flags} -D FIRMWARE_TASMOTA32
lib_extra_dirs =

View File

@ -62,14 +62,13 @@ build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_WEBCAM
lib_extra_dirs = lib/lib_ssl, lib/libesp32
[env:tasmota32-odroidgo]
extends = env:tasmota32_base
extends = env:tasmota32-lvgl
board = esp32-odroid
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_ODROID_GO -DUSE_UNIVERSAL_DISPLAY
[env:tasmota32-core2]
extends = env:tasmota32_base
extends = env:tasmota32-lvgl
board = esp32-m5core2
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_M5STACK_CORE2 -DUSE_UNIVERSAL_DISPLAY
build_flags = ${env:tasmota32-lvgl.build_flags} -DUSE_I2S_SAY_TIME -DUSE_I2S_WEBRADIO -DUSE_SENDMAIL -DUSE_ESP32MAIL
lib_extra_dirs = lib/libesp32, lib/libesp32_lvgl, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display, lib/lib_audio
[env:tasmota32-bluetooth]

View File

@ -0,0 +1,70 @@
#-------------------------------------------------------------
- Specialized driver for AXP202 of LilyGo TWatch 2020V3
- source is from: https://github.com/Xinyuan-LilyGO/TTGO_TWatch_Library/blob/master/src/TTGO.cpp
-------------------------------------------------------------#
class AXP202_LilyGo_TWatch_2020V3 : AXP202
def init()
super(self).init()
if self.wire
# Change the shutdown time to 4 seconds
# power->setShutdownTime(AXP_POWER_OFF_TIME_4S);
self. set_shutdown_time(4)
# Turn off the charging led
# power->setChgLEDMode(AXP20X_LED_OFF);
self.set_chg_led_mode(0)
# // Turn off external enable
# power->setPowerOutPut(AXP202_EXTEN, false);
self.set_exten(false)
# axp202 allows maximum charging current of 1800mA, minimum 300mA
# power->setChargeControlCur(300);
self.set_chg_current_ma(300)
# power->setLDO2Voltage(3300);
self.set_ldo_voltage(2, 3300)
# // New features of Twatch V3
# power->limitingOff();
self.set_limiting_off()
# //Audio power domain is AXP202 LDO4
# power->setPowerOutPut(AXP202_LDO4, false);
self.set_ldo_enable(4, false)
# power->setLDO4Voltage(AXP202_LDO4_3300MV);
self.set_ldo_voltage(4, 3300)
# power->setPowerOutPut(AXP202_LDO4, true);
self.set_ldo_enable(4, true)
# // No use
# power->setPowerOutPut(AXP202_LDO3, false);
self.set_ldo_enable(3, false)
end
end
# enable power to audio chip
def audio_enable(en)
self.set_ldo_enable(4, en)
end
# set power to backlight, dimming is controlled via PWM on GPIO15
def backlight_enable(en)
self.set_ldo_enable(2, en)
end
# Dimmer in percentage
def set_displaydimmer(x)
self.backlight_enable(x > 0)
end
# respond to display events
def display(cmd, idx, payload, raw)
if cmd == "dim" || cmd == "power"
self.set_displaydimmer(idx)
end
end
end
axp202 = AXP202_LilyGo_TWatch_2020V3()
tasmota.add_driver(axp202)

View File

@ -1028,6 +1028,7 @@
#define USE_LVGL_OPENHASP // Enable OpenHASP template compatiblity (adds LVGL template and some fonts)
#define USE_LVGL_MAX_SLEEP 10 // max sleep in ms when LVGL is enabled, more than 10ms will make display less responsive
#define USE_LVGL_PNG_DECODER // include a PNG image decoder from file system (+16KB)
//#define USE_LVGL_TOUCHSCREEN // Use virtual touch screen with Berry driver
//#define USE_LVGL_FREETYPE // Use the FreeType renderer to display fonts using native TTF files in file system (+77KB flash)
#define LV_USE_FT_CACHE_MANAGER 1 // define whether glyphs are cached by FreeType library
#define USE_LVGL_FREETYPE_MAX_FACES 64 // max number of FreeType faces in cache

View File

@ -444,11 +444,16 @@ bool SettingsConfigRestore(void) {
valid_settings = (0 == settings_buffer[0xF36]); // Settings->config_version
#endif // ESP8266
#ifdef ESP32
#ifdef CONFIG_IDF_TARGET_ESP32C3
valid_settings = (2 == settings_buffer[0xF36]); // Settings->config_version
#ifdef CONFIG_IDF_TARGET_ESP32S3
valid_settings = (2 == settings_buffer[0xF36]); // Settings->config_version ESP32S3
#elif CONFIG_IDF_TARGET_ESP32S2
valid_settings = (3 == settings_buffer[0xF36]); // Settings->config_version ESP32S2
#elif CONFIG_IDF_TARGET_ESP32C3
valid_settings = (4 == settings_buffer[0xF36]); // Settings->config_version ESP32C3
#else
valid_settings = (1 == settings_buffer[0xF36]); // Settings->config_version
#endif // CONFIG_IDF_TARGET_ESP32C3
valid_settings = (1 == settings_buffer[0xF36]); // Settings->config_version ESP32 all other
#endif // CONFIG_IDF_TARGET_ESP32S3
#endif // ESP32
}
@ -828,11 +833,15 @@ void SettingsDefaultSet2(void) {
// Settings->config_version = 0; // ESP8266 (Has been 0 for long time)
#endif // ESP8266
#ifdef ESP32
#ifdef CONFIG_IDF_TARGET_ESP32C3
Settings->config_version = 2; // ESP32C3
#ifdef CONFIG_IDF_TARGET_ESP32S3
Settings->config_version = 2; // ESP32S3
#elif CONFIG_IDF_TARGET_ESP32S2
Settings->config_version = 3; // ESP32S2
#elif CONFIG_IDF_TARGET_ESP32C3
Settings->config_version = 4; // ESP32C3
#else
Settings->config_version = 1; // ESP32
#endif // CONFIG_IDF_TARGET_ESP32C3
#endif // CONFIG_IDF_TARGET_ESP32S3
#endif // ESP32
flag.stop_flash_rotate |= APP_FLASH_CYCLE;
@ -1354,11 +1363,15 @@ void SettingsDelta(void) {
Settings->config_version = 0; // ESP8266 (Has been 0 for long time)
#endif // ESP8266
#ifdef ESP32
#ifdef CONFIG_IDF_TARGET_ESP32C3
Settings->config_version = 2; // ESP32C3
#ifdef CONFIG_IDF_TARGET_ESP32S3
Settings->config_version = 2; // ESP32S3
#elif CONFIG_IDF_TARGET_ESP32S2
Settings->config_version = 3; // ESP32S2
#elif CONFIG_IDF_TARGET_ESP32C3
Settings->config_version = 4; // ESP32C3
#else
Settings->config_version = 1; // ESP32
#endif // CONFIG_IDF_TARGET_ESP32C3
#endif // CONFIG_IDF_TARGET_ESP32S3
#endif // ESP32
}
if (Settings->version < 0x08020006) {

View File

@ -155,7 +155,6 @@ inline float atanf(float x) { return atan_66(x); }
inline float asinf(float x) { return asinf1(x); }
inline float acosf(float x) { return acosf1(x); }
inline float sqrtf(float x) { return sqrt1(x); }
inline float powf(float x, float y) { return FastPrecisePow(x, y); }
// Math constants we'll use
double const f_pi = 3.1415926535897932384626433; // f_pi

View File

@ -55,109 +55,6 @@
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#endif // FIRMWARE_WEBCAM
/*********************************************************************************************\
* [tasmota32-odroidgo.bin]
* Provide an image with useful supported sensors enabled for Odroid Go
\*********************************************************************************************/
#ifdef FIRMWARE_ODROID_GO
#undef CODE_IMAGE_STR
#define CODE_IMAGE_STR "odroid-go"
#undef MODULE
#define MODULE ODROID_GO // [Module] Select default module from tasmota_template.h
#undef FALLBACK_MODULE
#define FALLBACK_MODULE ODROID_GO // [Module2] Select default module on fast reboot where USER_MODULE is user template
#define USE_ODROID_GO // Add support for Odroid Go
#define USE_SDCARD
#define USE_WEBCLIENT_HTTPS
#undef USE_HOME_ASSISTANT
#define USE_I2C
#define USE_SPI
#define USE_DISPLAY
#define SHOW_SPLASH
#ifdef USE_UNIVERSAL_DISPLAY
#define USE_LVGL
#define USE_LVGL_FREETYPE
// #define USE_DISPLAY_LVGL_ONLY
#else
#define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code)
#define USE_DISPLAY_MODES1TO5
#endif
//#define USE_BLE_ESP32 // Enable new BLE driver
//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#endif // FIRMWARE_ODROID_GO
/*********************************************************************************************\
* [tasmota32-core2.bin]
* Provide an image with useful supported sensors enabled for M5stack core2
\*********************************************************************************************/
#ifdef FIRMWARE_M5STACK_CORE2
#undef CODE_IMAGE_STR
#define CODE_IMAGE_STR "core2"
#undef MODULE
#define MODULE M5STACK_CORE2 // [Module] Select default module from tasmota_template.h
#undef FALLBACK_MODULE
#define FALLBACK_MODULE M5STACK_CORE2 // [Module2] Select default module on fast reboot where USER_MODULE is user template
#undef USE_HOME_ASSISTANT
#define USE_M5STACK_CORE2 // Add support for M5Stack Core2
#define USE_I2S_SAY_TIME
#define USE_I2S_WEBRADIO
#define USE_SDCARD
#define USE_WEBCLIENT_HTTPS
#define USE_I2C
#define USE_BMA423
#define USE_MPU_ACCEL
#define USE_SPI
#define USE_DISPLAY
#define SHOW_SPLASH
#ifdef USE_UNIVERSAL_DISPLAY
#define USE_LVGL
#define USE_LVGL_FREETYPE
// #define USE_DISPLAY_LVGL_ONLY
#else
#define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code)
#define USE_DISPLAY_MODES1TO5
#endif
#define USE_TOUCH_BUTTONS
#define JPEG_PICTS
#define USE_FT5206
#define USE_SENDMAIL
#define USE_ESP32MAIL
#ifndef USE_RULES
#define USE_SCRIPT // Add support for script (+17k code)
// Script related defines
#define MAXVARS 75
#define MAXSVARS 15
#define MAXFILT 10
#define UFSYS_SIZE 8192
#define USE_SCRIPT_TASK
#define LARGE_ARRAYS
#define SCRIPT_LARGE_VNBUFF
#define USE_SCRIPT_GLOBVARS
#define USE_SCRIPT_SUB_COMMAND
#define USE_ANGLE_FUNC
#define USE_SCRIPT_WEB_DISPLAY
#define SCRIPT_FULL_WEBPAGE
#define SCRIPT_GET_HTTPS_JP
#define USE_GOOGLE_CHARTS
#endif // USE_RULES
#endif // FIRMWARE_M5STACK_CORE2
/*********************************************************************************************\
* [tasmota32-bluetooth.bin]
* Provide an image with BLE support
@ -212,6 +109,8 @@
#define USE_SPI
#define USE_LVGL
#define USE_LVGL_FREETYPE
#undef SET_ESP32_STACK_SIZE
#define SET_ESP32_STACK_SIZE (24 * 1024)
#define USE_LVGL_PNG_DECODER
#define USE_DISPLAY
#define SHOW_SPLASH
@ -224,7 +123,6 @@
#define USE_DISPLAY_LVGL_ONLY
#undef USE_DISPLAY_MODES1TO5
#undef SHOW_SPLASH
#undef USE_DISPLAY_LCD
#undef USE_DISPLAY_SSD1306
#undef USE_DISPLAY_MATRIX

View File

@ -376,11 +376,11 @@ void EnergyMarginCheck(void)
uint16_t min_power = (Energy.power_history[phase][0] > active_power) ? active_power : Energy.power_history[phase][0];
if (0 == min_power) { min_power++; } // Fix divide by 0 exception (#6741)
delta = (delta * 100) / min_power;
if (delta > Settings->energy_power_delta[phase]) {
if (delta >= Settings->energy_power_delta[phase]) {
threshold_met = true;
}
} else { // 101..32000 = Absolute
if (delta > (Settings->energy_power_delta[phase] -100)) {
if (delta >= (Settings->energy_power_delta[phase] -100)) {
threshold_met = true;
}
}

View File

@ -187,7 +187,11 @@ void HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b
if (r_b) *r_b = b;
}
#define POW FastPrecisePowf
#ifdef ESP8266
#define POW FastPrecisePowf
#else
#define POW powf
#endif
//
// Matrix 3x3 multiplied to a 3 vector, result in a 3 vector
@ -225,6 +229,7 @@ void RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y) {
mat3x3(XYZ_factors, rgb, XYZ);
float XYZ_sum = XYZ[0] + XYZ[1] + XYZ[2];
// AddLog(LOG_LEVEL_DEBUG, ">>>: RgbToXy X=%5_f Y=%5_f Z=%5_f TOTAL=%5_f", &XYZ[0], &XYZ[1], &XYZ[2], &XYZ_sum);
x = XYZ[0] / XYZ_sum;
y = XYZ[1] / XYZ_sum;
// we keep the raw gamut, one nice thing could be to convert to a narrower gamut
@ -239,14 +244,17 @@ void XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_t *rb)
x = (x > 0.99f ? 0.99f : (x < 0.01f ? 0.01f : x));
y = (y > 0.99f ? 0.99f : (y < 0.01f ? 0.01f : y));
float z = 1.0f - x - y;
// AddLog(LOG_LEVEL_DEBUG, ">>>: XyToRgb x=%5_f y=%5_f z=%5_f", &x, &y, &z);
XYZ[0] = x / y;
XYZ[1] = 1.0f;
XYZ[2] = z / y;
static const float rgb_factors[] = { 3.2406f, -1.5372f, -0.4986f,
-0.9689f, 1.8758f, 0.0415f,
0.0557f, -0.2040f, 1.0570f };
// AddLog(LOG_LEVEL_DEBUG, ">>>: XyToRgb X=%5_f Y=%5_f Z=%5_f", &XYZ[0], &XYZ[1], &XYZ[2]);
static const float rgb_factors[] = { 1.612f, -0.203f, -0.302f,
-0.509f, 1.412f, 0.066f,
0.026f, -0.072f, 0.962f };
mat3x3(rgb_factors, XYZ, rgb);
// AddLog(LOG_LEVEL_DEBUG, ">>>: XyToRgb rr=%5_f gg=%5_f bb=%5_f", &rgb[0], &rgb[1], &rgb[2]);
float max = (rgb[0] > rgb[1] && rgb[0] > rgb[2]) ? rgb[0] : (rgb[1] > rgb[2]) ? rgb[1] : rgb[2];
for (uint32_t i = 0; i < 3; i++) {

View File

@ -3801,15 +3801,15 @@ extern char *SML_GetSVal(uint32_t index);
float fvar2;
lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv);
SCRIPT_SKIP_SPACES
if (fvar2==0) {
if (fvar2 == 0) {
float fvar3;
lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv);
fvar = SML_SetBaud(fvar1, fvar3);
} else if (fvar2==1) {
} else if (fvar2 == 1) {
char str[SCRIPT_MAXSSIZE];
lp = GetStringArgument(lp, OPER_EQU, str, 0);
fvar = SML_Write(fvar1, str);
} else if (fvar2==2) {
} else if (fvar2 == 2) {
char str[SCRIPT_MAXSSIZE];
str[0] = 0;
fvar = SML_Read(fvar1, str, SCRIPT_MAXSSIZE);
@ -3817,8 +3817,27 @@ extern char *SML_GetSVal(uint32_t index);
lp++;
len = 0;
goto strexit;
} else if (fvar2 == 3) {
uint8_t vtype;
struct T_INDEX ind;
lp = isvar(lp, &vtype, &ind, 0, 0, 0);
if (vtype != VAR_NV) {
// found variable as result
if (vtype == NUM_RES || (vtype & STYPE) == 0) {
// numeric result
fvar = -1;
} else {
// string result
uint8_t sindex = glob_script_mem.type[ind.index].index;
char *cp = glob_script_mem.glob_snp + (sindex * glob_script_mem.max_ssize);
fvar = SML_Set_WStr(fvar1, cp);
}
} else {
fvar = -99;
}
} else {
#ifdef ED300L
fvar = SML_Status(fvar1);
#else

View File

@ -175,8 +175,16 @@ void ShutterRtc50mS(void)
if (Shutter[i].accelerator) {
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Accelerator i=%d -> %d"),i, Shutter[i].accelerator);
ShutterUpdateVelocity(i);
digitalWrite(Pin(GPIO_PWM1, i), LOW);
#ifdef ESP8266
// Convert frequency into clock cycles
uint32_t cc = microsecondsToClockCycles(1000000UL) / Shutter[i].pwm_velocity;
startWaveformClockCycles(Pin(GPIO_PWM1, i), cc/2, cc/2, 0, -1, 0, false);
#endif // ESP8266
#ifdef ESP32
analogWriteFreq(Shutter[i].pwm_velocity);
analogWrite(Pin(GPIO_PWM1, i), 50);
#endif // ESP32
}
break;
}

View File

@ -34,43 +34,47 @@ Renderer *Init_uDisplay(const char *desc);
* display.start(string) -> comptr or nil if failed
*
\*********************************************************************************************/
extern "C" {
int be_ntv_display_start(bvm *vm) {
#ifdef USE_UNIVERSAL_DISPLAY
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 1 && be_isstring(vm, 1)) {
const char * desc = be_tostring(vm, 1);
// remove all objects on stack to avoid warnings in subsequent calls to Berry
be_pop(vm, argc);
Renderer * renderer = Init_uDisplay(desc);
if (renderer) {
be_pushcomptr(vm, renderer);
} else {
be_pushnil(vm);
}
be_return(vm);
int be_ntv_display_start(struct bvm *vm) {
#ifdef USE_UNIVERSAL_DISPLAY
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 1 && be_isstring(vm, 1)) {
const char * desc = be_tostring(vm, 1);
// remove all objects on stack to avoid warnings in subsequent calls to Berry
be_pop(vm, argc);
Renderer * renderer = Init_uDisplay(desc);
if (renderer) {
be_pushcomptr(vm, renderer);
} else {
be_pushnil(vm);
}
be_raise(vm, kTypeError, nullptr);
#else // USE_UNIVERSAL_DISPLAY
be_raise(vm, "internal_error", "universal display driver not present");
#endif // USE_UNIVERSAL_DISPLAY
}
// `display.dimmer([dim:int]) -> int` sets the dimmer of display, value 0..100. If `0` then turn off display. If no arg, read the current value.
int be_ntv_display_dimmer(bvm *vm) {
int32_t argc = be_top(vm); // Get the number of arguments
int32_t dimmer;
if (argc >= 1) {
if (!be_isint(vm, 1)) { be_raise(vm, "type_error", "arg must be int"); }
dimmer = be_toint(vm, 1);
if ((dimmer < 0) || (dimmer > 100)) { be_raise(vm, "value_error", "value must be in range 0..100"); }
be_pop(vm, argc); // clear stack to avoid ripple errors in code called later
SetDisplayDimmer(dimmer);
ApplyDisplayDimmer();
}
be_pushint(vm, GetDisplayDimmer());
be_return(vm);
}
be_raise(vm, kTypeError, nullptr);
#else // USE_UNIVERSAL_DISPLAY
be_raise(vm, "internal_error", "universal display driver not present");
#endif // USE_UNIVERSAL_DISPLAY
}
// `display.dimmer([dim:int]) -> int` sets the dimmer of display, value 0..100. If `0` then turn off display. If no arg, read the current value.
int be_ntv_display_dimmer(struct bvm *vm) {
int32_t argc = be_top(vm); // Get the number of arguments
int32_t dimmer;
if (argc >= 1) {
if (!be_isint(vm, 1)) { be_raise(vm, "type_error", "arg must be int"); }
dimmer = be_toint(vm, 1);
if ((dimmer < 0) || (dimmer > 100)) { be_raise(vm, "value_error", "value must be in range 0..100"); }
be_pop(vm, argc); // clear stack to avoid ripple errors in code called later
SetDisplayDimmer(dimmer);
ApplyDisplayDimmer();
}
be_pushint(vm, GetDisplayDimmer());
be_return(vm);
}
void be_ntv_display_touch_update(int32_t touches, int32_t raw_x, int32_t raw_y, int32_t gesture) {
#if defined(USE_LVGL_TOUCHSCREEN) || defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS)
Touch_SetStatus(touches, raw_x, raw_y, gesture);
#endif
}
#endif // USE_DISPLAY

View File

@ -1,7 +1,7 @@
/*
xdrv_55_touch.ino - Touch contolers
Copyright (C) 2021 Gerhard Mutz and Theo Arends
Copyright (C) 2021 Gerhard Mutz, Theo Arends & 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
@ -17,9 +17,26 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************************\
* Universal TouchScreen driver, extensible via Berry
*
* API:
* void Touch_Init() - TODO
*
* uint32_t Touch_Status(int32_t sel)
* 0: return 1 if TSGlobal.touched
* 1: return x
* 2: return y
* -1: return raw x (before conersion for resistive)
* -2: return raw y
*
* void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y))
*
* void TS_RotConvert(int16_t *x, int16_t *y) - calls the renderer's rotation converter
\*******************************************************************************************/
#if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS)
#if defined(USE_LVGL_TOUCHSCREEN) || defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS)
#ifdef USE_DISPLAY_LVGL_ONLY
#undef USE_TOUCH_BUTTONS
@ -29,13 +46,33 @@
#define XDRV_55 55
// Codes for gestures, when supported by the Touch Screen controller
enum TS_Gesture {
TS_Gest_None = 0,
TS_Gest_Move_Up = 0x10,
TS_Gest_Move_Down = 0x11,
TS_Gest_Move_Left = 0x12,
TS_Gest_Move_Right = 0x13,
TS_Gest_Zoom_In = 0x20,
TS_Gest_Zoom_Out = 0x21,
};
typedef struct TSGlobal_t {
int16_t raw_touch_xp = 0;
int16_t raw_touch_yp = 0;
int16_t touch_xp = 0;
int16_t touch_yp = 0;
uint8_t touches = 0; // number of touches for multi-touch
uint8_t gesture = 0; // gesture code
// multi-point is not yet supported
bool touched = false;
bool external_ts = false;
} TSGlobal_t;
TSGlobal_t TSGlobal;
bool FT5206_found = false;
bool XPT2046_found = false;
int16_t raw_touch_xp;
int16_t raw_touch_yp;
int16_t touch_xp;
int16_t touch_yp;
bool touched;
#ifndef MAX_TOUCH_BUTTONS
#define MAX_TOUCH_BUTTONS 16
@ -45,19 +82,44 @@ bool touched;
VButton *buttons[MAX_TOUCH_BUTTONS];
#endif
void Touch_SetStatus(uint8_t touches, uint16_t raw_x, uint16_t raw_y, uint8_t gesture) {
TSGlobal.external_ts = true;
TSGlobal.gesture = gesture;
TSGlobal.touches = touches;
TSGlobal.touched = (TSGlobal.touches > 0);
TSGlobal.touch_xp = TSGlobal.raw_touch_xp = raw_x;
TSGlobal.touch_yp = TSGlobal.raw_touch_yp = raw_y;
TS_RotConvert(&TSGlobal.touch_xp, &TSGlobal.touch_yp);
}
// return true if succesful, false if not configured
bool Touch_GetStatus(uint8_t* touches, uint16_t* x, uint16_t* y, uint8_t* gesture,
uint16_t* raw_x, uint16_t* raw_y) {
if (TSGlobal.external_ts || FT5206_found || XPT2046_found) {
if (touches) { *touches = TSGlobal.touches; }
if (x) { *x = TSGlobal.touch_xp; }
if (y) { *y = TSGlobal.touch_yp; }
if (raw_x) { *raw_x = TSGlobal.raw_touch_xp; }
if (raw_y) { *raw_y = TSGlobal.raw_touch_yp; }
if (gesture) { *touches = TSGlobal.gesture; }
return true;
}
return false;
}
uint32_t Touch_Status(int32_t sel) {
if (FT5206_found || XPT2046_found) {
if (TSGlobal.external_ts || FT5206_found || XPT2046_found) {
switch (sel) {
case 0:
return touched;
return TSGlobal.touched;
case 1:
return touch_xp;
return TSGlobal.touch_xp;
case 2:
return touch_yp;
return TSGlobal.touch_yp;
case -1: // before calibration
return raw_touch_xp;
return TSGlobal.raw_touch_xp;
case -2:
return raw_touch_yp;
return TSGlobal.raw_touch_yp;
}
return 0;
} else {
@ -134,27 +196,27 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
#ifdef USE_FT5206
if (FT5206_found) {
touched = FT5206_touched();
if (touched) {
raw_touch_xp = FT5206_x();
raw_touch_yp = FT5206_y();
TSGlobal.touched = FT5206_touched();
if (TSGlobal.touched) {
TSGlobal.raw_touch_xp = FT5206_x();
TSGlobal.raw_touch_yp = FT5206_y();
}
}
#endif // USE_FT5206
#ifdef USE_XPT2046
if (XPT2046_found) {
touched = XPT2046_touched();
if (touched) {
raw_touch_xp = XPT2046_x();
raw_touch_yp = XPT2046_y();
TSGlobal.touched = XPT2046_touched();
if (TSGlobal.touched) {
TSGlobal.raw_touch_xp = XPT2046_x();
TSGlobal.raw_touch_yp = XPT2046_y();
}
}
#endif // USE_XPT2046
touch_xp = raw_touch_xp;
touch_yp = raw_touch_yp;
TSGlobal.touch_xp = TSGlobal.raw_touch_xp;
TSGlobal.touch_yp = TSGlobal.raw_touch_yp;
if (touched) {
if (TSGlobal.touched) {
was_touched = true;
#ifdef USE_TOUCH_BUTTONS
#ifdef USE_M5STACK_CORE2
@ -163,7 +225,7 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
#define TDELTA 30
#define TYPOS 275
for (uint32_t tbut = 0; tbut < 3; tbut++) {
if (touch_xp > (xcenter - TDELTA) && touch_xp < (xcenter + TDELTA) && touch_yp > (TYPOS - TDELTA) && touch_yp < (TYPOS + TDELTA)) {
if (TSGlobal.touch_xp > (xcenter - TDELTA) && TSGlobal.touch_xp < (xcenter + TDELTA) && TSGlobal.touch_yp > (TYPOS - TDELTA) && TSGlobal.touch_yp < (TYPOS + TDELTA)) {
// hit a button
if (!(tbstate[tbut] & 1)) {
// pressed
@ -177,11 +239,11 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
#endif // USE_M5STACK_CORE2
#endif // USE_TOUCH_BUTTONS
rotconvert(&touch_xp, &touch_yp);
AddLog(LOG_LEVEL_DEBUG_MORE, "TS : touched x=%i y=%i (raw x=%i y=%i)", touch_xp, touch_yp, raw_touch_xp, raw_touch_yp);
rotconvert(&TSGlobal.touch_xp, &TSGlobal.touch_yp);
AddLog(LOG_LEVEL_DEBUG_MORE, "TS : TSGlobal.touched x=%i y=%i (raw x=%i y=%i)", TSGlobal.touch_xp, TSGlobal.touch_yp, TSGlobal.raw_touch_xp, TSGlobal.raw_touch_yp);
#ifdef USE_TOUCH_BUTTONS
CheckTouchButtons(touched, touch_xp, touch_yp);
CheckTouchButtons(TSGlobal.touched, TSGlobal.touch_xp, TSGlobal.touch_yp);
#endif // USE_TOUCH_BUTTONS
} else {
@ -196,13 +258,13 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
}
#endif // USE_M5STACK_CORE2
rotconvert(&touch_xp, &touch_yp); // still do rot convert if not touched
rotconvert(&TSGlobal.touch_xp, &TSGlobal.touch_yp); // still do rot convert if not TSGlobal.touched
if (was_touched) {
AddLog(LOG_LEVEL_DEBUG_MORE, "TS : released x=%i y=%i (raw x=%i y=%i)", touch_xp, touch_yp, raw_touch_xp, raw_touch_yp);
AddLog(LOG_LEVEL_DEBUG_MORE, "TS : released x=%i y=%i (raw x=%i y=%i)", TSGlobal.touch_xp, TSGlobal.touch_yp, TSGlobal.raw_touch_xp, TSGlobal.raw_touch_yp);
was_touched = false;
}
#ifdef USE_TOUCH_BUTTONS
CheckTouchButtons(touched, touch_xp, touch_yp);
CheckTouchButtons(TSGlobal.touched, TSGlobal.touch_xp, TSGlobal.touch_yp);
#endif // USE_TOUCH_BUTTONS
}
@ -231,7 +293,7 @@ void CheckTouchButtons(bool touched, int16_t touch_x, int16_t touch_y) {
uint8_t vbutt=0;
if (!renderer) return;
if (touched) {
if (TSGlobal.touched) {
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("touch after convert %d - %d"), pLoc.x, pLoc.y);
// now must compare with defined buttons
for (uint8_t count = 0; count < MAX_TOUCH_BUTTONS; count++) {
@ -309,8 +371,8 @@ void CheckTouchButtons(bool touched, int16_t touch_x, int16_t touch_y) {
}
}
}
raw_touch_xp = touch_xp = 0;
raw_touch_yp = touch_yp = 0;
TSGlobal.raw_touch_xp = TSGlobal.touch_xp = 0;
TSGlobal.raw_touch_yp = TSGlobal.touch_yp = 0;
}
}
#endif // USE_TOUCH_BUTTONS

View File

@ -1,34 +0,0 @@
/*
xdrv_81_esp32_odroidgo.ino - ESP32 odroid go support for Tasmota
Copyright (C) 2021 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/>.
*/
#ifdef ESP32
#ifdef USE_ODROID_GO
/*********************************************************************************************\
* Odroid Go
*
* Clock frequency 160MHz (board_build.f_cpu = 160000000L)
* SPI Flash Size = 16MB (board_build.partitions = esp32_partition_app1984k_spiffs12M.csv)
*
* To be done:
* - Audio on GPIO25/26
*
/*********************************************************************************************/
#endif // USE_ODROID_GO
#endif // ESP32

View File

@ -1,366 +0,0 @@
/*
xdrv_84_esp32_core2.ino - ESP32 m5stack core2 support for Tasmota
Copyright (C) 2021 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/>.
*/
#ifdef ESP32
#ifdef USE_M5STACK_CORE2
/*********************************************************************************************\
* M5Stack Core2 support
*
* Module 7
* Template {"NAME":"M5Core2","GPIO":[1,1,1,1,6720,6368,0,0,0,1,1,6400,0,0,736,1,0,0,0,704,0,1,1,1,0,0,0,0,640,608,1,1,1,0,672,0],"FLAG":0,"BASE":7}
*
* Initial commands:
* - DisplayType 2
* - DisplayCols 27
* - (optional) DisplayMode 2
* - Power on
* - Voltres 3
* - Ampres 1
*
* Todo:
* - i2s microphone as loudness sensor
* - rtc better sync
\*********************************************************************************************/
#define XDRV_84 84
#include <Esp.h>
#include <sys/time.h>
#include <esp_system.h>
#include <AXP192.h>
#include <BM8563_RTC.h>
#include <soc/rtc.h>
#include <SPI.h>
struct CORE2_globs {
AXP192 Axp;
BM8563_RTC Rtc;
bool ready;
bool tset;
int32_t shutdownseconds;
uint8_t wakeup_hour;
uint8_t wakeup_minute;
uint8_t shutdowndelay;
} core2_globs;
struct CORE2_ADC {
float vbus_v;
float batt_v;
float vbus_c;
float batt_c;
float temp;
} core2_adc;
/*********************************************************************************************/
void Core2DoShutdown(void) {
SettingsSaveAll();
RtcSettingsSave();
core2_globs.Rtc.clearIRQ();
if (core2_globs.shutdownseconds > 0) {
core2_globs.Rtc.SetAlarmIRQ(core2_globs.shutdownseconds);
} else {
RTC_TimeTypeDef wut;
wut.Hours = core2_globs.wakeup_hour;
wut.Minutes = core2_globs.wakeup_minute;
core2_globs.Rtc.SetAlarmIRQ(wut);
}
delay(10);
core2_globs.Axp.PowerOff();
}
void Core2GetADC(void) {
core2_adc.vbus_v = core2_globs.Axp.GetVBusVoltage();
core2_adc.batt_v = core2_globs.Axp.GetBatVoltage();
core2_adc.vbus_c = core2_globs.Axp.GetVinCurrent();
core2_adc.batt_c = core2_globs.Axp.GetBatCurrent();
core2_adc.temp = ConvertTemp(core2_globs.Axp.GetTempInAXP192());
}
void Core2GetRtc(void) {
RTC_TimeTypeDef RTCtime;
core2_globs.Rtc.GetTime(&RTCtime);
RtcTime.hour = RTCtime.Hours;
RtcTime.minute = RTCtime.Minutes;
RtcTime.second = RTCtime.Seconds;
RTC_DateTypeDef RTCdate;
core2_globs.Rtc.GetDate(&RTCdate);
RtcTime.day_of_week = RTCdate.WeekDay;
RtcTime.month = RTCdate.Month;
RtcTime.day_of_month = RTCdate.Date;
RtcTime.year = RTCdate.Year;
AddLog(LOG_LEVEL_INFO, PSTR("CR2: Set RTC %04d-%02d-%02dT%02d:%02d:%02d"),
RTCdate.Year, RTCdate.Month, RTCdate.Date, RTCtime.Hours, RTCtime.Minutes, RTCtime.Seconds);
}
void Core2SetUtc(uint32_t epoch_time) {
TIME_T tm;
BreakTime(epoch_time, tm);
RTC_TimeTypeDef RTCtime;
RTCtime.Hours = tm.hour;
RTCtime.Minutes = tm.minute;
RTCtime.Seconds = tm.second;
core2_globs.Rtc.SetTime(&RTCtime);
RTC_DateTypeDef RTCdate;
RTCdate.WeekDay = tm.day_of_week;
RTCdate.Month = tm.month;
RTCdate.Date = tm.day_of_month;
RTCdate.Year = tm.year + 1970;
core2_globs.Rtc.SetDate(&RTCdate);
}
uint32_t Core2GetUtc(void) {
RTC_TimeTypeDef RTCtime;
// 1. read has errors ???
core2_globs.Rtc.GetTime(&RTCtime);
core2_globs.Rtc.GetTime(&RTCtime);
RTC_DateTypeDef RTCdate;
core2_globs.Rtc.GetDate(&RTCdate);
TIME_T tm;
tm.second = RTCtime.Seconds;
tm.minute = RTCtime.Minutes;
tm.hour = RTCtime.Hours;
tm.day_of_week = RTCdate.WeekDay;
tm.day_of_month = RTCdate.Date;
tm.month = RTCdate.Month;
tm.year = RTCdate.Year - 1970;
return MakeTime(tm);
}
/*********************************************************************************************\
* Called from xdrv_10_scripter.ino
\*********************************************************************************************/
extern uint8_t tbstate[3];
// c2ps(a b)
float Core2SetAxpPin(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;
case 3:
switch (val) {
case 0:
return core2_globs.Axp.isACIN();
break;
case 1:
return core2_globs.Axp.isCharging();
break;
case 2:
return core2_globs.Axp.isVBUS();
break;
case 3:
return core2_globs.Axp.AXPInState();
break;
}
break;
default:
Core2GetRtc();
break;
}
return 0;
}
/*********************************************************************************************\
* Called from xdrv_42_i2s_audio.ino
\*********************************************************************************************/
void Core2AudioPower(bool power) {
core2_globs.Axp.SetSpkEnable(power);
}
/*********************************************************************************************\
* Called from xdsp_04_ili9341.ino and xdsp_17_universal.ino
\*********************************************************************************************/
void Core2DisplayPower(uint8_t on) {
core2_globs.Axp.SetDCDC3(on);
}
// display dimmer ranges from 0-15
// very little effect
void Core2DisplayDim(uint8_t dim) {
uint16_t voltage = 2200;
voltage += ((uint32_t)dim*1200)/15;
core2_globs.Axp.SetLcdVoltage(voltage);
// core2_globs.Axp.ScreenBreath(dim);
}
/*********************************************************************************************/
// cause SC card is needed by scripter
void Core2ModuleInit(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);
// motor voltage
core2_globs.Axp.SetLDOVoltage(3,2000);
core2_globs.Rtc.begin();
I2cSetActiveFound(RTC_ADRESS, "RTC");
core2_globs.ready = true;
}
void Core2Init(void) {
if (Rtc.utc_time < START_VALID_TIME) {
// set rtc from chip
Rtc.utc_time = Core2GetUtc();
TIME_T tmpTime;
TasmotaGlobal.ntp_force_sync = true; // Force to sync with ntp
BreakTime(Rtc.utc_time, tmpTime);
Rtc.daylight_saving_time = RuleToTime(Settings->tflag[1], RtcTime.year);
Rtc.standard_time = RuleToTime(Settings->tflag[0], RtcTime.year);
AddLog(LOG_LEVEL_INFO, PSTR("CR2: Set time from BM8563 to 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
TasmotaGlobal.rules_flag.time_init = 1;
} else {
TasmotaGlobal.rules_flag.time_set = 1;
}
}
}
void Core2Loop(uint32_t flg) {
}
void Core2EverySecond(void) {
if (core2_globs.ready) {
Core2GetADC();
if (Rtc.utc_time > START_VALID_TIME && core2_globs.tset==false && abs((int32_t)Rtc.utc_time - (int32_t)Core2GetUtc()) > 3) {
Core2SetUtc(Rtc.utc_time);
AddLog(LOG_LEVEL_INFO, PSTR("CR2: Write Time TO BM8563 from NTP (" 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());
core2_globs.tset = true;
}
if (core2_globs.shutdowndelay) {
core2_globs.shutdowndelay--;
if (!core2_globs.shutdowndelay) {
Core2DoShutdown();
}
}
}
}
void Core2Show(uint32_t json) {
if (json) {
ResponseAppend_P(PSTR(",\"Core2\":{\"VBV\":%*_f,\"VBC\":%*_f,\"BV\":%*_f,\"BC\":%*_f,\"" D_JSON_TEMPERATURE "\":%*_f}"),
Settings->flag2.voltage_resolution, &core2_adc.vbus_v,
Settings->flag2.current_resolution, &core2_adc.vbus_c,
Settings->flag2.voltage_resolution, &core2_adc.batt_v,
Settings->flag2.current_resolution, &core2_adc.batt_c,
Settings->flag2.temperature_resolution, &core2_adc.temp);
} else {
WSContentSend_Voltage("VBus", core2_adc.vbus_v);
WSContentSend_CurrentMA("VBus", core2_adc.vbus_c);
WSContentSend_Voltage("Batt", core2_adc.batt_v);
WSContentSend_CurrentMA("Batt", core2_adc.batt_c);
WSContentSend_Temp("Core2", core2_adc.temp);
}
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
const char kCore2Commands[] PROGMEM = "Core2|"
"Shutdown";
void (* const Core2Command[])(void) PROGMEM = {
&CmndCore2Shutdown};
void CmndCore2Shutdown(void) {
char *mp = strchr(XdrvMailbox.data, ':');
if (mp) {
core2_globs.wakeup_hour = atoi(XdrvMailbox.data);
core2_globs.wakeup_minute = atoi(mp+1);
core2_globs.shutdownseconds = -1;
core2_globs.shutdowndelay = 10;
char tbuff[16];
sprintf(tbuff, "%02.2d" D_HOUR_MINUTE_SEPARATOR "%02.2d", core2_globs.wakeup_hour, core2_globs.wakeup_minute );
ResponseCmndChar(tbuff);
} else {
if (XdrvMailbox.payload >= 30) {
core2_globs.shutdownseconds = XdrvMailbox.payload;
core2_globs.shutdowndelay = 10;
}
ResponseCmndNumber(XdrvMailbox.payload);
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv84(uint8_t function) {
bool result = false;
switch (function) {
case FUNC_LOOP:
Core2Loop(1);
break;
case FUNC_EVERY_SECOND:
Core2EverySecond();
break;
case FUNC_JSON_APPEND:
Core2Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
Core2Show(0);
break;
#endif
case FUNC_COMMAND:
result = DecodeCommand(kCore2Commands, Core2Command);
break;
case FUNC_INIT:
Core2Init();
break;
case FUNC_MODULE_INIT:
Core2ModuleInit();
break;
}
return result;
}
#endif // USE_M5STACK_CORE2
#endif // ESP32

View File

@ -89,6 +89,7 @@ struct METER_DESC {
char *txmem;
uint8_t index;
uint8_t max_index;
char *script_str;
uint8_t sopt;
};
@ -1848,93 +1849,117 @@ void SML_Decode(uint8_t index) {
cp += skip;
}
}
} else if (!strncmp(mp,"UUuuUUuu",8)) {
uint32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0);
ebus_dval=val;
mbus_dval=val;
mp+=8;
cp+=4;
} else if (*mp=='U' && *(mp+1)=='U' && *(mp+2)=='u' && *(mp+3)=='u'){
uint16_t val = cp[1]|(cp[0]<<8);
mbus_dval=val;
ebus_dval=val;
mp+=4;
cp+=2;
} else if (!strncmp(mp,"SSssSSss",8)) {
int32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0);
ebus_dval=val;
mbus_dval=val;
mp+=8;
cp+=4;
} else if (*mp=='u' && *(mp+1)=='u' && *(mp+2)=='U' && *(mp+3)=='U'){
uint16_t val = cp[0]|(cp[1]<<8);
mbus_dval=val;
ebus_dval=val;
mp+=4;
cp+=2;
} else if (*mp=='u' && *(mp+1)=='u') {
} else if (!strncmp(mp, "UUuuUUuu", 8)) {
uint32_t val = (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | (cp[3]<<0);
mp += 8;
cp += 4;
if (*mp == 's') {
mp++;
// swap words
val = (val>>16) | (val<<16);
}
ebus_dval = val;
mbus_dval = val;
} else if (!strncmp(mp, "uuUUuuUU", 8)) {
uint32_t val = (cp[1]<<24) | (cp[0]<<16) | (cp[3]<<8) | (cp[2]<<0);
mp += 8;
cp += 4;
if (*mp == 's') {
mp++;
// swap words
val = (val>>16) | (val<<16);
}
ebus_dval = val;
mbus_dval = val;
} else if (!strncmp(mp, "UUuu", 4)) {
uint16_t val = cp[1] | (cp[0]<<8);
mbus_dval = val;
ebus_dval = val;
mp += 4;
cp += 2;
} else if (!strncmp(mp, "SSssSSss", 8)) {
int32_t val = (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | (cp[3]<<0);
mp += 8;
cp += 4;
if (*mp == 's') {
mp++;
// swap words
val = ((uint32_t)val>>16) | ((uint32_t)val<<16);
}
ebus_dval = val;
mbus_dval = val;
} else if (!strncmp(mp, "ssSSssSS", 8)) {
int32_t val = (cp[1]<<24) | (cp[0]<<16) | (cp[3]<<8) | (cp[2]<<0);
mp += 8;
cp += 4;
if (*mp == 's') {
mp++;
// swap words
val = ((uint32_t)val>>16) | ((uint32_t)val<<16);
}
ebus_dval = val;
mbus_dval = val;
} else if (!strncmp(mp, "uuUU", 4)) {
uint16_t val = cp[0] | (cp[1]<<8);
mbus_dval = val;
ebus_dval = val;
mp += 4;
cp += 2;
} else if (!strncmp(mp, "uu", 2)) {
uint8_t val = *cp++;
mbus_dval=val;
ebus_dval=val;
mp+=2;
} else if (*mp=='s' && *(mp+1)=='s' && *(mp+2)=='S' && *(mp+3)=='S') {
int16_t val = *cp|(*(cp+1)<<8);
mbus_dval=val;
ebus_dval=val;
mp+=4;
cp+=2;
} else if (*mp=='S' && *(mp+1)=='S' && *(mp+2)=='s' && *(mp+3)=='s') {
int16_t val = cp[1]|(cp[0]<<8);
mbus_dval=val;
ebus_dval=val;
mp+=4;
cp+=2;
}
else if (*mp=='s' && *(mp+1)=='s') {
mbus_dval = val;
ebus_dval = val;
mp += 2;
} else if (!strncmp(mp, "ssSS", 4)) {
int16_t val = *cp | (*(cp+1)<<8);
mbus_dval = val;
ebus_dval = val;
mp += 4;
cp += 2;
} else if (!strncmp(mp, "SSss", 4)) {
int16_t val = cp[1] | (cp[0]<<8);
mbus_dval = val;
ebus_dval = val;
mp += 4;
cp += 2;
} else if (!strncmp(mp,"ss", 2)) {
int8_t val = *cp++;
mbus_dval=val;
ebus_dval=val;
mp+=2;
}
else if (!strncmp(mp,"ffffffff",8)) {
uint32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0);
float *fp=(float*)&val;
ebus_dval=*fp;
mbus_dval=*fp;
mp+=8;
cp+=4;
}
else if (!strncmp(mp,"FFffFFff",8)) {
mbus_dval = val;
ebus_dval = val;
mp += 2;
} else if (!strncmp(mp, "ffffffff", 8)) {
uint32_t val = (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | (cp[3]<<0);
float *fp = (float*)&val;
ebus_dval = *fp;
mbus_dval = *fp;
mp += 8;
cp += 4;
} else if (!strncmp(mp, "FFffFFff", 8)) {
// reverse word float
uint32_t val= (cp[1]<<0)|(cp[0]<<8)|(cp[3]<<16)|(cp[2]<<24);
float *fp=(float*)&val;
ebus_dval=*fp;
mbus_dval=*fp;
mp+=8;
cp+=4;
}
else if (!strncmp(mp,"eeeeee",6)) {
uint32_t val=(cp[0]<<16)|(cp[1]<<8)|(cp[2]<<0);
mbus_dval=val;
mp+=6;
cp+=3;
}
else if (!strncmp(mp,"vvvvvv",6)) {
mbus_dval=(float)((cp[0]<<8)|(cp[1])) + ((float)cp[2]/10.0);
mp+=6;
cp+=3;
}
else if (!strncmp(mp,"cccccc",6)) {
mbus_dval=(float)((cp[0]<<8)|(cp[1])) + ((float)cp[2]/100.0);
mp+=6;
cp+=3;
}
else if (!strncmp(mp,"pppp",4)) {
mbus_dval=(float)((cp[0]<<8)|cp[1]);
mp+=4;
cp+=2;
}
else if (*mp == 'v') {
uint32_t val = (cp[1]<<0) | (cp[0]<<8) | (cp[3]<<16) | (cp[2]<<24);
float *fp = (float*)&val;
ebus_dval = *fp;
mbus_dval = *fp;
mp += 8;
cp += 4;
} else if (!strncmp(mp, "eeeeee", 6)) {
uint32_t val = (cp[0]<<16) | (cp[1]<<8) | (cp[2]<<0);
mbus_dval = val;
mp += 6;
cp += 3;
} else if (!strncmp(mp, "vvvvvv", 6)) {
mbus_dval = (float)((cp[0]<<8) | (cp[1])) + ((float)cp[2]/10.0);
mp += 6;
cp += 3;
} else if (!strncmp(mp, "cccccc", 6)) {
mbus_dval = (float)((cp[0]<<8) | (cp[1])) + ((float)cp[2]/100.0);
mp += 6;
cp += 3;
} else if (!strncmp(mp, "pppp", 4)) {
mbus_dval = (float)((cp[0]<<8) | cp[1]);
mp += 4;
cp += 2;
} else if (*mp == 'v') {
// vbus values vul, vsl, vuwh, vuwl, wswh, vswl, vswh
// vub3, vsb3 etc
mp++;
@ -2411,7 +2436,7 @@ uint8_t sml_cnt_index[MAX_COUNTERS] = { 0, 1, 2, 3 };
void IRAM_ATTR SML_CounterIsr(void *arg) {
uint32_t index = *static_cast<uint8_t*>(arg);
uint32_t time = micros();
uint32_t time = millis();
uint32_t debounce_time;
if (digitalRead(meter_desc_p[sml_counters[index].sml_cnt_old_state].srcpin) == bitRead(sml_counter_pinstate, index)) {
@ -2420,15 +2445,15 @@ uint32_t debounce_time;
debounce_time = time - sml_counters[index].sml_counter_ltime;
if (debounce_time <= sml_counters[index].sml_debounce * 1000) return;
if (debounce_time <= sml_counters[index].sml_debounce) return;
if bitRead(sml_counter_pinstate, index) {
// falling edge
RtcSettings.pulse_counter[index]++;
sml_counters[index].sml_cnt_updated=1;
sml_counters[index].sml_cnt_updated = 1;
}
sml_counters[index].sml_counter_ltime = time;
sml_counter_pinstate ^= (1<<index);
sml_counter_pinstate ^= (1 << index);
}
@ -2797,9 +2822,10 @@ init10:
// preloud counters
for (byte i = 0; i < MAX_COUNTERS; i++) {
RtcSettings.pulse_counter[i] = Settings->pulse_counter[i];
sml_counters[i].sml_cnt_last_ts=millis();
sml_counters[i].sml_cnt_last_ts = millis();
}
uint32_t uart_index = 2;
sml_counter_pinstate = 0;
for (uint8_t meters = 0; meters < meters_used; meters++) {
if (meter_desc_p[meters].type == 'c') {
if (meter_desc_p[meters].flag & 2) {
@ -2819,11 +2845,17 @@ init10:
// check for irq mode
if (meter_desc_p[meters].params<=0) {
// init irq mode
attachInterruptArg(meter_desc_p[meters].srcpin, SML_CounterIsr,&sml_cnt_index[cindex], CHANGE);
sml_counters[cindex].sml_cnt_old_state=meters;
sml_counters[cindex].sml_debounce=-meter_desc_p[meters].params;
sml_counters[cindex].sml_cnt_old_state = meters;
sml_counters[cindex].sml_debounce = -meter_desc_p[meters].params;
attachInterruptArg(meter_desc_p[meters].srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE);
if (digitalRead(meter_desc_p[meters].srcpin) > 0) {
sml_counter_pinstate |= (1 << cindex);
}
sml_counters[cindex].sml_counter_ltime = millis();
}
InjektCounterValue(meters,RtcSettings.pulse_counter[cindex]);
RtcSettings.pulse_counter[cindex] = Settings->pulse_counter[cindex];
InjektCounterValue(meters, RtcSettings.pulse_counter[cindex]);
cindex++;
}
} else {
@ -3007,6 +3039,15 @@ char *SML_GetSVal(uint32_t index) {
if (index < 1 || index > MAX_METERS) { index = 1;}
return &meter_id[index - 1][0];
}
int32_t SML_Set_WStr(uint32_t meter, char *hstr) {
if (meter < 1 || meter > meters_used) return -1;
meter--;
if (!meter_ss[meter]) return -2;
script_meter_desc[meter].script_str = hstr;
return 0;
}
#endif // USE_SML_SCRIPT_CMD
@ -3114,29 +3155,35 @@ char *SML_Get_Sequence(char *cp,uint32_t index) {
void SML_Check_Send(void) {
sml_100ms_cnt++;
char *cp;
for (uint32_t cnt=sml_desc_cnt; cnt<meters_used; cnt++) {
if (script_meter_desc[cnt].trxpin>=0 && script_meter_desc[cnt].txmem) {
for (uint32_t cnt = sml_desc_cnt; cnt < meters_used; cnt++) {
if (script_meter_desc[cnt].trxpin >= 0 && script_meter_desc[cnt].txmem) {
//AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> %d - %s - %d"),sml_desc_cnt,script_meter_desc[cnt].txmem,script_meter_desc[cnt].tsecs);
if ((sml_100ms_cnt>=script_meter_desc[cnt].tsecs)) {
sml_100ms_cnt=0;
//AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> 2"),cp);
if (script_meter_desc[cnt].max_index>1) {
script_meter_desc[cnt].index++;
if (script_meter_desc[cnt].index>=script_meter_desc[cnt].max_index) {
script_meter_desc[cnt].index=0;
if ((sml_100ms_cnt >= script_meter_desc[cnt].tsecs)) {
sml_100ms_cnt = 0;
// check for scriptsync extra output
if (script_meter_desc[cnt].script_str) {
cp = script_meter_desc[cnt].script_str;
script_meter_desc[cnt].script_str = 0;
} else {
//AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> 2"),cp);
if (script_meter_desc[cnt].max_index>1) {
script_meter_desc[cnt].index++;
if (script_meter_desc[cnt].index >= script_meter_desc[cnt].max_index) {
script_meter_desc[cnt].index = 0;
sml_desc_cnt++;
}
cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index);
//SML_Send_Seq(cnt,cp);
} else {
cp = script_meter_desc[cnt].txmem;
//SML_Send_Seq(cnt,cp);
sml_desc_cnt++;
}
cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index);
//SML_Send_Seq(cnt,cp);
} else {
cp=script_meter_desc[cnt].txmem;
//SML_Send_Seq(cnt,cp);
sml_desc_cnt++;
}
//AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),cp);
SML_Send_Seq(cnt,cp);
if (sml_desc_cnt>=meters_used) {
sml_desc_cnt=0;
if (sml_desc_cnt >= meters_used) {
sml_desc_cnt = 0;
}
break;
}
@ -3144,8 +3191,8 @@ void SML_Check_Send(void) {
sml_desc_cnt++;
}
if (sml_desc_cnt>=meters_used) {
sml_desc_cnt=0;
if (sml_desc_cnt >= meters_used) {
sml_desc_cnt = 0;
}
}
}

View File

@ -236,6 +236,7 @@ struct mi_sensor_t{
uint32_t NMT:1;
uint32_t motion:1;
uint32_t Btn:1;
uint32_t knob:1;
uint32_t door:1;
uint32_t leak:1;
};
@ -254,6 +255,8 @@ struct mi_sensor_t{
uint32_t motion:1;
uint32_t noMotion:1;
uint32_t Btn:1;
uint32_t knob:1;
uint32_t longpress:1; //needs no extra feature bit, because knob is sufficient
uint32_t door:1;
uint32_t leak:1;
};
@ -285,11 +288,15 @@ struct mi_sensor_t{
}; // MJ_HT_V1, LYWSD0x
struct {
uint16_t events; //"alarms" since boot
uint32_t NMT; // no motion time in seconds for the MJYD2S
uint32_t NMT; // no motion time in seconds for the MJYD2S and NLIGHT
};
struct {
uint16_t Btn;
uint8_t leak;
uint8_t Btn; // number starting with 0
uint8_t BtnType; // 0 -single, 1 - double, 2 - hold
uint8_t leak; // the leak sensor is the only non-RC device so far with a button fuctionality, so we handle it here
int8_t dimmer;
uint8_t pressed; // dimmer knob pressed while rotating
uint8_t longpress; // dimmer knob pressed without rotating
};
uint8_t door;
};
@ -315,9 +322,9 @@ struct mi_sensor_t{
#define D_CMND_MI32 "MI32"
const char kMI32_Commands[] PROGMEM = D_CMND_MI32 "|Key|"/*Time|Battery|Unit|Beacon|*/"Cfg|Option";
const char kMI32_Commands[] PROGMEM = D_CMND_MI32 "|Key|Cfg|Option";
void (*const MI32_Commands[])(void) PROGMEM = {&CmndMi32Key, /*&CmndMi32Time, &CmndMi32Battery, &CmndMi32Unit, &CmndMi32Beacon,*/ &CmndMi32Cfg, &CmndMi32Option };
void (*const MI32_Commands[])(void) PROGMEM = {&CmndMi32Key, &CmndMi32Cfg, &CmndMi32Option };
#define FLORA 1
#define MJ_HT_V1 2
@ -327,7 +334,7 @@ void (*const MI32_Commands[])(void) PROGMEM = {&CmndMi32Key, /*&CmndMi32Time, &C
#define CGD1 6
#define NLIGHT 7
#define MJYD2S 8
#define YEERC 9
#define YLYK01 9
#define MHOC401 10
#define MHOC303 11
#define ATC 12
@ -346,7 +353,7 @@ const uint16_t kMI32DeviceID[MI32_TYPES]={ 0x0098, // Flora
0x0576, // CGD1
0x03dd, // NLIGHT
0x07f6, // MJYD2S
0x0153, // yee-rc
0x0153, // YLYK01, old name yee-rc
0x0387, // MHO-C401
0x06d3, // MHO-C303
0x0a1c, // ATC -> this is a fake ID
@ -364,7 +371,7 @@ const char kMI32DeviceType5[] PROGMEM = "CGG1";
const char kMI32DeviceType6[] PROGMEM = "CGD1";
const char kMI32DeviceType7[] PROGMEM = "NLIGHT";
const char kMI32DeviceType8[] PROGMEM = "MJYD2S";
const char kMI32DeviceType9[] PROGMEM = "YEERC";
const char kMI32DeviceType9[] PROGMEM = "YLYK01"; //old name yeerc
const char kMI32DeviceType10[] PROGMEM ="MHOC401";
const char kMI32DeviceType11[] PROGMEM ="MHOC303";
const char kMI32DeviceType12[] PROGMEM ="ATC";
@ -382,6 +389,8 @@ const char kMI32_ConnErrorMsg[] PROGMEM = "no Error|could not connect|got no ser
const char kMI32_BLEInfoMsg[] PROGMEM = "Scan ended|Got Notification|Did connect|Did disconnect|Start scanning";
const char kMI32_HKInfoMsg[] PROGMEM = "HAP core started|HAP core did not start!!|HAP controller disconnected|HAP controller connected|HAP outlet added";
const char kMI32_ButtonMsg[] PROGMEM = "Single|Double|Hold"; //mapping: in Tasmota: 1,2,3 ; for HomeKit and Xiaomi 0,1,2
/*********************************************************************************************\
* enumerations
\*********************************************************************************************/

View File

@ -22,13 +22,15 @@
--------------------------------------------------------------------------------------------
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
0.9.5.1 20220209 changed - rename YEERC to YLYK01, add dimmer YLKG08 (incl. YLKG07), change button report scheme
-------
0.9.5.0 20211016 changed - major rewrite, added mi32cfg (file and command), Homekit-Bridge,
extended GUI,
removed BLOCK, PERIOD, TIME, UNIT, BATTERY and PAGE -> replaced via Berry-Support
-------
0.9.1.7 20201116 changed - small bugfixes, add BLOCK and OPTION command, send BLE scan via MQTT
-------
0.9.1.0 20200712 changed - add lights and yeerc, add pure passive mode with decryption,
0.9.1.0 20200712 changed - add lights and YLYK01, add pure passive mode with decryption,
lots of refactoring
-------
0.9.0.1 20200706 changed - adapt to new NimBLE-API, tweak scan process
@ -44,7 +46,7 @@
#ifdef USE_MI_ESP32
#ifdef USE_ENERGY_SENSOR
// #define USE_MI_ESP32_ENERGY //perpare for some GUI extensions
// #define USE_MI_ESP32_ENERGY //prepare for some GUI extensions
#endif
#define XSNS_62 62
@ -256,6 +258,7 @@ void MI32AddKey(mi_bindKey_t keyMAC){
_sensor.key = _key;
unknownMAC=false;
_sensor.status.hasWrongKey = 0;
AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*) _sensor.key, 16);
}
}
if(unknownMAC){
@ -278,7 +281,7 @@ int MI32_decryptPacket(char * _buf, uint16_t _bufSize, uint8_t * _payload, uint3
mi_beacon_t *_beacon = (mi_beacon_t *)_buf;
uint8_t nonce[13]; //v3:13, v5:12
uint32_t nonceLen =12; // most devices are v5
uint32_t nonceLen = 12; // most devices are v5
uint8_t tag[4] = {0};
const unsigned char authData[1] = {0x11};
size_t dataLen = _bufSize - 11 ; // _bufsize - frame - type - frame.counter - MAC
@ -288,13 +291,6 @@ int MI32_decryptPacket(char * _buf, uint16_t _bufSize, uint8_t * _payload, uint3
return -2;
}
// uint8_t _testBuf[] = {0x58,0x30,0xb6,0x03,0x36,0x8b,0x98,0xc5,0x41,0x24,0xf8,0x8b,0xb8,0xf2,0x66,0x13,0x51,0x00,0x00,0x00,0xd6};
// uint8_t _testKey[] = {0xb8,0x53,0x07,0x51,0x58,0x48,0x8d,0x3d,0x3c,0x97,0x7c,0xa3,0x9a,0x5b,0x5e,0xa9};
// _beacon = (mi_beacon_t *)_testBuf;
// _bufSize = sizeof(_testBuf);
// dataLen = _bufSize - 11 ; // _bufsize - frame - type - frame.counter - MAC
uint32_t _version = (uint32_t)_beacon->frame.version;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: encrypted msg from %s with version:%u"),kMI32DeviceType[MIBLEsensors[_slot].type-1],_version);
@ -335,8 +331,7 @@ int MI32_decryptPacket(char * _buf, uint16_t _bufSize, uint8_t * _payload, uint3
for (uint32_t i = 0; i<5; i++){
nonce[i+8] = _beacon->MAC[i];
}
tag[0] = _buf[_bufSize-1];
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*) nonce, 13);
// tag[0] = _buf[_bufSize-1]; // it is unclear, if this value is a checksum
dataLen -= 4;
}
else{
@ -345,7 +340,6 @@ int MI32_decryptPacket(char * _buf, uint16_t _bufSize, uint8_t * _payload, uint3
br_aes_small_ctrcbc_keys keyCtx;
br_aes_small_ctrcbc_init(&keyCtx, MIBLEsensors[_slot].key, 16);
// br_aes_small_ctrcbc_init(&keyCtx, _testKey, 16);
br_ccm_context ctx;
br_ccm_init(&ctx, &keyCtx.vtable);
@ -355,9 +349,9 @@ int MI32_decryptPacket(char * _buf, uint16_t _bufSize, uint8_t * _payload, uint3
br_ccm_run(&ctx, 0, _payload, dataLen);
if(br_ccm_check_tag(&ctx, &tag)) return 0;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: decrypted in %.2f mSec"),enctime);
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*) _payload, dataLen);
if(_version == 3 && _payload[1] == 0x10) return 0; // no known way to really verify decryption, but 0x10 is expected here for button events
return -1; // wrong key ... maybe corrupt data packet too
}
@ -457,9 +451,13 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter)
_newSensor.feature.bat=1;
_newSensor.NMT=0;
break;
case YEERC: case YLKG08:
_newSensor.feature.Btn=1;
_newSensor.Btn=99;
case YLYK01: case YLKG08:
_newSensor.feature.Btn = 1;
_newSensor.Btn = 99;
if(_type == YLKG08){
_newSensor.feature.knob = 1;
_newSensor.dimmer = 0;
}
#ifdef USE_MI_HOMEKIT
_newSensor.button_hap_service[0] = nullptr;
#endif //USE_MI_HOMEKIT
@ -1222,40 +1220,46 @@ if(decryptRet!=0){
MIBLEsensors[_slot].lastTime = millis();
switch(_payload.type){
case 0x01:
if(_payload.Btn.type == 4){ //knob dimmer
if(_payload.Btn.type == 4){ //dimmer knob rotation
MIBLEsensors[_slot].eventType.knob = 1;
if(_payload.Btn.num == 0){
if(_payload.Btn.value<128){
AddLog(LOG_LEVEL_DEBUG,PSTR("Rotate right: %u"),_payload.Btn.value);
}
else{
AddLog(LOG_LEVEL_DEBUG,PSTR("Rotate left: %u"),256 - _payload.Btn.value);
}
MIBLEsensors[_slot].pressed = 0;
MIBLEsensors[_slot].dimmer = _payload.Btn.value;
}
else if(_payload.Btn.num<128){
AddLog(LOG_LEVEL_DEBUG,PSTR("Rotate right: %u"),_payload.Btn.num);
else {
MIBLEsensors[_slot].pressed = 1;
MIBLEsensors[_slot].dimmer = _payload.Btn.num;
}
else{
AddLog(LOG_LEVEL_DEBUG,PSTR("Rotate left: %u"),256 - _payload.Btn.num);
}
return; //TODO: implement MQTT later
MI32.mode.shallTriggerTele = 1;
break; //To-Do: Map to HomeKit somehow or wait for real support of this device class in HomeKit
}
if(_payload.Btn.num == 1 && MIBLEsensors[_slot].feature.knob){ //dimmer knob long press
MIBLEsensors[_slot].longpress = _payload.Btn.value;
MI32.mode.shallTriggerTele = 1;
MIBLEsensors[_slot].eventType.longpress = 1;
#ifdef USE_MI_HOMEKIT
if((void**)MIBLEsensors[_slot].button_hap_service[0] != nullptr){
mi_homekit_update_value(MIBLEsensors[_slot].button_hap_service[0], (float)2.0f, 0x01); // only one button, long press = 2
}
#endif //USE_MI_HOMEKIT
break;
}
// single, double, long
MIBLEsensors[_slot].Btn = _payload.Btn.num;
if(MIBLEsensors[_slot].feature.knob){
MIBLEsensors[_slot].BtnType = _payload.Btn.value - 1;
}
else{
MIBLEsensors[_slot].BtnType = _payload.Btn.type;
}
MIBLEsensors[_slot].Btn=_payload.Btn.num + (_payload.Btn.type/2)*6;
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
#ifdef USE_MI_HOMEKIT
{
// {uint32_t _button = _payload.Btn.num + (_payload.Btn.type/2)*6;
uint32_t _singleLong = 0;
if(MIBLEsensors[_slot].Btn>5){
MIBLEsensors[_slot].Btn = MIBLEsensors[_slot].Btn - 6;
_singleLong = 2;
}
if(MIBLEsensors[_slot].Btn>5) break; //
if(MIBLEsensors[_slot].Btn>5) break; // hard coded limit for now
if((void**)MIBLEsensors[_slot].button_hap_service[MIBLEsensors[_slot].Btn] != nullptr){
// AddLog(LOG_LEVEL_DEBUG,PSTR("Send Button %u: SingleLong:%u, pointer: %x"), MIBLEsensors[_slot].Btn,_singleLong,MIBLEsensors[_slot].button_hap_service[MIBLEsensors[_slot].Btn] );
mi_homekit_update_value(MIBLEsensors[_slot].button_hap_service[MIBLEsensors[_slot].Btn], (float)_singleLong, 0x01);
}
}
mi_homekit_update_value(MIBLEsensors[_slot].button_hap_service[MIBLEsensors[_slot].Btn], (float)MIBLEsensors[_slot].BtnType, 0x01);
}
#endif //USE_MI_HOMEKIT
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 1: U16: %u Button"), MIBLEsensors[_slot].Btn );
break;
@ -1774,8 +1778,19 @@ void MI32sendWidget(uint32_t slot){
WSContentSend_P(PSTR("</p>"));
}
}
if(_sensor.feature.knob){
if(_sensor.pressed == 0) {
WSContentSend_P(PSTR("<p>Dimmer Steps: %d</p>"),_sensor.dimmer);
}
else {
WSContentSend_P(PSTR("<p>Dimmer Steps pressed: %d</p>"),_sensor.dimmer);
}
WSContentSend_P(PSTR("<p>Long: %u</p>"),_sensor.longpress);
}
if(_sensor.feature.Btn){
if(_sensor.Btn<12) WSContentSend_P(PSTR("<p>Last Button: %u</p>"),_sensor.Btn);
char _message[16];
GetTextIndexed(_message, sizeof(_message), _sensor.BtnType, kMI32_ButtonMsg);
if(_sensor.Btn<12) WSContentSend_P(PSTR("<p>Button%u: %s</p>"),_sensor.Btn,_message);
}
if(_sensor.feature.motion){
WSContentSend_P(PSTR("<p>Events: %u</p>"),_sensor.events);
@ -1797,7 +1812,7 @@ void MI32sendWidget(uint32_t slot){
WSContentSend_P(PSTR("<p>Leak !!!</p>"));
}
else{
WSContentSend_P(PSTR("<p>no leak</p>"));
WSContentSend_P(PSTR("<p>No leak</p>"));
}
}
WSContentSend_P(PSTR("</div>"));
@ -1990,7 +2005,29 @@ void MI32Show(bool json)
#endif //USE_HOME_ASSISTANT
){
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"Btn\":%u"),MIBLEsensors[i].Btn);
ResponseAppend_P(PSTR("\"Button%u\":%u"),MIBLEsensors[i].Btn,MIBLEsensors[i].BtnType + 1); //internal type is Xiaomi/Homekit 0,1,2 -> Tasmota 1,2,3
}
}
if (MIBLEsensors[i].feature.knob){
if(MIBLEsensors[i].eventType.knob
#ifdef USE_HOME_ASSISTANT
||(hass_mode==2)
#endif //USE_HOME_ASSISTANT
){
MI32ShowContinuation(&commaflg);
char _pressed[3] = {'_','P',0};
if (MIBLEsensors[i].pressed == 0){
_pressed[0] = 0;
}
ResponseAppend_P(PSTR("\"Dimmer%s\":%d"),_pressed, MIBLEsensors[i].dimmer);
}
if(MIBLEsensors[i].eventType.longpress
#ifdef USE_HOME_ASSISTANT
||(hass_mode==2)
#endif //USE_HOME_ASSISTANT
){
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"Hold\":%d"), MIBLEsensors[i].longpress);
}
}
} // minimal summary
@ -1998,14 +2035,14 @@ void MI32Show(bool json)
if(MIBLEsensors[i].eventType.motion || !MI32.mode.triggeredTele){
if(MI32.mode.triggeredTele) {
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"motion\":1")); // only real-time
ResponseAppend_P(PSTR("\"Motion\":1")); // only real-time
}
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"Events\":%u"),MIBLEsensors[i].events);
}
else if(MIBLEsensors[i].eventType.noMotion && MI32.mode.triggeredTele){
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"motion\":0"));
ResponseAppend_P(PSTR("\"Motion\":0"));
}
}
@ -2013,7 +2050,7 @@ void MI32Show(bool json)
if(MIBLEsensors[i].eventType.door || !MI32.mode.triggeredTele){
if(MI32.mode.triggeredTele) {
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"DOOR\":%u"),MIBLEsensors[i].door); // only real-time
ResponseAppend_P(PSTR("\"Door\":%u"),MIBLEsensors[i].door);
}
MI32ShowContinuation(&commaflg);
ResponseAppend_P(PSTR("\"Events\":%u"),MIBLEsensors[i].events);
@ -2131,7 +2168,7 @@ void MI32Show(bool json)
if(MIBLEsensors[i].bat!=0x00){
WSContentSend_PD(HTTP_BATTERY, kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].bat);
}
if (MIBLEsensors[i].type==YEERC){
if (MIBLEsensors[i].type==YLYK01){
WSContentSend_PD(HTTP_LASTBUTTON, kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].Btn);
}
}

View File

@ -40,7 +40,7 @@ static bool MIBridgeWasNeverConnected = true;
#define CGD1 6
#define NLIGHT 7
#define MJYD2S 8
#define YEERC 9
#define YLYK01 9
#define MHOC401 10
#define MHOC303 11
#define ATC 12
@ -221,7 +221,7 @@ static void MI32_bridge_thread_entry(void *p)
MI32saveHAPhandles(i,0x0a,hap_serv_get_char_by_uuid(service, HAP_CHAR_UUID_BATTERY_LEVEL));
break;
}
case YEERC:
case YLYK01:
{
bridge_cfg.cid = HAP_CID_PROGRAMMABLE_SWITCH;
hap_serv_t * _label = hap_serv_service_label_create(1);
@ -237,6 +237,20 @@ static void MI32_bridge_thread_entry(void *p)
}
}
break;
case YLKG08: //without the dimmer function due to lack of HomeKit support
{
bridge_cfg.cid = HAP_CID_PROGRAMMABLE_SWITCH;
hap_serv_t * _label = hap_serv_service_label_create(1);
hap_acc_add_serv(accessory, _label);
hap_serv_t * _newSwitch = hap_serv_stateless_programmable_switch_create(0);
const uint8_t _validVals[] = {0,1,2};
hap_char_add_valid_vals(hap_serv_get_char_by_uuid(_newSwitch, HAP_CHAR_UUID_PROGRAMMABLE_SWITCH_EVENT), _validVals, 3);
hap_char_t *_index = hap_char_service_label_index_create(1);
hap_serv_add_char(_newSwitch,_index);
hap_acc_add_serv(accessory, _newSwitch);
MI32saveHAPhandles(i,1000,hap_serv_get_char_by_uuid(_newSwitch, HAP_CHAR_UUID_PROGRAMMABLE_SWITCH_EVENT));
}
break;
case SJWS01L:
service = hap_serv_leak_sensor_create(0);
hap_serv_set_bulk_read_cb(service, MI32_bridge_read_callback);