Skip to content

Commit

Permalink
Renaming
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieucarbou committed Sep 21, 2024
1 parent eb372ff commit ee8dbc6
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 79 deletions.
51 changes: 31 additions & 20 deletions lib/MycilaDimmer/MycilaDimmer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ extern Mycila::Logger logger;

static const uint16_t TABLE_PHASE_DELAY[TABLE_PHASE_LEN] PROGMEM{0xefea, 0xdfd4, 0xd735, 0xd10d, 0xcc12, 0xc7cc, 0xc403, 0xc094, 0xbd6a, 0xba78, 0xb7b2, 0xb512, 0xb291, 0xb02b, 0xaddc, 0xaba2, 0xa97a, 0xa762, 0xa557, 0xa35a, 0xa167, 0x9f7f, 0x9da0, 0x9bc9, 0x99fa, 0x9831, 0x966e, 0x94b1, 0x92f9, 0x9145, 0x8f95, 0x8de8, 0x8c3e, 0x8a97, 0x88f2, 0x8750, 0x85ae, 0x840e, 0x826e, 0x80cf, 0x7f31, 0x7d92, 0x7bf2, 0x7a52, 0x78b0, 0x770e, 0x7569, 0x73c2, 0x7218, 0x706b, 0x6ebb, 0x6d07, 0x6b4f, 0x6992, 0x67cf, 0x6606, 0x6437, 0x6260, 0x6081, 0x5e99, 0x5ca6, 0x5aa9, 0x589e, 0x5686, 0x545e, 0x5224, 0x4fd5, 0x4d6f, 0x4aee, 0x484e, 0x4588, 0x4296, 0x3f6c, 0x3bfd, 0x3834, 0x33ee, 0x2ef3, 0x28cb, 0x202c, 0x1016};

