Add rotary encoder support

- Add rotary encoder support for light dimmer and optional color temperature if button1 still pressed (#8670)
- Fix Mi Desk Lamp brightness control (#8748)
This commit is contained in:
Theo Arends 2020-06-30 16:58:36 +02:00
parent 6853926948
commit e52961b3b4
6 changed files with 61 additions and 76 deletions

View File

@ -91,3 +91,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
- Add support for single wire LMT01 temperature Sensor by justifiably (#8713) - Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
- Add compile time interlock parameters (#8759) - Add compile time interlock parameters (#8759)
- Add compile time user template (#8766) - Add compile time user template (#8766)
- Add rotary encoder support for light dimmer and optional color temperature if button1 still pressed (#8670)

View File

@ -8,6 +8,7 @@
- Add support for single wire LMT01 temperature Sensor by justifiably (#8713) - Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
- Add compile time interlock parameters (#8759) - Add compile time interlock parameters (#8759)
- Add compile time user template (#8766) - Add compile time user template (#8766)
- Add rotary encoder support for light dimmer and optional color temperature if button1 still pressed (#8670)
- Fix exception or watchdog on rule re-entry (#8757) - Fix exception or watchdog on rule re-entry (#8757)
- Change ESP32 USER GPIO template representation decreasing template message size - Change ESP32 USER GPIO template representation decreasing template message size
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT - Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT

View File

@ -429,7 +429,7 @@
// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) // #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code)
// -- Optional modules ---------------------------- // -- Optional modules ----------------------------
//#define ROTARY_V1 // Add support for MI Desk Lamp #define ROTARY_V1 // Add support for Rotary Encoder as used in MI Desk Lamp (+0k8 code)
#define USE_SONOFF_RF // Add support for Sonoff Rf Bridge (+3k2 code) #define USE_SONOFF_RF // Add support for Sonoff Rf Bridge (+3k2 code)
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+2k7 code) #define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+2k7 code)
#define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code) #define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code)

View File

@ -18,7 +18,6 @@
*/ */
#ifdef USE_LIGHT #ifdef USE_LIGHT
//#define ROTARY_V1
#ifdef ROTARY_V1 #ifdef ROTARY_V1
/*********************************************************************************************\ /*********************************************************************************************\
* Rotary support * Rotary support
@ -36,49 +35,40 @@ struct ROTARY {
/********************************************************************************************/ /********************************************************************************************/
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 // Fix core 2.5.x ISR not in IRAM Exception
void update_rotary(void) ICACHE_RAM_ATTR; void update_rotary(void) ICACHE_RAM_ATTR;
#endif // ARDUINO_ESP8266_RELEASE_2_3_0 void update_rotary(void) {
if (Rotary.busy || !LightPowerIRAM()) { return; }
void update_rotary(void) /*
{ * https://github.com/PaulStoffregen/Encoder/blob/master/Encoder.h
if (MI_DESK_LAMP == my_module_type) { */
if (LightPowerIRAM() && !Rotary.busy) { uint8_t s = Rotary.state & 3;
/* if (digitalRead(Pin(GPIO_ROT1A))) { s |= 4; }
* https://github.com/PaulStoffregen/Encoder/blob/master/Encoder.h if (digitalRead(Pin(GPIO_ROT1B))) { s |= 8; }
*/ switch (s) {
case 0: case 5: case 10: case 15:
uint8_t s = Rotary.state & 3; break;
if (digitalRead(Pin(GPIO_ROT1A))) { s |= 4; } case 1: case 7: case 8: case 14:
if (digitalRead(Pin(GPIO_ROT1B))) { s |= 8; } Rotary.position++; break;
switch (s) { case 2: case 4: case 11: case 13:
case 0: case 5: case 10: case 15: Rotary.position--; break;
break; case 3: case 12:
case 1: case 7: case 8: case 14: Rotary.position = Rotary.position + 2; break;
Rotary.position++; break; default:
case 2: case 4: case 11: case 13: Rotary.position = Rotary.position - 2; break;
Rotary.position--; break;
case 3: case 12:
Rotary.position = Rotary.position + 2; break;
default:
Rotary.position = Rotary.position - 2; break;
}
Rotary.state = (s >> 2);
}
} }
Rotary.state = (s >> 2);
} }
bool RotaryButtonPressed(void) bool RotaryButtonPressed(void) {
{ if (Rotary.changed && LightPower()) {
if ((MI_DESK_LAMP == my_module_type) && (Rotary.changed) && LightPower()) {
Rotary.changed = 0; // Color temp changed, no need to turn of the light Rotary.changed = 0; // Color temp changed, no need to turn of the light
return true; return true;
} }
return false; return false;
} }
void RotaryInit(void) void RotaryInit(void) {
{
Rotary.present = 0; Rotary.present = 0;
if (PinUsed(GPIO_ROT1A) && PinUsed(GPIO_ROT1B)) { if (PinUsed(GPIO_ROT1A) && PinUsed(GPIO_ROT1B)) {
Rotary.present++; Rotary.present++;
@ -93,57 +83,30 @@ void RotaryInit(void)
* Rotary handler * Rotary handler
\*********************************************************************************************/ \*********************************************************************************************/
void RotaryHandler(void) void RotaryHandler(void) {
{
if (Rotary.last_position != Rotary.position) { if (Rotary.last_position != Rotary.position) {
Rotary.busy = true; Rotary.busy = true;
int rotary_position = Rotary.position - Rotary.last_position; int rotary_position = Rotary.position - Rotary.last_position;
if (MI_DESK_LAMP == my_module_type) { // Mi Desk lamp if (Button.hold_timer[0]) { // Button1 is pressed: set color temperature
if (Button.hold_timer[0]) { // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ROT: " D_CMND_COLORTEMPERATURE " %d"), rotary_position);
Rotary.changed = 1; Rotary.changed = 1;
// button1 is pressed: set color temperature LightColorTempOffset(rotary_position * 4);
int16_t t = LightGetColorTemp(); } else {
t = t + ((rotary_position) * 4); // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ROT: " D_CMND_DIMMER " %d"), rotary_position);
if (t < 153) { LightDimmerOffset(rotary_position);
t = 153;
}
if (t > 500) {
t = 500;
}
DEBUG_CORE_LOG(PSTR("ROT: " D_CMND_COLORTEMPERATURE " %d"), rotary_position);
LightSetColorTemp((uint16_t)t);
// char scmnd[20];
// snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_COLORTEMPERATURE " %d"), t);
// ExecuteCommand(scmnd, SRC_SWITCH);
} else {
int8_t d = Settings.light_dimmer;
d = d + rotary_position;
if (d < 1) {
d = 1;
}
if (d > 100) {
d = 100;
}
DEBUG_CORE_LOG(PSTR("ROT: " D_CMND_DIMMER " %d"), rotary_position);
char scmnd[20];
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER "0 %d"), d);
ExecuteCommand(scmnd, SRC_SWITCH);
}
} }
Rotary.last_position = 128; Rotary.last_position = 128;
Rotary.position = 128; Rotary.position = 128;
Rotary.busy = false; Rotary.busy = false;
} }
} }
void RotaryLoop(void) void RotaryLoop(void) {
{
if (Rotary.present) { if (Rotary.present) {
if (TimeReached(Rotary.debounce)) { if (TimeReached(Rotary.debounce)) {
SetNextTimeInterval(Rotary.debounce, Settings.button_debounce); // Using button_debounce setting for this as well SetNextTimeInterval(Rotary.debounce, Settings.button_debounce); // Using button_debounce setting for this as well
RotaryHandler(); RotaryHandler();
} }
} }

View File

@ -33,7 +33,7 @@
#undef USE_DISCOVERY // Disable mDNS (+8k code or +23.5k code with core 2_5_x, +0.3k mem) #undef USE_DISCOVERY // Disable mDNS (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
// -- Optional modules ---------------------------- // -- Optional modules ----------------------------
//#define ROTARY_V1 // Add support for MI Desk Lamp #define ROTARY_V1 // Add support for Rotary Encoder as used in MI Desk Lamp
#define USE_SONOFF_RF // Add support for Sonoff Rf Bridge (+3k2 code) #define USE_SONOFF_RF // Add support for Sonoff Rf Bridge (+3k2 code)
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+2k7 code) #define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+2k7 code)
#define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code) #define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code)

View File

@ -895,7 +895,7 @@ void LightStateClass::XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_
0.0557f, -0.2040f, 1.0570f }; 0.0557f, -0.2040f, 1.0570f };
mat3x3(rgb_factors, XYZ, rgb); mat3x3(rgb_factors, XYZ, rgb);
float max = (rgb[0] > rgb[1] && rgb[0] > rgb[2]) ? rgb[0] : (rgb[1] > rgb[2]) ? 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++) { for (uint32_t i = 0; i < 3; i++) {
rgb[i] = rgb[i] / max; // normalize to max == 1.0 rgb[i] = rgb[i] / max; // normalize to max == 1.0
rgb[i] = (rgb[i] <= 0.0031308f) ? 12.92f * rgb[i] : 1.055f * POW(rgb[i], (1.0f / 2.4f)) - 0.055f; // gamma rgb[i] = (rgb[i] <= 0.0031308f) ? 12.92f * rgb[i] : 1.055f * POW(rgb[i], (1.0f / 2.4f)) - 0.055f; // gamma
@ -1478,12 +1478,22 @@ void LightSetBri(uint8_t device, uint8_t bri) {
} }
} }
void LightColorTempOffset(int32_t offset) {
int32_t ct = LightGetColorTemp();
if (0 == ct) { return; } // CT not supported
ct += offset;
if (ct < CT_MIN) { ct = CT_MIN; }
else if (ct > CT_MAX) { ct = CT_MAX; }
LightSetColorTemp(ct);
}
void LightSetColorTemp(uint16_t ct) void LightSetColorTemp(uint16_t ct)
{ {
/* Color Temperature (https://developers.meethue.com/documentation/core-concepts) /* Color Temperature (https://developers.meethue.com/documentation/core-concepts)
* *
* ct = 153 = 6500K = Cold = CCWW = FF00 * ct = 153 mirek = 6500K = Cold = CCWW = FF00
* ct = 600 = 2000K = Warm = CCWW = 00FF * ct = 500 mirek = 2000K = Warm = CCWW = 00FF
*/ */
// don't set CT if not supported // don't set CT if not supported
if ((LST_COLDWARM != Light.subtype) && (LST_RGBCW != Light.subtype)) { if ((LST_COLDWARM != Light.subtype) && (LST_RGBCW != Light.subtype)) {
@ -2745,6 +2755,16 @@ void CmndColorTemperature(void)
} }
} }
void LightDimmerOffset(int32_t offset) {
int32_t dimmer = light_state.getDimmer() + offset;
if (dimmer < 1) { dimmer = 1; }
if (dimmer > 100) { dimmer = 100; }
XdrvMailbox.index = 0;
XdrvMailbox.payload = dimmer;
CmndDimmer();
}
void CmndDimmer(void) void CmndDimmer(void)
{ {
// Dimmer - Show current Dimmer state // Dimmer - Show current Dimmer state