Skip to content

Commit

Permalink
automation: Add WEM2 outputs as automation trigger
Browse files Browse the repository at this point in the history
Implements issue #393
  • Loading branch information
borg42 committed Feb 14, 2025
1 parent c1aec6f commit 0f8823f
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ PM Power Available
PM Grid Power Draw
HTTP
EM Input
Day Ahead Price Now
Day Ahead Price Now
EM Relay Switch
EM SG Ready Switch
62 changes: 60 additions & 2 deletions software/src/modules/em_v2/em_v2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,22 @@ void EMV2::pre_setup()
})
);

automation.register_trigger(
AutomationTriggerID::EMRelaySwitch,
Config::Object({
{"index", Config::Uint(0, 0, 1)},
{"closed", Config::Bool(false)},
})
);

automation.register_trigger(
AutomationTriggerID::EMSGReadySwitch,
Config::Object({
{"index", Config::Uint(0, 0, 1)},
{"closed", Config::Bool(false)},
})
);

automation.register_action(
AutomationActionID::EMRelaySwitch,
Config::Object({
Expand Down Expand Up @@ -171,6 +187,14 @@ void EMV2::setup()
uint32_t index = i;
automation.trigger(AutomationTriggerID::EMInput, &index, this);
}
for (size_t i = 0; i < ARRAY_SIZE(this->all_data.output_relay); i++) {
uint32_t index = i;
automation.trigger(AutomationTriggerID::EMRelaySwitch, &index, this);
}
for (size_t i = 0; i < ARRAY_SIZE(this->all_data.output_sg_ready); i++) {
uint32_t index = i;
automation.trigger(AutomationTriggerID::EMSGReadySwitch, &index, this);
}
});
#endif
}
Expand Down Expand Up @@ -395,6 +419,34 @@ bool EMV2::has_triggered(const Config *conf, void *data)
return is_closed == want_closed;
}

case AutomationTriggerID::EMRelaySwitch: {
const uint32_t triggered_index = *static_cast<uint32_t *>(data);
const Config *cfg = static_cast<const Config *>(conf->get());
const uint32_t cfg_index = cfg->get("index")->asUint();

if (triggered_index != cfg_index) {
return false;
}

const bool is_closed = this->all_data.output_relay[triggered_index];
const bool want_closed = cfg->get("closed")->asBool();
return is_closed == want_closed;
}

case AutomationTriggerID::EMSGReadySwitch: {
const uint32_t triggered_index = *static_cast<uint32_t *>(data);
const Config *cfg = static_cast<const Config *>(conf->get());
const uint32_t cfg_index = cfg->get("index")->asUint();

if (triggered_index != cfg_index) {
return false;
}

const bool is_closed = this->all_data.output_sg_ready[triggered_index];
const bool want_closed = cfg->get("closed")->asBool();
return is_closed == want_closed;
}

default:
break;
}
Expand Down Expand Up @@ -436,12 +488,18 @@ void EMV2::update_all_data()

Config *state_sg_ready = static_cast<Config *>(em_common.state.get("sg_ready_outputs"));
for (size_t i = 0; i < ARRAY_SIZE(all_data.output_sg_ready); i++) {
state_sg_ready->get(i)->updateBool(all_data.output_sg_ready[i]);
if(state_sg_ready->get(i)->updateBool(all_data.output_sg_ready[i])) {
uint32_t index = i;
AUTOMATION_TRIGGER(EMSGReadySwitch, &index);
}
}

Config *state_relays = static_cast<Config *>(em_common.state.get("relays"));
for (size_t i = 0; i < ARRAY_SIZE(all_data.output_relay); i++) {
state_relays->get(i)->updateBool(all_data.output_relay[i]);
if(state_relays->get(i)->updateBool(all_data.output_relay[i])) {
uint32_t index = i;
AUTOMATION_TRIGGER(EMRelaySwitch, &index);
}
}

#if MODULE_METERS_EM_AVAILABLE()
Expand Down
110 changes: 110 additions & 0 deletions software/web/src/modules/em_v2/plugin_automation_trigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,33 @@ export type EMInputAutomationTrigger = [
closed: boolean;
},
];
export type EMRelaySwitchAutomationTrigger = [
AutomationTriggerID.EMRelaySwitch,
{
index: number;
closed: boolean;
},
];
export type EMSGReadySwitchAutomationTrigger = [
AutomationTriggerID.EMSGReadySwitch,
{
index: number;
closed: boolean;
},
];

function get_em_input_table_children(trigger: EMInputAutomationTrigger) {
return __("energy_manager.automation.automation_input_text")(trigger[1].index + 1, trigger[1].closed);
}

function get_em_relay_switch_table_children(trigger: EMRelaySwitchAutomationTrigger) {
return __("em_v2.automation.automation_relay_text")(trigger[1].index + 1, trigger[1].closed);
}

function get_em_sg_ready_switch_table_children(trigger: EMSGReadySwitchAutomationTrigger) {
return __("em_v2.automation.automation_sgready_text")(trigger[1].index + 1, trigger[1].closed);
}

