From eb4770768f2d606e4ac26cb3a0bf923ecbde67ca Mon Sep 17 00:00:00 2001 From: Markus Kirberg Date: Fri, 10 Jan 2025 16:48:44 +0100 Subject: [PATCH] +Plug S: Support for Neopixel Status LEDs (#1601) --- mos.yml | 4 ++ src/ShellyPlusPlugS/shelly_init.cpp | 10 ++-- src/shelly_statusled.cpp | 77 +++++++++++++++++++++++++++++ src/shelly_statusled.hpp | 66 +++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 src/shelly_statusled.cpp create mode 100644 src/shelly_statusled.hpp diff --git a/mos.yml b/mos.yml index d9cbf59d..e8c21885 100644 --- a/mos.yml +++ b/mos.yml @@ -618,6 +618,8 @@ conds: ${build_vars.ESP_IDF_SDKCONFIG_OPTS} CONFIG_FREERTOS_UNICORE=y CONFIG_ESPTOOLPY_FLASHMODE_DIO=y + libs: + - location: https://github.com/mongoose-os-libs/neopixel cdefs: LED_GPIO: 25 LED_ON: 1 @@ -638,6 +640,8 @@ conds: - ["sw1.state_led_en", 1] - ["bl0937.power_coeff", "f", 0, {title: "BL0937 counts -> watts conversion coefficient"}] - ["bl0937.power_coeff", 1.64358469] # (16 + 1010 + 1935) / (9.55 + 617 + 1175) + - ["led.color_on", "i", 0x00FF00, {title: "LED color when on"}] + - ["led.color_off", "i", 0xFF0000, {title: "LED color when off"}] - when: build_vars.MODEL == "ShellyPlusRGBWPM" apply: diff --git a/src/ShellyPlusPlugS/shelly_init.cpp b/src/ShellyPlusPlugS/shelly_init.cpp index aea806b8..ac7443c9 100644 --- a/src/ShellyPlusPlugS/shelly_init.cpp +++ b/src/ShellyPlusPlugS/shelly_init.cpp @@ -19,6 +19,7 @@ #include "shelly_main.hpp" #include "shelly_output.hpp" #include "shelly_pm_bl0937.hpp" +#include "shelly_statusled.hpp" #include "shelly_sys_led_btn.hpp" #include "shelly_temp_sensor_ntc.hpp" @@ -30,10 +31,11 @@ void CreatePeripherals(std::vector> *inputs, std::unique_ptr *sys_temp) { outputs->emplace_back(new OutputPin(1, 4, 1)); - // TODO: GPIO 25 and 26 are actually neopixel lights, and are not used as such - // currently - outputs->emplace_back(new OutputPin(2, 25, 1)); - outputs->emplace_back(new OutputPin(3, 26, 1)); + outputs->emplace_back(new StatusLED(2, 25, 2, MGOS_NEOPIXEL_ORDER_GRB, + nullptr, mgos_sys_config_get_led())); + outputs->emplace_back(new StatusLED(3, 26, 2, MGOS_NEOPIXEL_ORDER_GRB, + FindOutput(2), + mgos_sys_config_get_led())); std::unique_ptr pm( new BL0937PowerMeter(1, 10 /* CF */, 22 /* CF1 */, 19 /* SEL */, 2, diff --git a/src/shelly_statusled.cpp b/src/shelly_statusled.cpp new file mode 100644 index 00000000..5b7ab68c --- /dev/null +++ b/src/shelly_statusled.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) Shelly-HomeKit Contributors + * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "shelly_statusled.hpp" + +#ifdef MGOS_CONFIG_HAVE_LED + +namespace shelly { + +StatusLED::StatusLED(int id, int pin, int num_pixel, + enum mgos_neopixel_order pixel_type, Output *chained_led, + const struct mgos_config_led *cfg) + : Output(id), + pin_(pin), + num_pixel_(num_pixel), + chained_led_(chained_led), + cfg_(cfg) { + pixel_ = mgos_neopixel_create(pin_, num_pixel_, pixel_type); + value_ = false; +} + +StatusLED::~StatusLED() { + mgos_neopixel_free(pixel_); +} + +bool StatusLED::GetState() { + return value_; +} + +int StatusLED::pin() const { + return pin_; +} + +struct rgb { + int r; + int g; + int b; +}; + +Status StatusLED::SetState(bool on, const char *source) { + if (chained_led_ != nullptr) { + chained_led_->SetState(on, source); + } + value_ = on; + // get color from config + struct rgb colorOn = {(cfg_->color_on >> 16) & 0xFF, + (cfg_->color_on >> 8) & 0xFF, + (cfg_->color_on >> 0) & 0xFF}; + struct rgb colorOff = {(cfg_->color_off >> 16) & 0xFF, + (cfg_->color_off >> 8) & 0xFF, + (cfg_->color_off >> 0) & 0xFF}; + + struct rgb color = on ? colorOn : colorOff; + + for (int i = 0; i < num_pixel_; i++) { + mgos_neopixel_set(pixel_, i, color.r, color.b, color.g); + } + mgos_neopixel_show(pixel_); + return Status::OK(); +} + +} // namespace shelly + +#endif diff --git a/src/shelly_statusled.hpp b/src/shelly_statusled.hpp new file mode 100644 index 00000000..54ae6d7a --- /dev/null +++ b/src/shelly_statusled.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) Shelly-HomeKit Contributors + * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mgos_config.h" + +#ifdef MGOS_CONFIG_HAVE_LED + +#pragma once + +#include "shelly_output.hpp" + +#include "mgos_neopixel.h" + +namespace shelly { + +class StatusLED : public Output { + public: + StatusLED(int id, int pin, int num_pixel, enum mgos_neopixel_order pixel_type, + Output *chained_led, const struct mgos_config_led *cfg); + virtual ~StatusLED(); + + // Output interface impl. + bool GetState() override; + Status SetState(bool on, const char *source) override; + Status SetStatePWM(float duty, const char *source) override { + return Status::UNIMPLEMENTED(); + }; + Status Pulse(bool on, int duration_ms, const char *source) override { + return Status::UNIMPLEMENTED(); + }; + void SetInvert(bool out_invert) override{}; + int pin() const; + + protected: + private: + const int pin_; + const int num_pixel_; + + bool value_; + + struct mgos_neopixel *pixel_; + + Output *chained_led_; + + const struct mgos_config_led *cfg_; + + StatusLED(const StatusLED &other) = delete; +}; + +} // namespace shelly + +#endif \ No newline at end of file