void Mycila::Dimmer::beginDimmer(const int8_t pin, const uint16_t semiPeriod) {
if (_dimmer)
void Mycila::Dimmer::begin(int8_t pin, uint32_t semiPeriod) {
if (_enabled)
return;

if (!semiPeriod) {
LOGE(TAG, "Disable Dimmer on pin %" PRId8 ": Invalid semi-period: %" PRIu16 " us", pin, semiPeriod);
LOGE(TAG, "Disable Dimmer on pin %" PRId8 ": Invalid semi-period: %" PRIu32 " us", pin, semiPeriod);
return;
}

Expand All @@ -55,30 +55,28 @@ void Mycila::Dimmer::beginDimmer(const int8_t pin, const uint16_t semiPeriod) {
return;
}

LOGI(TAG, "Enable Dimmer on pin %" PRId8, _pin);
LOGI(TAG, "Enable Dimmer on pin %" PRId8 " with semi-period %" PRIu32 " us", pin, semiPeriod);

_semiPeriod = semiPeriod;
_dimmer = new Thyristor(_pin);
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
_enabled = true;

_dimmer = new Thyristor(_pin);
setDutyCycle(_dutyCycleMin);
}

void Mycila::Dimmer::endDimmer() {
if (_dimmer) {
LOGI(TAG, "Disable Dimmer on pin %" PRId8, _pin);
_dutyCycle = 0;
_dimmer->turnOff();
digitalWrite(_pin, LOW);
delete _dimmer;
_dimmer = nullptr;
_pin = GPIO_NUM_NC;
}
void Mycila::Dimmer::end() {
if (!_enabled)
return;

LOGI(TAG, "Disable Dimmer on pin %" PRId8, _pin);
_enabled = false;
_disable();
}

void Mycila::Dimmer::setDutyCycle(float newDutyCycle) {
if (!_dimmer)
if (!_enabled)
return;

if (_semiPeriod == 0)
Expand All @@ -104,25 +102,38 @@ void Mycila::Dimmer::setDutyCycle(float newDutyCycle) {
const uint32_t a = TABLE_PHASE_DELAY[index];
const uint32_t b = TABLE_PHASE_DELAY[index + 1];
const uint32_t delay = a - (((a - b) * (slot & 0xffff)) >> 16);
_dimmer->setDelay((delay * _semiPeriod) >> 16);
_delay = (delay * _semiPeriod) >> 16;

_dimmer->setDelay(_delay);
}
}

void Mycila::Dimmer::setDutyCycleLimit(float limit) {
_dutyCycleLimit = constrain(limit, 0, 1);
LOGD(TAG, "Set dimmer duty cycle limit to %f", _dutyCycleLimit);
LOGD(TAG, "Set dimmer %" PRId8 " duty cycle limit to %f", _pin, _dutyCycleLimit);
if (_dutyCycle > _dutyCycleLimit)
setDutyCycle(_dutyCycleLimit);
}

void Mycila::Dimmer::setDutyCycleMin(float min) {
_dutyCycleMin = constrain(min, 0, _dutyCycleMax);
LOGD(TAG, "Set dimmer duty cycle min to %f", _dutyCycleMin);
LOGD(TAG, "Set dimmer %" PRId8 " duty cycle min to %f", _pin, _dutyCycleMin);
setDutyCycle(_dutyCycle);
}

void Mycila::Dimmer::setDutyCycleMax(float max) {
_dutyCycleMax = constrain(max, _dutyCycleMin, 1);
LOGD(TAG, "Set dimmer duty cycle max to %f", _dutyCycleMax);
LOGD(TAG, "Set dimmer %" PRId8 " duty cycle max to %f", _pin, _dutyCycleMax);
setDutyCycle(_dutyCycle);
}

void Mycila::Dimmer::_disable() {
if (_enabled) {
_dutyCycle = 0;
_delay = UINT32_MAX;
digitalWrite(_pin, LOW);
delete _dimmer;
_dimmer = nullptr;
_pin = GPIO_NUM_NC;
}
}
141 changes: 111 additions & 30 deletions lib/MycilaDimmer/MycilaDimmer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,49 @@
namespace Mycila {
class Dimmer {
public:
~Dimmer() { endDimmer(); }
Dimmer() {}
~Dimmer() { end(); }

void beginDimmer(const int8_t pin, const uint16_t semiPeriod);
void endDimmer();
/**
* @brief Enable a dimmer on a specific GPIO pin
*
* @param pin: the GPIO pin to use for the dimmer
*
* @warning Dimmer won't be enabled if pin is invalid
* @warning Dimmer won't be activated until the ZCD is enabled
*/
void begin(int8_t pin, uint32_t semiPeriod);

/**
* @brief Disable the dimmer
*
* @warning Dimmer won't be destroyed but won't turn on anymore even is a duty cycle is set.
*/
void end();

/**
* @brief Check if the dimmer is enabled
*/
bool isEnabled() const { return _enabled; }

/**
* @brief Get the GPIO pin used for the dimmer
*/
gpio_num_t getPin() const { return _pin; }
bool isDimmerEnabled() const { return _dimmer != nullptr; }

#ifdef MYCILA_JSON_SUPPORT
/**
* @brief Serialize Dimmer information to a JSON object
*
* @param root: the JSON object to serialize to
*/
void dimmerToJson(const JsonObject& root) const {
const float angle = getPhaseAngle();
root["enabled"] = _dimmer != nullptr;
root["enabled"] = _enabled;
root["state"] = isOn() ? "on" : "off";
root["angle_d"] = angle * RAD_TO_DEG;
root["angle"] = angle;
root["delay"] = getFiringDelay();
root["delay"] = _delay;
root["duty_cycle"] = _dutyCycle;
root["duty_cycle_limit"] = _dutyCycleLimit;
root["duty_cycle_min"] = _dutyCycleMin;
Expand All @@ -41,52 +68,106 @@ namespace Mycila {
}
#endif

/**
* @brief Turn on the dimmer at full power
*/
void on() { setDutyCycle(1); }

/**
* @brief Turn off the dimmer
*/
void off() { setDutyCycle(0); }

/**
* @brief Check if the dimmer is off
*/
bool isOff() const { return _dutyCycle <= _dutyCycleMin; }

/**
* @brief Check if the dimmer is on
*/
bool isOn() const { return _dutyCycle > _dutyCycleMin; }

/**
* @brief Check if the dimmer is on at full power
*/
bool isOnAtFullPower() const { return _dutyCycle >= _dutyCycleMax; }

// Power Duty Cycle [0, 1]
// At 0% power, duty == 0
// At 100% power, duty == 1
/**
* @brief Set the power duty
*
* @param dutyCycle: the power duty cycle in the range [0.0, 1.0]
*/
void setDutyCycle(float dutyCycle);

// set the maximum duty [0, 1]
/**
* @brief Set the power duty cycle limit of the dimmer. The duty cycle will be clamped to this limit.
*
* @param limit: the power duty cycle limit in the range [0.0, 1.0]
*/
void setDutyCycleLimit(float limit);

// Duty remapping (equivalent to Shelly Dimmer remapping feature)
// remap the duty minimum and maximum values to be a new ones
// useful to calibrate the dimmer when using for example a PWM signal to 0-10V analog convertor connected to a voltage regulator which is only working in a specific voltage range like 1-8V
/**
* @brief Duty remapping (equivalent to Shelly Dimmer remapping feature).
* Useful to calibrate the dimmer when using for example a PWM signal to 0-10V analog convertor connected to a voltage regulator which is only working in a specific voltage range like 1-8V.
*
* @param min: Set the new "0" value for the power duty cycle. The duty cycle in the range [0.0, 1.0] will be remapped to [min, max].
*/
void setDutyCycleMin(float min);

/**
* @brief Duty remapping (equivalent to Shelly Dimmer remapping feature).
* Useful to calibrate the dimmer when using for example a PWM signal to 0-10V analog convertor connected to a voltage regulator which is only working in a specific voltage range like 1-8V.
*
* @param max: Set the new "1" value for the power duty cycle. The duty cycle in the range [0.0, 1.0] will be remapped to [min, max].
*/
void setDutyCycleMax(float max);

/**
* @brief Get the power duty cycle of the dimmer
*/
float getDutyCycle() const { return _dutyCycle; }

/**
* @brief Get the power duty cycle limit of the dimmer
*/
float getDutyCycleLimit() const { return _dutyCycleLimit; }

/**
* @brief Get the remapped "0" of the dimmer duty cycle
*/
float getDutyCycleMin() const { return _dutyCycleMin; }

/**
* @brief Get the remapped "1" of the dimmer duty cycle
*/
float getDutyCycleMax() const { return _dutyCycleMax; }

// Delay [0, semi-period] us
// Where semi-period = 1000000 / 2 / frequency (50h: 10000 us, 60Hz: 8333 us)
// At 0% power, delay is equal to the semi-period
// At 100% power, the delay is 0 us
uint16_t getFiringDelay() const { return isDimmerEnabled() ? _dimmer->getDelay() : _semiPeriod; }

// Phase angle [0, PI] rad
// At 0% power, the phase angle is equal to PI
// At 100% power, the phase angle is equal to 0
float getPhaseAngle() const {
// angle_rad = PI * delay_us / period_us
return _semiPeriod == 0 ? PI : PI * getFiringDelay() / _semiPeriod;
}
/**
* @brief Get the firing delay in us of the dimmer in the range [0, semi-period]
* At 0% power, delay is equal to the semi-period.
* At 100% power, the delay is 0 us
* If the firing delay is UINT32_MAX, the dimmer is off
*/
uint32_t getFiringDelay() const { return _delay; }

/**
* @brief Get the phase angle in radians of the dimmer in the range [0, PI]
* At 0% power, the phase angle is equal to PI
* At 100% power, the phase angle is equal to 0
*/
float getPhaseAngle() const { return _delay >= _semiPeriod ? PI : PI * _delay / _semiPeriod; }

private:
bool _enabled = false;
gpio_num_t _pin = GPIO_NUM_NC;
Thyristor* _dimmer = nullptr;
uint16_t _semiPeriod = 0;
uint32_t _semiPeriod = 0;
float _dutyCycle = 0;
float _dutyCycleLimit = 1;
float _dutyCycleMin = 0;
float _dutyCycleMax = 1;
float _dutyCycleLimit = 1;
float _dutyCycle = 0;
void _disable();
uint32_t _delay = UINT32_MAX;
Thyristor* _dimmer = nullptr;
};
} // namespace Mycila
14 changes: 7 additions & 7 deletions lib/MycilaRouter/MycilaRouterOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const char* Mycila::RouterOutput::getStateName() const { return StateNames[stati
// output

Mycila::RouterOutput::State Mycila::RouterOutput::getState() const {
if (!_dimmer->isDimmerEnabled() && !_relay->isEnabled())
if (!_dimmer->isEnabled() && !_relay->isEnabled())
return State::OUTPUT_DISABLED;
if (_autoBypassEnabled)
return State::OUTPUT_BYPASS_AUTO;
Expand All @@ -52,7 +52,7 @@ Mycila::RouterOutput::State Mycila::RouterOutput::getState() const {
#ifdef MYCILA_JSON_SUPPORT
void Mycila::RouterOutput::toJson(const JsonObject& root, float gridVoltage) const {
root["bypass"] = isBypassOn() ? "on" : "off";
root["enabled"] = isDimmerEnabled();
root["enabled"] = isEnabled();
root["state"] = getStateName();
root["temperature"] = _temperature.orElse(0);

Expand Down Expand Up @@ -81,7 +81,7 @@ void Mycila::RouterOutput::toJson(const JsonObject& dest, const Metrics& metrics
// dimmer

bool Mycila::RouterOutput::setDimmerDutyCycle(float dutyCycle) {
if (!_dimmer->isDimmerEnabled()) {
if (!_dimmer->isEnabled()) {
LOGW(TAG, "Dimmer '%s' is disabled", _name);
return false;
}
Expand Down Expand Up @@ -127,7 +127,7 @@ void Mycila::RouterOutput::applyTemperatureLimit() {
}

float Mycila::RouterOutput::autoDivert(float gridVoltage, float availablePowerToDivert) {
if (!_dimmer->isDimmerEnabled() || _autoBypassEnabled || !config.autoDimmer || config.calibratedResistance <= 0 || isDimmerTemperatureLimitReached()) {
if (!_dimmer->isEnabled() || _autoBypassEnabled || !config.autoDimmer || config.calibratedResistance <= 0 || isDimmerTemperatureLimitReached()) {
_dimmer->off();
return 0;
}
Expand Down Expand Up @@ -171,7 +171,7 @@ void Mycila::RouterOutput::applyAutoBypass() {

// dimmer & relay checks

if (!_relay->isEnabled() && !_dimmer->isDimmerEnabled()) {
if (!_relay->isEnabled() && !_dimmer->isEnabled()) {
if (_autoBypassEnabled) {
LOGW(TAG, "Relay and dimmer disabled: stopping Auto Bypass '%s'", _name);
_autoBypassEnabled = false;
Expand Down Expand Up @@ -252,7 +252,7 @@ void Mycila::RouterOutput::applyAutoBypass() {
// time and temp OK, let's start
if (!_autoBypassEnabled) {
// auto bypass is not enabled, let's start it
if (!_relay->isEnabled() && !_dimmer->isDimmerEnabled()) {
if (!_relay->isEnabled() && !_dimmer->isEnabled()) {
return;
}
const char* wday = DaysOfWeek[timeInfo.tm_wday];
Expand Down Expand Up @@ -329,7 +329,7 @@ void Mycila::RouterOutput::_setBypass(bool state, bool log) {

} else {
// we don't have a relay: use the dimmer
if (_dimmer->isDimmerEnabled()) {
if (_dimmer->isEnabled()) {
if (log)
LOGD(TAG, "Turning Dimmer '%s' ON", _name);
_dimmer->on();
Expand Down
6 changes: 3 additions & 3 deletions lib/MycilaRouter/MycilaRouterOutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ namespace Mycila {

// dimmer

bool isDimmerEnabled() const { return _dimmer->isDimmerEnabled(); }
bool isAutoDimmerEnabled() const { return _dimmer->isDimmerEnabled() && config.autoDimmer && config.calibratedResistance > 0; }
bool isEnabled() const { return _dimmer->isEnabled(); }
bool isAutoDimmerEnabled() const { return _dimmer->isEnabled() && config.autoDimmer && config.calibratedResistance > 0; }
bool isDimmerTemperatureLimitReached() const { return config.dimmerTempLimit > 0 && _temperature.orElse(0) >= config.dimmerTempLimit; }
bool isDimmerOn() const { return _dimmer->isOn(); }
float getDimmerDutyCycle() const { return _dimmer->getDutyCycle(); }
Expand All @@ -91,7 +91,7 @@ namespace Mycila {

// bypass

bool isBypassEnabled() const { return _relay->isEnabled() || _dimmer->isDimmerEnabled(); }
bool isBypassEnabled() const { return _relay->isEnabled() || _dimmer->isEnabled(); }
bool isAutoBypassEnabled() const { return isBypassEnabled() && config.autoBypass; }
bool isBypassOn() const { return _bypassEnabled; }
bool setBypass(bool state);
Expand Down
6 changes: 3 additions & 3 deletions src/Website.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -907,10 +907,10 @@ void YaSolR::WebsiteClass::updateCards() {

_status(_jsy, KEY_ENABLE_JSY, jsy.isEnabled(), jsy.isConnected(), YASOLR_LBL_110);
_status(_mqtt, KEY_ENABLE_MQTT, mqtt.isEnabled(), mqtt.isConnected(), mqtt.getLastError() ? mqtt.getLastError() : YASOLR_LBL_113);
_status(_output1Dimmer, KEY_ENABLE_OUTPUT1_DIMMER, dimmerO1.isDimmerEnabled(), zcd.isEnabled(), YASOLR_LBL_179);
_status(_output1Dimmer, KEY_ENABLE_OUTPUT1_DIMMER, dimmerO1.isEnabled(), zcd.isEnabled(), YASOLR_LBL_179);
_status(_output1DS18, KEY_ENABLE_OUTPUT1_DS18, ds18O1.isEnabled(), ds18O1.getLastTime() > 0, YASOLR_LBL_114);
_status(_output1PZEM, KEY_ENABLE_OUTPUT1_PZEM, pzemO1.isEnabled(), pzemO1.isConnected() && pzemO1.readAddress() == YASOLR_PZEM_ADDRESS_OUTPUT1, pzemO1.isConnected() ? YASOLR_LBL_180 : YASOLR_LBL_110);
_status(_output2Dimmer, KEY_ENABLE_OUTPUT2_DIMMER, dimmerO2.isDimmerEnabled(), zcd.isEnabled(), YASOLR_LBL_179);
_status(_output2Dimmer, KEY_ENABLE_OUTPUT2_DIMMER, dimmerO2.isEnabled(), zcd.isEnabled(), YASOLR_LBL_179);
_status(_output2DS18, KEY_ENABLE_OUTPUT2_DS18, ds18O2.isEnabled(), ds18O2.getLastTime() > 0, YASOLR_LBL_114);
_status(_output2PZEM, KEY_ENABLE_OUTPUT2_PZEM, pzemO2.isEnabled(), pzemO2.isConnected() && pzemO2.readAddress() == YASOLR_PZEM_ADDRESS_OUTPUT2, pzemO2.isConnected() ? YASOLR_LBL_180 : YASOLR_LBL_110);
_status(_routerDS18, KEY_ENABLE_DS18_SYSTEM, ds18Sys.isEnabled(), ds18Sys.getLastTime() > 0, YASOLR_LBL_114);
Expand Down Expand Up @@ -1108,7 +1108,7 @@ void YaSolR::WebsiteClass::_outputBypassSwitch(Card& card, Mycila::RouterOutput&

void YaSolR::WebsiteClass::_outputDimmerSlider(Card& card, Mycila::RouterOutput& output) {
card.attachCallbackF([&card, &output, this](float value) {
if (output.isDimmerEnabled()) {
if (output.isEnabled()) {
output.setDimmerDutyCycle(value / 100);
}
card.update(output.getDimmerDutyCycle() * 100);
Expand Down
Loading

0 comments on commit ee8dbc6

Please sign in to comment.