diff --git a/docker/MQTTManager/include/entity_manager/entity_manager.cpp b/docker/MQTTManager/include/entity_manager/entity_manager.cpp index 983a442c..0784a17f 100644 --- a/docker/MQTTManager/include/entity_manager/entity_manager.cpp +++ b/docker/MQTTManager/include/entity_manager/entity_manager.cpp @@ -783,7 +783,12 @@ void EntityManager::_command_callback(NSPanelMQTTManagerCommand &command) { SPDLOG_ERROR("Received command to toggle light entity in slot {} in page with ID {} but entity could not be cast to a light.", command.toggle_entity_from_entities_page().entity_slot(), command.toggle_entity_from_entities_page().entity_page_id()); } } else { - (*entity)->toggle(); + auto scene = std::dynamic_pointer_cast(*entity); + if (scene) { + scene->activate(EntityManager::get_room_id_for_panel_id(command.nspanel_id())); + } else { + (*entity)->toggle(); + } } } else { SPDLOG_DEBUG("Received command to toggle entity in slot {} in page with ID {} bot did not find such an entity.", command.toggle_entity_from_entities_page().entity_slot(), command.toggle_entity_from_entities_page().entity_page_id()); @@ -893,6 +898,14 @@ std::expected, EntityManager::EntityError> EntityManage return std::unexpected(EntityManager::EntityError::NOT_FOUND); } +std::expected EntityManager::get_room_id_for_panel_id(uint32_t nspanel_id) { + auto nspanel = EntityManager::get_nspanel_by_id(nspanel_id); + if (nspanel.has_value()) { + return (*nspanel)->get_default_room_id(); + } + return std::unexpected(EntityManager::EntityError::NOT_FOUND); +} + std::expected, EntityManager::EntityError> EntityManager::get_nspanel_by_mac(std::string mac) { SPDLOG_TRACE("Trying to find NSPanel by MAC {}", mac); std::lock_guard mutex_guard(EntityManager::_nspanels_mutex); diff --git a/docker/MQTTManager/include/entity_manager/entity_manager.hpp b/docker/MQTTManager/include/entity_manager/entity_manager.hpp index 6153c2aa..19dbf67b 100644 --- a/docker/MQTTManager/include/entity_manager/entity_manager.hpp +++ b/docker/MQTTManager/include/entity_manager/entity_manager.hpp @@ -206,6 +206,7 @@ class EntityManager { static std::expected, EntityError> get_nspanel_by_id(uint id); static std::expected, EntityError> get_nspanel_by_mac(std::string mac); + static std::expected get_room_id_for_panel_id(uint32_t nspanel_id); private: static inline std::vector> _entities; diff --git a/docker/MQTTManager/include/nspanel/nspanel.cpp b/docker/MQTTManager/include/nspanel/nspanel.cpp index 8a3b0f81..22b5727e 100644 --- a/docker/MQTTManager/include/nspanel/nspanel.cpp +++ b/docker/MQTTManager/include/nspanel/nspanel.cpp @@ -1,4 +1,5 @@ #include "nspanel.hpp" +#include #include "database_manager/database_manager.hpp" #include "entity_manager/entity_manager.hpp" #include "mqtt_manager/mqtt_manager.hpp" @@ -1401,7 +1402,12 @@ void NSPanel::command_callback(NSPanelMQTTManagerCommand &command) { auto entity = EntityManager::get_entity_by_id(MQTT_MANAGER_ENTITY_TYPE::ANY, this->_settings.button1_detached_mode_entity_id.value()); if (entity) { if ((*entity)->can_toggle()) { - (*entity)->toggle(); + auto scene = std::dynamic_pointer_cast(*entity); + if (scene) { + scene->activate(this->get_default_room_id()); + } else { + (*entity)->toggle(); + } } } else SPDLOG_ERROR("Tried to toggle detached entity via panel but no entity was found with configured ID '{}'.", this->_settings.button1_detached_mode_entity_id.value()); @@ -1430,7 +1436,12 @@ void NSPanel::command_callback(NSPanelMQTTManagerCommand &command) { auto entity = EntityManager::get_entity_by_id(MQTT_MANAGER_ENTITY_TYPE::ANY, this->_settings.button2_detached_mode_entity_id.value()); if (entity) { if ((*entity)->can_toggle()) { - (*entity)->toggle(); + auto scene = std::dynamic_pointer_cast(*entity); + if (scene) { + scene->activate(this->get_default_room_id()); + } else { + (*entity)->toggle(); + } } } else SPDLOG_ERROR("Tried to toggle detached entity via panel but no entity was found with configured ID '{}'.", this->_settings.button2_detached_mode_entity_id.value()); diff --git a/docker/MQTTManager/include/scenes/home_assistant_scene.cpp b/docker/MQTTManager/include/scenes/home_assistant_scene.cpp index e3443259..82cc3c8e 100644 --- a/docker/MQTTManager/include/scenes/home_assistant_scene.cpp +++ b/docker/MQTTManager/include/scenes/home_assistant_scene.cpp @@ -36,8 +36,9 @@ void HomeAssistantScene::reload_config() { } } -void HomeAssistantScene::activate() { +void HomeAssistantScene::activate(std::expected triggering_room_id) { SPDLOG_INFO("Activating scene {}::{}.", this->_id, this->_name); + if (this->_entity_id.starts_with("scene.")) { nlohmann::json service_data; service_data["type"] = "call_service"; @@ -50,11 +51,23 @@ void HomeAssistantScene::activate() { nlohmann::json context; context["scene_name"] = this->_name; context["scene_id"] = this->_id; - auto room = EntityManager::get_room(this->_room_id); - if (!this->_is_global && room.has_value()) { - context["room_name"] = (*room)->get_name(); - context["room_id"] = this->_room_id; + + if (triggering_room_id.has_value()) { + auto triggering_room = EntityManager::get_room(*triggering_room_id); + if (triggering_room.has_value()) { + context["triggering_room_id"] = *triggering_room_id; + context["triggering_room_name"] = (*triggering_room)->get_name(); + } } + + if (!this->_is_global) { + auto scene_room = EntityManager::get_room(this->_room_id); + if (scene_room.has_value()) { + context["scene_room_id"] = this->_room_id; + context["scene_room_name"] = (*scene_room)->get_name(); + } + } + service_data["service_data"]["variables"]["nspanelmanager"] = context; SPDLOG_DEBUG("Sending script with context: {}", context.dump()); service_data["type"] = "call_service"; diff --git a/docker/MQTTManager/include/scenes/home_assistant_scene.hpp b/docker/MQTTManager/include/scenes/home_assistant_scene.hpp index e2acc260..5c301370 100644 --- a/docker/MQTTManager/include/scenes/home_assistant_scene.hpp +++ b/docker/MQTTManager/include/scenes/home_assistant_scene.hpp @@ -7,7 +7,7 @@ class HomeAssistantScene : public Scene { public: HomeAssistantScene(uint32_t id); void reload_config(); - void activate(); + void activate(std::expected triggering_room_id = std::unexpected(EntityManager::EntityError::NOT_FOUND)); void save(); void remove(); uint16_t get_id(); diff --git a/docker/MQTTManager/include/scenes/nspm_scene.cpp b/docker/MQTTManager/include/scenes/nspm_scene.cpp index 6019280e..e0e5bab4 100644 --- a/docker/MQTTManager/include/scenes/nspm_scene.cpp +++ b/docker/MQTTManager/include/scenes/nspm_scene.cpp @@ -47,7 +47,7 @@ void NSPMScene::reload_config() { } } -void NSPMScene::activate() { +void NSPMScene::activate(std::expected triggering_room_id) { SPDLOG_INFO("Activating scene {}::{}.", this->_id, this->_name); try { auto light_states = database_manager::database.get_all(sqlite_orm::where(sqlite_orm::c(&database_manager::SceneLightState::scene_id) == this->_id)); diff --git a/docker/MQTTManager/include/scenes/nspm_scene.hpp b/docker/MQTTManager/include/scenes/nspm_scene.hpp index 58f1ba48..0bbd2cc9 100644 --- a/docker/MQTTManager/include/scenes/nspm_scene.hpp +++ b/docker/MQTTManager/include/scenes/nspm_scene.hpp @@ -15,7 +15,7 @@ class NSPMScene : public Scene { ~NSPMScene(); void reload_config(); - void activate(); + void activate(std::expected triggering_room_id = std::unexpected(EntityManager::EntityError::NOT_FOUND)); void save(); void remove(); uint16_t get_id(); diff --git a/docker/MQTTManager/include/scenes/openhab_scene.cpp b/docker/MQTTManager/include/scenes/openhab_scene.cpp index a039d8c6..bc7e5e76 100644 --- a/docker/MQTTManager/include/scenes/openhab_scene.cpp +++ b/docker/MQTTManager/include/scenes/openhab_scene.cpp @@ -36,7 +36,7 @@ void OpenhabScene::reload_config() { } } -void OpenhabScene::activate() { +void OpenhabScene::activate(std::expected triggering_room_id) { SPDLOG_INFO("Activating scene {}::{}.", this->_id, this->_name); std::string openhab_trigger_scene_url = fmt::format("{}/rest/rules/{}/runnow", MqttManagerConfig::get_setting_with_default(MQTT_MANAGER_SETTING::OPENHAB_ADDRESS), this->_entity_id); diff --git a/docker/MQTTManager/include/scenes/openhab_scene.hpp b/docker/MQTTManager/include/scenes/openhab_scene.hpp index 93282c56..ba47893e 100644 --- a/docker/MQTTManager/include/scenes/openhab_scene.hpp +++ b/docker/MQTTManager/include/scenes/openhab_scene.hpp @@ -8,7 +8,7 @@ class OpenhabScene : public Scene { public: OpenhabScene(uint32_t id); void reload_config(); - void activate(); + void activate(std::expected triggering_room_id = std::unexpected(EntityManager::EntityError::NOT_FOUND)); void save(); void remove(); uint16_t get_id(); diff --git a/docker/MQTTManager/include/scenes/scene.cpp b/docker/MQTTManager/include/scenes/scene.cpp index 573b8c69..4ef9e3ad 100644 --- a/docker/MQTTManager/include/scenes/scene.cpp +++ b/docker/MQTTManager/include/scenes/scene.cpp @@ -15,7 +15,9 @@ bool Scene::can_toggle() { } void Scene::toggle() { - this->activate(); + // Satisfies MqttManagerEntity's pure virtual. In practice all scene activations go through + // activate(triggering_room_id) directly, so this path should never be reached. + this->activate(std::unexpected(EntityManager::EntityError::NOT_FOUND)); } bool Scene::is_global() { diff --git a/docker/MQTTManager/include/scenes/scene.hpp b/docker/MQTTManager/include/scenes/scene.hpp index aee11bd9..b917f9a5 100644 --- a/docker/MQTTManager/include/scenes/scene.hpp +++ b/docker/MQTTManager/include/scenes/scene.hpp @@ -1,10 +1,12 @@ #ifndef MQTT_MANAGER_SCENE_BASE_H #define MQTT_MANAGER_SCENE_BASE_H #include "entity/entity.hpp" +#include "entity_manager/entity_manager.hpp" +#include class Scene : public MqttManagerEntity { public: - virtual void activate() = 0; + virtual void activate(std::expected triggering_room_id = std::unexpected(EntityManager::EntityError::NOT_FOUND)) = 0; virtual void save() = 0; virtual void remove() = 0; virtual void reload_config() = 0; @@ -17,7 +19,7 @@ class Scene : public MqttManagerEntity { bool is_global(); // The same as activate() - void toggle(); + void toggle() override; virtual std::string get_name() = 0; virtual bool can_save() = 0;