function get_em_input_edit_children(trigger: EMInputAutomationTrigger, on_trigger: (trigger: AutomationTrigger) => void) {
return [
<FormRow label={__("em_v2.automation.input_index")}>
Expand Down Expand Up @@ -66,6 +88,60 @@ function get_em_input_edit_children(trigger: EMInputAutomationTrigger, on_trigge
];
}

function get_em_relay_switch_edit_children(trigger: EMRelaySwitchAutomationTrigger, on_trigger: (trigger: AutomationTrigger) => void) {
return [
<FormRow label={__("em_v2.automation.relay_index")}>
<InputNumber
required
min={1}
max={2}
value={trigger[1].index + 1}
onValue={(v) => {on_trigger(util.get_updated_union(trigger, {index: v - 1}));}}
/>
</FormRow>,

<FormRow label={__("energy_manager.automation.state")}>
<InputSelect
value={trigger[1].closed ? '1' : '0'}
items = {[
['0', __("energy_manager.automation.open")],
['1', __("energy_manager.automation.closed")],
]}
onValue={(v) => {
on_trigger(util.get_updated_union(trigger, {closed: v === '1'}));
}}
/>
</FormRow>,
];
}

function get_em_sg_ready_switch_edit_children(trigger: EMSGReadySwitchAutomationTrigger, on_trigger: (trigger: AutomationTrigger) => void) {
return [
<FormRow label={__("em_v2.automation.sgready_index")}>
<InputNumber
required
min={1}
max={2}
value={trigger[1].index + 1}
onValue={(v) => {on_trigger(util.get_updated_union(trigger, {index: v - 1}));}}
/>
</FormRow>,

<FormRow label={__("energy_manager.automation.state")}>
<InputSelect
value={trigger[1].closed ? '1' : '0'}
items = {[
['0', __("energy_manager.automation.open")],
['1', __("energy_manager.automation.closed")],
]}
onValue={(v) => {
on_trigger(util.get_updated_union(trigger, {closed: v === '1'}));
}}
/>
</FormRow>,
];
}

function new_em_input_config(): AutomationTrigger {
return [
AutomationTriggerID.EMInput,
Expand All @@ -76,6 +152,26 @@ function new_em_input_config(): AutomationTrigger {
];
}

function new_em_relay_switch_config(): AutomationTrigger {
return [
AutomationTriggerID.EMRelaySwitch,
{
index: 0,
closed: true,
},
];
}

function new_em_sg_ready_switch_config(): AutomationTrigger {
return [
AutomationTriggerID.EMSGReadySwitch,
{
index: 0,
closed: true,
},
];
}

export function init(): InitResult {
return {
trigger_components: {
Expand All @@ -86,6 +182,20 @@ export function init(): InitResult {
get_table_children: get_em_input_table_children,
get_edit_children: get_em_input_edit_children,
},
[AutomationTriggerID.EMRelaySwitch]: {
translation_name: () => __("em_v2.automation.relay_switches"),
new_config: new_em_relay_switch_config,
clone_config: (trigger: AutomationTrigger) => [trigger[0], {...trigger[1]}] as AutomationTrigger,
get_table_children: get_em_relay_switch_table_children,
get_edit_children: get_em_relay_switch_edit_children,
},
[AutomationTriggerID.EMSGReadySwitch]: {
translation_name: () => __("em_v2.automation.sgready_switches"),
new_config: new_em_sg_ready_switch_config,
clone_config: (trigger: AutomationTrigger) => [trigger[0], {...trigger[1]}] as AutomationTrigger,
get_table_children: get_em_sg_ready_switch_table_children,
get_edit_children: get_em_sg_ready_switch_edit_children,
},
},
};
}
11 changes: 11 additions & 0 deletions software/web/src/modules/em_v2/translation_de.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ let x = {
"input_switches": "Eingang geschaltet",
"input_index": "Eingangsnummer",

"relay_switches": "Relais-Ausgang geschaltet",
"relay_index": "Relais-Ausgang",

"sgready_switch": "Schalte SG-Ready-Ausgang",
"sgready_switches": "SG-Ready-Ausgang geschaltet",
"sgready_index": "SG-Ready-Ausgang",
"sgready_action_text": /*FFN*/(index: number, state: boolean) => {
let ret = state ? <><b>schließen</b></> : <><b>öffnen</b></>
return <>SG-Ready-Ausgang {index+1} {ret}.</>
}/*NF*/,

"automation_relay_text": /*FFN*/(input: number, state: boolean) => {
return <>Wenn <b>Relais-Ausgang {input}</b> {state ? <b>geschlossen</b> : <b>geöffnet</b>} wird, </>
}/*NF*/,
"automation_sgready_text": /*FFN*/(input: number, state: boolean) => {
return <>Wenn <b>SG-Ready-Ausgang {input}</b> {state ? <b>geschlossen</b> : <b>geöffnet</b>} wird, </>
}/*NF*/
}
}
Expand Down
11 changes: 11 additions & 0 deletions software/web/src/modules/em_v2/translation_en.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ let x = {
"input_switches": "Input switched",
"input_index": "Input number",

"relay_switches": "Relay output switched",
"relay_index": "Relay output",

"sgready_switch": "Switch SG Ready output",
"sgready_switches": "SG Ready output switched",
"sgready_index": "SG Ready output",
"sgready_action_text": /*FFN*/(index: number, state: boolean) => {
let ret = state ? <><b>close</b></> : <><b>open</b></>
return <>{ret} SG Ready output {index+1}.</>
}/*NF*/,

"automation_relay_text": /*FFN*/(input: number, state: boolean) => {
return <>If <b>relay output {input}</b> switches to state {state ? <><b>closed</b></> : <><b>open</b></>}, </>
}/*NF*/,
"automation_sgready_text": /*FFN*/(input: number, state: boolean) => {
return <>If <b>SG Ready output {input}</b> switches to state {state ? <><b>closed</b></> : <><b>open</b></>}, </>
}/*NF*/
}
}
Expand Down

0 comments on commit 0f8823f

Please sign in to comment.