Skip to content

Commit

Permalink
Add rotary encoder support
Browse files Browse the repository at this point in the history
- Add rotary encoder support for light dimmer and optional color temperature if button1 still pressed (#8670)
- Fix Mi Desk Lamp brightness control (#8748)
  • Loading branch information
arendst committed Jun 30, 2020
1 parent 6853926 commit e52961b
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 77 deletions.
1 change: 1 addition & 0 deletions RELEASENOTES.md
Expand Up @@ -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 compile time interlock parameters (#8759)
- Add compile time user template (#8766)
- Add rotary encoder support for light dimmer and optional color temperature if button1 still pressed (#8670)
1 change: 1 addition & 0 deletions tasmota/CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@
- Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
- Add compile time interlock parameters (#8759)
- 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)
- Change ESP32 USER GPIO template representation decreasing template message size
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
Expand Down
2 changes: 1 addition & 1 deletion tasmota/my_user_config.h
Expand Up @@ -429,7 +429,7 @@
// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code)

// -- 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_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)
Expand Down
107 changes: 35 additions & 72 deletions tasmota/support_rotary.ino
Expand Up @@ -18,7 +18,6 @@
*/

#ifdef USE_LIGHT
//#define ROTARY_V1
#ifdef ROTARY_V1
/*********************************************************************************************\
* Rotary support
Expand All @@ -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;
#endif // ARDUINO_ESP8266_RELEASE_2_3_0

void update_rotary(void)
{
if (MI_DESK_LAMP == my_module_type) {
if (LightPowerIRAM() && !Rotary.busy) {
/*
* https://github.com/PaulStoffregen/Encoder/blob/master/Encoder.h
*/

uint8_t s = Rotary.state & 3;
if (digitalRead(Pin(GPIO_ROT1A))) { s |= 4; }
if (digitalRead(Pin(GPIO_ROT1B))) { s |= 8; }
switch (s) {
case 0: case 5: case 10: case 15:
break;
case 1: case 7: case 8: case 14:
Rotary.position++; break;
case 2: case 4: case 11: case 13:
Rotary.position--; break;
case 3: case 12:
Rotary.position = Rotary.position + 2; break;
default:
Rotary.position = Rotary.position - 2; break;
}
Rotary.state = (s >> 2);
}
void update_rotary(void) {
if (Rotary.busy || !LightPowerIRAM()) { return; }

/*
* https://github.com/PaulStoffregen/Encoder/blob/master/Encoder.h
*/
uint8_t s = Rotary.state & 3;
if (digitalRead(Pin(GPIO_ROT1A))) { s |= 4; }
if (digitalRead(Pin(GPIO_ROT1B))) { s |= 8; }
switch (s) {
case 0: case 5: case 10: case 15:
break;
case 1: case 7: case 8: case 14:
Rotary.position++; break;
case 2: case 4: case 11: case 13:
Rotary.position--; break;
case 3: case 12:
Rotary.position = Rotary.position + 2; break;
default:
Rotary.position = Rotary.position - 2; break;
}
Rotary.state = (s >> 2);
}

bool RotaryButtonPressed(void)
{
if ((MI_DESK_LAMP == my_module_type) && (Rotary.changed) && LightPower()) {
bool RotaryButtonPressed(void) {
if (Rotary.changed && LightPower()) {
Rotary.changed = 0; // Color temp changed, no need to turn of the light
return true;
}
return false;
}

void RotaryInit(void)
{
void RotaryInit(void) {
Rotary.present = 0;
if (PinUsed(GPIO_ROT1A) && PinUsed(GPIO_ROT1B)) {
Rotary.present++;
Expand All @@ -93,57 +83,30 @@ void RotaryInit(void)
* Rotary handler
\*********************************************************************************************/

void RotaryHandler(void)
{
void RotaryHandler(void) {
if (Rotary.last_position != Rotary.position) {
Rotary.busy = true;
int rotary_position = Rotary.position - Rotary.last_position;

if (MI_DESK_LAMP == my_module_type) { // Mi Desk lamp
if (Button.hold_timer[0]) {
Rotary.changed = 1;
// button1 is pressed: set color temperature
int16_t t = LightGetColorTemp();
t = t + ((rotary_position) * 4);
if (t < 153) {
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);
}
if (Button.hold_timer[0]) { // Button1 is pressed: set color temperature
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ROT: " D_CMND_COLORTEMPERATURE " %d"), rotary_position);
Rotary.changed = 1;
LightColorTempOffset(rotary_position * 4);
} else {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ROT: " D_CMND_DIMMER " %d"), rotary_position);
LightDimmerOffset(rotary_position);
}

Rotary.last_position = 128;
Rotary.position = 128;
Rotary.busy = false;
}
}

void RotaryLoop(void)
{
void RotaryLoop(void) {
if (Rotary.present) {
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();
}
}
Expand Down
2 changes: 1 addition & 1 deletion tasmota/tasmota_configurations.h
Expand Up @@ -33,7 +33,7 @@
#undef USE_DISCOVERY // Disable mDNS (+8k code or +23.5k code with core 2_5_x, +0.3k mem)

// -- 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_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)
Expand Down
26 changes: 23 additions & 3 deletions tasmota/xdrv_04_light.ino
Expand Up @@ -895,7 +895,7 @@ void LightStateClass::XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_
0.0557f, -0.2040f, 1.0570f };
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];

for (uint32_t i = 0; i < 3; i++) {
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
Expand Down Expand Up @@ -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)
{
/* Color Temperature (https://developers.meethue.com/documentation/core-concepts)
*
* ct = 153 = 6500K = Cold = CCWW = FF00
* ct = 600 = 2000K = Warm = CCWW = 00FF
* ct = 153 mirek = 6500K = Cold = CCWW = FF00
* ct = 500 mirek = 2000K = Warm = CCWW = 00FF
*/
// don't set CT if not supported
if ((LST_COLDWARM != Light.subtype) && (LST_RGBCW != Light.subtype)) {
Expand Down Expand Up @@ -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)
{
// Dimmer - Show current Dimmer state
Expand Down

0 comments on commit e52961b

Please sign in to comment.