Add support for push notifications
This commit is contained in:
parent
8d186ba5e5
commit
2e6a4f218c
@ -63,6 +63,7 @@ AirConditioningJsonHandler::AirConditioningJsonHandler(AirConditioningManager *m
|
|||||||
params.insert("o:windowSensors", QVariantList() << enumValueName(Uuid));
|
params.insert("o:windowSensors", QVariantList() << enumValueName(Uuid));
|
||||||
params.insert("o:indoorSensors", QVariantList() << enumValueName(Uuid));
|
params.insert("o:indoorSensors", QVariantList() << enumValueName(Uuid));
|
||||||
params.insert("o:outdoorSensors", QVariantList() << enumValueName(Uuid));
|
params.insert("o:outdoorSensors", QVariantList() << enumValueName(Uuid));
|
||||||
|
params.insert("o:notifications", QVariantList() << enumValueName(Uuid));
|
||||||
returns.insert("airConditioningError", enumRef<AirConditioningManager::AirConditioningError>());
|
returns.insert("airConditioningError", enumRef<AirConditioningManager::AirConditioningError>());
|
||||||
returns.insert("o:zone", objectRef<ZoneInfo>());
|
returns.insert("o:zone", objectRef<ZoneInfo>());
|
||||||
registerMethod("AddZone", description, params, returns);
|
registerMethod("AddZone", description, params, returns);
|
||||||
@ -106,10 +107,11 @@ AirConditioningJsonHandler::AirConditioningJsonHandler(AirConditioningManager *m
|
|||||||
params.clear(); returns.clear();
|
params.clear(); returns.clear();
|
||||||
description = "Set Zone things";
|
description = "Set Zone things";
|
||||||
params.insert("zoneId", enumValueName(Uuid));
|
params.insert("zoneId", enumValueName(Uuid));
|
||||||
params.insert("thermostats", QVariantList() << enumValueName(Uuid));
|
params.insert("o:thermostats", QVariantList() << enumValueName(Uuid));
|
||||||
params.insert("windowSensors", QVariantList() << enumValueName(Uuid));
|
params.insert("o:windowSensors", QVariantList() << enumValueName(Uuid));
|
||||||
params.insert("indoorSensors", QVariantList() << enumValueName(Uuid));
|
params.insert("o:indoorSensors", QVariantList() << enumValueName(Uuid));
|
||||||
params.insert("outdoorSensors", QVariantList() << enumValueName(Uuid));
|
params.insert("o:outdoorSensors", QVariantList() << enumValueName(Uuid));
|
||||||
|
params.insert("o:notifications", QVariantList() << enumValueName(Uuid));
|
||||||
returns.insert("airConditioningError", enumRef<AirConditioningManager::AirConditioningError>());
|
returns.insert("airConditioningError", enumRef<AirConditioningManager::AirConditioningError>());
|
||||||
registerMethod("SetZoneThings", description, params, returns);
|
registerMethod("SetZoneThings", description, params, returns);
|
||||||
|
|
||||||
@ -161,7 +163,7 @@ JsonReply *AirConditioningJsonHandler::GetZones(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
JsonReply *AirConditioningJsonHandler::AddZone(const QVariantMap ¶ms)
|
JsonReply *AirConditioningJsonHandler::AddZone(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
QList<ThingId> thermostats, windowSensors, indoorSensors, outdoorSensors;
|
QList<ThingId> thermostats, windowSensors, indoorSensors, outdoorSensors, notifications;
|
||||||
foreach (const QVariant &id, params.value("thermostats").toList()) {
|
foreach (const QVariant &id, params.value("thermostats").toList()) {
|
||||||
thermostats.append(id.toUuid());
|
thermostats.append(id.toUuid());
|
||||||
}
|
}
|
||||||
@ -174,7 +176,10 @@ JsonReply *AirConditioningJsonHandler::AddZone(const QVariantMap ¶ms)
|
|||||||
foreach (const QVariant &id, params.value("outdoorSensors").toList()) {
|
foreach (const QVariant &id, params.value("outdoorSensors").toList()) {
|
||||||
outdoorSensors.append(id.toUuid());
|
outdoorSensors.append(id.toUuid());
|
||||||
}
|
}
|
||||||
QPair<AirConditioningManager::AirConditioningError, ZoneInfo> status = m_manager->addZone(params.value("name").toString(), thermostats, windowSensors, indoorSensors, outdoorSensors);
|
foreach (const QVariant &id, params.value("notificatiosn").toList()) {
|
||||||
|
notifications.append(id.toUuid());
|
||||||
|
}
|
||||||
|
QPair<AirConditioningManager::AirConditioningError, ZoneInfo> status = m_manager->addZone(params.value("name").toString(), thermostats, windowSensors, indoorSensors, outdoorSensors, notifications);
|
||||||
QVariantMap ret = {
|
QVariantMap ret = {
|
||||||
{"airConditioningError", enumValueName(status.first)}
|
{"airConditioningError", enumValueName(status.first)}
|
||||||
};
|
};
|
||||||
@ -230,19 +235,50 @@ JsonReply *AirConditioningJsonHandler::SetZoneWeekSchedule(const QVariantMap &pa
|
|||||||
JsonReply *AirConditioningJsonHandler::SetZoneThings(const QVariantMap ¶ms)
|
JsonReply *AirConditioningJsonHandler::SetZoneThings(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
QUuid zoneId = params.value("zoneId").toUuid();
|
QUuid zoneId = params.value("zoneId").toUuid();
|
||||||
QList<ThingId> thermostats, windowSensors, indoorSensors, outdoorSensors;
|
|
||||||
|
ZoneInfo zone = m_manager->zone(zoneId);
|
||||||
|
|
||||||
|
QList<ThingId> thermostats, windowSensors, indoorSensors, outdoorSensors, notifications;
|
||||||
|
if (params.contains("thermostats")) {
|
||||||
foreach (const QVariant &variant, params.value("thermostats").toList()) {
|
foreach (const QVariant &variant, params.value("thermostats").toList()) {
|
||||||
thermostats.append(ThingId(variant.toUuid()));
|
thermostats.append(ThingId(variant.toUuid()));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
thermostats = zone.thermostats();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.contains("windowSensors")) {
|
||||||
foreach (const QVariant &variant, params.value("windowSensors").toList()) {
|
foreach (const QVariant &variant, params.value("windowSensors").toList()) {
|
||||||
windowSensors.append(ThingId(variant.toUuid()));
|
windowSensors.append(ThingId(variant.toUuid()));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
windowSensors = zone.windowSensors();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.contains("indoorSensors")) {
|
||||||
foreach (const QVariant &variant, params.value("indoorSensors").toList()) {
|
foreach (const QVariant &variant, params.value("indoorSensors").toList()) {
|
||||||
indoorSensors.append(ThingId(variant.toUuid()));
|
indoorSensors.append(ThingId(variant.toUuid()));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
indoorSensors = zone.indoorSensors();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.contains("outdoorSensors")) {
|
||||||
foreach (const QVariant &variant, params.value("outdoorSensors").toList()) {
|
foreach (const QVariant &variant, params.value("outdoorSensors").toList()) {
|
||||||
outdoorSensors.append(ThingId(variant.toUuid()));
|
outdoorSensors.append(ThingId(variant.toUuid()));
|
||||||
}
|
}
|
||||||
AirConditioningManager::AirConditioningError status = m_manager->setZoneThings(zoneId, thermostats, windowSensors, indoorSensors, outdoorSensors);
|
} else {
|
||||||
|
outdoorSensors = zone.outdoorSensors();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.contains("notifications")) {
|
||||||
|
foreach (const QVariant &variant, params.value("notifications").toList()) {
|
||||||
|
notifications.append(ThingId(variant.toUuid()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notifications = zone.notifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
AirConditioningManager::AirConditioningError status = m_manager->setZoneThings(zoneId, thermostats, windowSensors, indoorSensors, outdoorSensors, notifications);
|
||||||
return createReply({{"airConditioningError", enumValueName(status)}});
|
return createReply({{"airConditioningError", enumValueName(status)}});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,9 @@ AirConditioningManager::AirConditioningManager(ThingManager *thingManager, QObje
|
|||||||
if (thing->thingClass().interfaces().contains("thermostat")) {
|
if (thing->thingClass().interfaces().contains("thermostat")) {
|
||||||
m_thermostats.insert(thing->id(), new Thermostat(m_thingManager, thing, this));
|
m_thermostats.insert(thing->id(), new Thermostat(m_thingManager, thing, this));
|
||||||
}
|
}
|
||||||
|
if (thing->thingClass().interfaces().contains("notifications")) {
|
||||||
|
m_notifications.insert(thing->id(), new Notifications(m_thingManager, thing, this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadZones();
|
loadZones();
|
||||||
@ -71,17 +74,17 @@ ZoneInfos AirConditioningManager::zones() const
|
|||||||
return m_zones.values();
|
return m_zones.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneInfo AirConditioningManager::zone(const ThingId &thermostatId)
|
ZoneInfo AirConditioningManager::zone(const QUuid &zoneId)
|
||||||
{
|
{
|
||||||
return m_zones.value(thermostatId);
|
return m_zones.value(zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<AirConditioningManager::AirConditioningError, ZoneInfo> AirConditioningManager::addZone(const QString &name, const QList<ThingId> &thermostats, const QList<ThingId> windowSensors, const QList<ThingId> indoorSensors, const QList<ThingId> outdoorSensors)
|
QPair<AirConditioningManager::AirConditioningError, ZoneInfo> AirConditioningManager::addZone(const QString &name, const QList<ThingId> &thermostats, const QList<ThingId> windowSensors, const QList<ThingId> indoorSensors, const QList<ThingId> outdoorSensors, const QList<ThingId> notifications)
|
||||||
{
|
{
|
||||||
ZoneInfo zone(QUuid::createUuid());
|
ZoneInfo zone(QUuid::createUuid());
|
||||||
zone.setName(name);
|
zone.setName(name);
|
||||||
zone.setWeekSchedule(TemperatureWeekSchedule::create());
|
zone.setWeekSchedule(TemperatureWeekSchedule::create());
|
||||||
AirConditioningError status = verifyThingIds(thermostats, windowSensors, indoorSensors, outdoorSensors);
|
AirConditioningError status = verifyThingIds(thermostats, windowSensors, indoorSensors, outdoorSensors, notifications);
|
||||||
if (status != AirConditioningErrorNoError) {
|
if (status != AirConditioningErrorNoError) {
|
||||||
qCWarning(dcAirConditioning()) << "Invalid thing id" << status << "in" << thermostats;
|
qCWarning(dcAirConditioning()) << "Invalid thing id" << status << "in" << thermostats;
|
||||||
return qMakePair<AirConditioningError, ZoneInfo>(status, ZoneInfo());
|
return qMakePair<AirConditioningError, ZoneInfo>(status, ZoneInfo());
|
||||||
@ -91,6 +94,7 @@ QPair<AirConditioningManager::AirConditioningError, ZoneInfo> AirConditioningMan
|
|||||||
zone.setWindowSensors(windowSensors);
|
zone.setWindowSensors(windowSensors);
|
||||||
zone.setIndoorSensors(indoorSensors);
|
zone.setIndoorSensors(indoorSensors);
|
||||||
zone.setOutdoorSensors(outdoorSensors);
|
zone.setOutdoorSensors(outdoorSensors);
|
||||||
|
zone.setNotifications(notifications);
|
||||||
|
|
||||||
m_zones.insert(zone.id(), zone);
|
m_zones.insert(zone.id(), zone);
|
||||||
saveZones();
|
saveZones();
|
||||||
@ -179,12 +183,12 @@ AirConditioningManager::AirConditioningError AirConditioningManager::setZoneWeek
|
|||||||
return AirConditioningErrorNoError;
|
return AirConditioningErrorNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
AirConditioningManager::AirConditioningError AirConditioningManager::setZoneThings(const QUuid &zoneId, const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors)
|
AirConditioningManager::AirConditioningError AirConditioningManager::setZoneThings(const QUuid &zoneId, const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors, const QList<ThingId> ¬ifications)
|
||||||
{
|
{
|
||||||
if (!m_zones.contains(zoneId)) {
|
if (!m_zones.contains(zoneId)) {
|
||||||
return AirConditioningErrorZoneNotFound;
|
return AirConditioningErrorZoneNotFound;
|
||||||
}
|
}
|
||||||
AirConditioningError status = verifyThingIds(thermostats, windowSensors, indoorSensors, outdoorSensors);
|
AirConditioningError status = verifyThingIds(thermostats, windowSensors, indoorSensors, outdoorSensors, notifications);
|
||||||
if (status != AirConditioningErrorNoError) {
|
if (status != AirConditioningErrorNoError) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -192,8 +196,9 @@ AirConditioningManager::AirConditioningError AirConditioningManager::setZoneThin
|
|||||||
m_zones[zoneId].setWindowSensors(windowSensors);
|
m_zones[zoneId].setWindowSensors(windowSensors);
|
||||||
m_zones[zoneId].setIndoorSensors(indoorSensors);
|
m_zones[zoneId].setIndoorSensors(indoorSensors);
|
||||||
m_zones[zoneId].setOutdoorSensors(outdoorSensors);
|
m_zones[zoneId].setOutdoorSensors(outdoorSensors);
|
||||||
|
m_zones[zoneId].setNotifications(notifications);
|
||||||
saveZones();
|
saveZones();
|
||||||
qCDebug(dcAirConditioning()) << "Zone things set. Thermostats:" << thermostats << "Window sensors:" << windowSensors << "indoor sensors:" << indoorSensors << "outdoor sensors:" << outdoorSensors;
|
qCDebug(dcAirConditioning()) << "Zone things set. Thermostats:" << thermostats << "Window sensors:" << windowSensors << "indoor sensors:" << indoorSensors << "outdoor sensors:" << outdoorSensors << "notifications:" << notifications;
|
||||||
emit zoneChanged(m_zones.value(zoneId));
|
emit zoneChanged(m_zones.value(zoneId));
|
||||||
updateZone(zoneId);
|
updateZone(zoneId);
|
||||||
return AirConditioningErrorNoError;
|
return AirConditioningErrorNoError;
|
||||||
@ -219,6 +224,10 @@ void AirConditioningManager::onThingAdded(Thing *thing)
|
|||||||
qCInfo(dcAirConditioning()) << "Thermostat added:" << thing;
|
qCInfo(dcAirConditioning()) << "Thermostat added:" << thing;
|
||||||
m_thermostats.insert(thing->id(), new Thermostat(m_thingManager, thing, this));
|
m_thermostats.insert(thing->id(), new Thermostat(m_thingManager, thing, this));
|
||||||
}
|
}
|
||||||
|
if (thing->thingClass().interfaces().contains("notifications")) {
|
||||||
|
qCInfo(dcAirConditioning()) << "Notifications added:" << thing;
|
||||||
|
m_notifications.insert(thing->id(), new Notifications(m_thingManager, thing, this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AirConditioningManager::onThingRemoved(const ThingId &thingId)
|
void AirConditioningManager::onThingRemoved(const ThingId &thingId)
|
||||||
@ -228,6 +237,7 @@ void AirConditioningManager::onThingRemoved(const ThingId &thingId)
|
|||||||
QList<ThingId> windowSensors = m_zones.value(zone.id()).windowSensors();
|
QList<ThingId> windowSensors = m_zones.value(zone.id()).windowSensors();
|
||||||
QList<ThingId> indoorSensors = m_zones.value(zone.id()).indoorSensors();
|
QList<ThingId> indoorSensors = m_zones.value(zone.id()).indoorSensors();
|
||||||
QList<ThingId> outdoorSensors = m_zones.value(zone.id()).outdoorSensors();
|
QList<ThingId> outdoorSensors = m_zones.value(zone.id()).outdoorSensors();
|
||||||
|
QList<ThingId> notifications = m_zones.value(zone.id()).notifications();
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (thermostats.contains(thingId)) {
|
if (thermostats.contains(thingId)) {
|
||||||
thermostats.removeAll(thingId);
|
thermostats.removeAll(thingId);
|
||||||
@ -245,28 +255,37 @@ void AirConditioningManager::onThingRemoved(const ThingId &thingId)
|
|||||||
outdoorSensors.removeAll(thingId);
|
outdoorSensors.removeAll(thingId);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
if (notifications.contains(thingId)) {
|
||||||
|
notifications.removeAll(thingId);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
setZoneThings(zone.id(), thermostats, windowSensors, indoorSensors, outdoorSensors);
|
setZoneThings(zone.id(), thermostats, windowSensors, indoorSensors, outdoorSensors, notifications);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AirConditioningManager::onThingStateChaged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue)
|
void AirConditioningManager::onThingStateChaged(Thing *thing, const StateTypeId &stateTypeId, const QVariant &value, const QVariant &minValue, const QVariant &maxValue)
|
||||||
{
|
{
|
||||||
Q_UNUSED(stateTypeId)
|
|
||||||
Q_UNUSED(value)
|
|
||||||
Q_UNUSED(minValue)
|
Q_UNUSED(minValue)
|
||||||
Q_UNUSED(maxValue)
|
Q_UNUSED(maxValue)
|
||||||
|
|
||||||
// We'll only want to immediately react on window open/close changes. Anything else is good enough once per minute
|
StateType stateType = thing->thingClass().getStateType(stateTypeId);
|
||||||
if (!thing->thingClass().interfaces().contains("closablesensor")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (const ZoneInfo &zone, m_zones) {
|
foreach (const ZoneInfo &zone, m_zones) {
|
||||||
if (zone.windowSensors().contains(thing->id())) {
|
bool changed = false;
|
||||||
qCDebug(dcAirConditioning()) << "Window sensor in zone" << zone.name() << "changed";
|
if (zone.windowSensors().contains(thing->id()) && stateType.name() == "closed") {
|
||||||
|
qCDebug(dcAirConditioning()) << "Window sensor in zone" << zone.name() << "changed" << value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (zone.thermostats().contains(thing->id()) && stateType.name() == "temperature") {
|
||||||
|
qCDebug(dcAirConditioning()) << "Thermostat temperature sensor in zone" << zone.name() << "changed" << value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (zone.indoorSensors().contains(thing->id()) && QStringList{"temperature", "humidity", "voc", "pm25"}.contains(stateType.name())) {
|
||||||
|
qCDebug(dcAirConditioning()) << "Sensor for" << stateType.name() << "in zone" << zone.name() << "changed" << value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
updateZone(zone.id());
|
updateZone(zone.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,7 +293,7 @@ void AirConditioningManager::onThingStateChaged(Thing *thing, const StateTypeId
|
|||||||
|
|
||||||
void AirConditioningManager::onActionExecuted(const Action &action, Thing::ThingError status)
|
void AirConditioningManager::onActionExecuted(const Action &action, Thing::ThingError status)
|
||||||
{
|
{
|
||||||
if (action.triggeredBy() == Action::TriggeredByUser) {
|
if (action.triggeredBy() == Action::TriggeredByUser && status == Thing::ThingErrorNoError) {
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(action.thingId());
|
Thing *thing = m_thingManager->findConfiguredThing(action.thingId());
|
||||||
if (thing && thing->thingClass().interfaces().contains("thermostat")) {
|
if (thing && thing->thingClass().interfaces().contains("thermostat")) {
|
||||||
if (thing->thingClass().actionTypes().findById(action.actionTypeId()).name() == "targetTemperature") {
|
if (thing->thingClass().actionTypes().findById(action.actionTypeId()).name() == "targetTemperature") {
|
||||||
@ -353,46 +372,67 @@ void AirConditioningManager::updateZone(const QUuid &zoneId)
|
|||||||
|
|
||||||
qCDebug(dcAirConditioning()) << "Window open" << windowOpen << "Override active:" << overrideActive << "Time schedule active:" << timeScheduleActive << "target:" << targetTemp;
|
qCDebug(dcAirConditioning()) << "Window open" << windowOpen << "Override active:" << overrideActive << "Time schedule active:" << timeScheduleActive << "target:" << targetTemp;
|
||||||
|
|
||||||
bool highHumidity = false;
|
// To determine the zone temperature we'll first check the thermostats if they have a temp sensor and use the highest value
|
||||||
bool badAir = false;
|
// If no thermstats with temp sensors are available, we'll use the highest temp value from the indoor sensors.
|
||||||
|
bool tempFromThermostat = false;
|
||||||
|
bool tempFromSensors = false;
|
||||||
|
double temperature = 0;
|
||||||
|
|
||||||
foreach (const ThingId &thingId, zone.thermostats()) {
|
foreach (const ThingId &thingId, zone.thermostats()) {
|
||||||
Thermostat *thermostat = m_thermostats.value(thingId);
|
Thermostat *thermostat = m_thermostats.value(thingId);
|
||||||
if (thermostat) {
|
if (thermostat) {
|
||||||
qCDebug(dcAirConditioning()) << "Setting window open" << windowOpen << " and target temp" << targetTemp;
|
qCDebug(dcAirConditioning()) << "Setting window open" << windowOpen << " and target temp" << targetTemp;
|
||||||
thermostat->setWindowOpen(windowOpen);
|
thermostat->setWindowOpen(windowOpen);
|
||||||
thermostat->setTargetTemperature(targetTemp);
|
thermostat->setTargetTemperature(targetTemp);
|
||||||
|
|
||||||
|
if (thermostat->hasTemperatureSensor()) {
|
||||||
|
qCDebug(dcAirConditioning()) << "Thermostat has temperature sensor:" << thermostat->temperature();
|
||||||
|
if (!tempFromThermostat) {
|
||||||
|
temperature = thermostat->temperature();
|
||||||
|
tempFromThermostat = true;
|
||||||
|
}
|
||||||
|
temperature = qMax(temperature, thermostat->temperature());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double humidity = 0;
|
||||||
|
uint voc = 0;
|
||||||
|
double pm25 = 0;
|
||||||
|
|
||||||
foreach (const ThingId &thingId, zone.indoorSensors()) {
|
foreach (const ThingId &thingId, zone.indoorSensors()) {
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
||||||
|
|
||||||
if (thing->thingClass().interfaces().contains("humiditysensor")) {
|
if (!tempFromThermostat) {
|
||||||
if (thing->stateValue("humidity").toDouble() >= 60) { // > 60 over longer periods of time may cause mould
|
if (thing->thingClass().interfaces().contains("temperaturesensor")) {
|
||||||
highHumidity = true;
|
if (!tempFromSensors) {
|
||||||
|
temperature = thing->stateValue("temperature").toDouble();
|
||||||
|
tempFromSensors = true;
|
||||||
|
} else {
|
||||||
|
temperature = qMax(temperature, thing->stateValue("temperature").toDouble());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thing->thingClass().interfaces().contains("humiditysensor")) {
|
||||||
|
humidity = qMax(humidity, thing->stateValue("humidity").toDouble());
|
||||||
|
}
|
||||||
|
|
||||||
if (thing->thingClass().interfaces().contains("vocsensor")) {
|
if (thing->thingClass().interfaces().contains("vocsensor")) {
|
||||||
if (thing->stateValue("voc").toDouble() >= 660) { // Moderate as of IAQ
|
voc = qMax(voc, thing->stateValue("voc").toUInt());
|
||||||
badAir = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thing->thingClass().interfaces().contains("pm25sensor")) {
|
if (thing->thingClass().interfaces().contains("pm25sensor")) {
|
||||||
if (thing->stateValue("pm25").toDouble() >= 25) { // Moderate as of CAQI
|
pm25 = qMax(pm25, thing->stateValue("pm25").toDouble());
|
||||||
badAir = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ZoneInfo::ZoneStatus newStatus = ZoneInfo::ZoneStatusFlagNone;
|
ZoneInfo::ZoneStatus newStatus = ZoneInfo::ZoneStatusFlagNone;
|
||||||
newStatus.setFlag(ZoneInfo::ZoneStatusFlagWindowOpen, windowOpen);
|
newStatus.setFlag(ZoneInfo::ZoneStatusFlagWindowOpen, windowOpen);
|
||||||
newStatus.setFlag(ZoneInfo::ZoneStatusFlagSetpointOverrideActive, overrideActive);
|
newStatus.setFlag(ZoneInfo::ZoneStatusFlagSetpointOverrideActive, overrideActive);
|
||||||
newStatus.setFlag(ZoneInfo::ZoneStatusFlagTimeScheduleActive, timeScheduleActive);
|
newStatus.setFlag(ZoneInfo::ZoneStatusFlagTimeScheduleActive, timeScheduleActive);
|
||||||
newStatus.setFlag(ZoneInfo::ZoneStatusFlagHighHumidity, highHumidity);
|
newStatus.setFlag(ZoneInfo::ZoneStatusFlagHighHumidity, humidity >= 65); // > 60 over longer periods of time may cause mould, 70 will cause mould
|
||||||
newStatus.setFlag(ZoneInfo::ZoneStatusFlagBadAir, badAir);
|
newStatus.setFlag(ZoneInfo::ZoneStatusFlagBadAir, voc >= 660 || pm25 >= 25); // VOC: 660 Moderate as of IAQ, PM25: 25 Moderate as of CAQI
|
||||||
|
|
||||||
if (zone.setpointOverrideMode() == ZoneInfo::SetpointOverrideModeEventual &&
|
if (zone.setpointOverrideMode() == ZoneInfo::SetpointOverrideModeEventual &&
|
||||||
newStatus != m_eventualOverrideCache.value(zone.id())) {
|
newStatus != m_eventualOverrideCache.value(zone.id())) {
|
||||||
@ -403,11 +443,30 @@ void AirConditioningManager::updateZone(const QUuid &zoneId)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetTemp != zone.currentSetpoint() || newStatus != zone.zoneStatus()) {
|
if (targetTemp != zone.currentSetpoint()
|
||||||
qCDebug(dcAirConditioning()) << "Modifying Zone: setpoint:" << targetTemp << "status:" << newStatus;
|
|| newStatus != zone.zoneStatus()
|
||||||
|
|| temperature != zone.temperature()
|
||||||
|
|| humidity != zone.humidity()
|
||||||
|
|| voc != zone.voc()
|
||||||
|
|| pm25 != zone.pm25()
|
||||||
|
) {
|
||||||
|
qCDebug(dcAirConditioning()) << "Modifying Zone: setpoint:" << targetTemp << "status:" << newStatus << "temp:" << temperature << "humidity:" << humidity << "VOC:" << voc << "PM25:" << pm25;
|
||||||
m_zones[zone.id()].setCurrentSetpoint(targetTemp);
|
m_zones[zone.id()].setCurrentSetpoint(targetTemp);
|
||||||
m_zones[zone.id()].setZoneStatus(newStatus);
|
m_zones[zone.id()].setZoneStatus(newStatus);
|
||||||
|
m_zones[zone.id()].setTemperature(temperature);
|
||||||
|
m_zones[zone.id()].setHumidity(humidity);
|
||||||
|
m_zones[zone.id()].setVoc(voc);
|
||||||
|
m_zones[zone.id()].setPm25(pm25);
|
||||||
emit zoneChanged(m_zones.value(zone.id()));
|
emit zoneChanged(m_zones.value(zone.id()));
|
||||||
|
|
||||||
|
foreach (const ThingId ¬ificationThingId, zone.notifications()) {
|
||||||
|
Notifications *notifications = m_notifications.value(notificationThingId);
|
||||||
|
if (!notifications) {
|
||||||
|
qCWarning(dcAirConditioning()) << "Stale notification thing id in zone!" << notificationThingId << m_notifications.keys();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
notifications->update(m_zones[zone.id()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,6 +474,7 @@ void AirConditioningManager::loadZones()
|
|||||||
{
|
{
|
||||||
qCDebug(dcAirConditioning()) << "Loading zones";
|
qCDebug(dcAirConditioning()) << "Loading zones";
|
||||||
QSettings settings(NymeaSettings::settingsPath() + "/airconditioning.conf", QSettings::IniFormat);
|
QSettings settings(NymeaSettings::settingsPath() + "/airconditioning.conf", QSettings::IniFormat);
|
||||||
|
|
||||||
settings.beginGroup("zones");
|
settings.beginGroup("zones");
|
||||||
qCDebug(dcAirConditioning()) << "child groups of zones" << settings.childKeys() << settings.childGroups();
|
qCDebug(dcAirConditioning()) << "child groups of zones" << settings.childKeys() << settings.childGroups();
|
||||||
foreach (const QString &key, settings.childGroups()) {
|
foreach (const QString &key, settings.childGroups()) {
|
||||||
@ -447,8 +507,7 @@ void AirConditioningManager::loadZones()
|
|||||||
settings.endGroup(); // weekSchedule
|
settings.endGroup(); // weekSchedule
|
||||||
zone.setWeekSchedule(weekSchedule);
|
zone.setWeekSchedule(weekSchedule);
|
||||||
|
|
||||||
qCDebug(dcAirConditioning()) << "Loading thermostats" << settings.value("thermostats").toStringList() << settings.value("thermostats").toList();
|
QList<ThingId> thermostats, windowSensors, indoorSensors, outdoorSensors, notifications;
|
||||||
QList<ThingId> thermostats, windowSensors, indoorSensors, outdoorSensors;
|
|
||||||
foreach (const QString &thingId, settings.value("thermostats").toStringList()) {
|
foreach (const QString &thingId, settings.value("thermostats").toStringList()) {
|
||||||
thermostats.append(ThingId(thingId));
|
thermostats.append(ThingId(thingId));
|
||||||
}
|
}
|
||||||
@ -465,8 +524,12 @@ void AirConditioningManager::loadZones()
|
|||||||
outdoorSensors.append(ThingId(thingId));
|
outdoorSensors.append(ThingId(thingId));
|
||||||
}
|
}
|
||||||
zone.setOutdoorSensors(outdoorSensors);
|
zone.setOutdoorSensors(outdoorSensors);
|
||||||
|
foreach (const QString &thingId, settings.value("notifications").toStringList()) {
|
||||||
|
notifications.append(ThingId(thingId));
|
||||||
|
}
|
||||||
|
zone.setNotifications(notifications);
|
||||||
|
|
||||||
qCDebug(dcAirConditioning()) << "Zone Loaded:" << zone.thermostats();
|
qCDebug(dcAirConditioning()) << "Zone Loaded:" << zone.thermostats() << zone.notifications();
|
||||||
m_zones.insert(zoneId, zone);
|
m_zones.insert(zoneId, zone);
|
||||||
settings.endGroup(); // zone
|
settings.endGroup(); // zone
|
||||||
}
|
}
|
||||||
@ -504,7 +567,7 @@ void AirConditioningManager::saveZones()
|
|||||||
}
|
}
|
||||||
settings.endGroup(); // weekSchedule
|
settings.endGroup(); // weekSchedule
|
||||||
|
|
||||||
QStringList thermostats, windowSensors, indoorSensors, outdoorSensors;
|
QStringList thermostats, windowSensors, indoorSensors, outdoorSensors, notifications;
|
||||||
foreach (const ThingId &thingId, zone.thermostats()) {
|
foreach (const ThingId &thingId, zone.thermostats()) {
|
||||||
thermostats.append(thingId.toString());
|
thermostats.append(thingId.toString());
|
||||||
}
|
}
|
||||||
@ -522,13 +585,18 @@ void AirConditioningManager::saveZones()
|
|||||||
}
|
}
|
||||||
settings.setValue("outdoorSensors", outdoorSensors);
|
settings.setValue("outdoorSensors", outdoorSensors);
|
||||||
|
|
||||||
|
foreach (const ThingId &thingId, zone.notifications()) {
|
||||||
|
notifications.append(thingId.toString());
|
||||||
|
}
|
||||||
|
settings.setValue("notifications", notifications);
|
||||||
|
|
||||||
settings.endGroup(); // zone
|
settings.endGroup(); // zone
|
||||||
}
|
}
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AirConditioningManager::AirConditioningError AirConditioningManager::verifyThingIds(const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors)
|
AirConditioningManager::AirConditioningError AirConditioningManager::verifyThingIds(const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors, const QList<ThingId> ¬ifications)
|
||||||
{
|
{
|
||||||
foreach (const QUuid &thingId, thermostats) {
|
foreach (const QUuid &thingId, thermostats) {
|
||||||
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
||||||
@ -566,6 +634,17 @@ AirConditioningManager::AirConditioningError AirConditioningManager::verifyThing
|
|||||||
return AirConditioningErrorInvalidThingType;
|
return AirConditioningErrorInvalidThingType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (const QUuid &thingId, notifications) {
|
||||||
|
Thing *thing = m_thingManager->findConfiguredThing(thingId);
|
||||||
|
if (!thing) {
|
||||||
|
qCWarning(dcAirConditioning()) << "No thing with id" << thingId;
|
||||||
|
return AirConditioningErrorThingNotFound;
|
||||||
|
}
|
||||||
|
if (!thing->thingClass().interfaces().contains("notifications")) {
|
||||||
|
qCWarning(dcAirConditioning()) << "Not a notification thing:" << thing->name();
|
||||||
|
return AirConditioningErrorInvalidThingType;
|
||||||
|
}
|
||||||
|
}
|
||||||
return AirConditioningErrorNoError;
|
return AirConditioningErrorNoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include "zoneinfo.h"
|
#include "zoneinfo.h"
|
||||||
#include "thermostat.h"
|
#include "thermostat.h"
|
||||||
|
#include "notifications.h"
|
||||||
|
|
||||||
class AirConditioningManager : public QObject
|
class AirConditioningManager : public QObject
|
||||||
{
|
{
|
||||||
@ -56,8 +57,8 @@ public:
|
|||||||
explicit AirConditioningManager(ThingManager *thingManager, QObject *parent = nullptr);
|
explicit AirConditioningManager(ThingManager *thingManager, QObject *parent = nullptr);
|
||||||
|
|
||||||
ZoneInfos zones() const;
|
ZoneInfos zones() const;
|
||||||
ZoneInfo zone(const ThingId &thermostatId);
|
ZoneInfo zone(const QUuid &thermostatId);
|
||||||
QPair<AirConditioningManager::AirConditioningError, ZoneInfo> addZone(const QString &name, const QList<ThingId> &thermostats, const QList<ThingId> windowSensors, const QList<ThingId> indoorSensors, const QList<ThingId> outdoorSensors);
|
QPair<AirConditioningManager::AirConditioningError, ZoneInfo> addZone(const QString &name, const QList<ThingId> &thermostats, const QList<ThingId> windowSensors, const QList<ThingId> indoorSensors, const QList<ThingId> outdoorSensors, const QList<ThingId> notifications);
|
||||||
AirConditioningError removeZone(const QUuid &zoneId);
|
AirConditioningError removeZone(const QUuid &zoneId);
|
||||||
|
|
||||||
AirConditioningError setZoneName(const QUuid &zoneId, const QString &name);
|
AirConditioningError setZoneName(const QUuid &zoneId, const QString &name);
|
||||||
@ -65,7 +66,7 @@ public:
|
|||||||
AirConditioningError setZoneSetpointOverride(const QUuid &zoneId, double setpoint, ZoneInfo::SetpointOverrideMode mode, uint minutes);
|
AirConditioningError setZoneSetpointOverride(const QUuid &zoneId, double setpoint, ZoneInfo::SetpointOverrideMode mode, uint minutes);
|
||||||
AirConditioningError setZoneWeekSchedules(const QUuid &zoneId, const TemperatureWeekSchedule &temperatureWeekSchedule);
|
AirConditioningError setZoneWeekSchedules(const QUuid &zoneId, const TemperatureWeekSchedule &temperatureWeekSchedule);
|
||||||
|
|
||||||
AirConditioningError setZoneThings(const QUuid &zoneId, const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors);
|
AirConditioningError setZoneThings(const QUuid &zoneId, const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors, const QList<ThingId> ¬ifications);
|
||||||
// AirConditioningError addThing(const QUuid &zoneId, const ThingId &thingId);
|
// AirConditioningError addThing(const QUuid &zoneId, const ThingId &thingId);
|
||||||
// AirConditioningError removeThing(const QUuid &zoneId, const ThingId &thingId);
|
// AirConditioningError removeThing(const QUuid &zoneId, const ThingId &thingId);
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ signals:
|
|||||||
void zoneAdded(const ZoneInfo &zone);
|
void zoneAdded(const ZoneInfo &zone);
|
||||||
void zoneRemoved(const QUuid &zoneId);
|
void zoneRemoved(const QUuid &zoneId);
|
||||||
void zoneChanged(const ZoneInfo &zoneInfo);
|
void zoneChanged(const ZoneInfo &zoneInfo);
|
||||||
|
void notificationThingsChanged(const QList<ThingId> ¬ificationThigns);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onThingAdded(Thing *thing);
|
void onThingAdded(Thing *thing);
|
||||||
@ -88,7 +90,7 @@ private:
|
|||||||
void loadZones();
|
void loadZones();
|
||||||
void saveZones();
|
void saveZones();
|
||||||
|
|
||||||
AirConditioningError verifyThingIds(const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors);
|
AirConditioningError verifyThingIds(const QList<ThingId> &thermostats, const QList<ThingId> &windowSensors, const QList<ThingId> &indoorSensors, const QList<ThingId> &outdoorSensors, const QList<ThingId> ¬ifications);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ThingManager *m_thingManager = nullptr;
|
ThingManager *m_thingManager = nullptr;
|
||||||
@ -97,6 +99,7 @@ private:
|
|||||||
QHash<ThingId, Thermostat*> m_thermostats;
|
QHash<ThingId, Thermostat*> m_thermostats;
|
||||||
QHash<QUuid, ZoneInfo> m_zones;
|
QHash<QUuid, ZoneInfo> m_zones;
|
||||||
QHash<QUuid, ZoneInfo::ZoneStatus> m_eventualOverrideCache;
|
QHash<QUuid, ZoneInfo::ZoneStatus> m_eventualOverrideCache;
|
||||||
|
QHash<ThingId, Notifications*> m_notifications;
|
||||||
|
|
||||||
QDateTime m_lastUpdateTime;
|
QDateTime m_lastUpdateTime;
|
||||||
};
|
};
|
||||||
|
|||||||
101
notifications.cpp
Normal file
101
notifications.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "notifications.h"
|
||||||
|
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
|
Notifications::Notifications(ThingManager *thingManager, Thing *thing, QObject *parent)
|
||||||
|
: QObject{parent},
|
||||||
|
m_thingManager(thingManager),
|
||||||
|
m_thing(thing)
|
||||||
|
{
|
||||||
|
m_clearTimer.setInterval(30*60*1000);
|
||||||
|
m_clearTimer.setSingleShot(true);
|
||||||
|
connect(&m_clearTimer, &QTimer::timeout, this, [this](){
|
||||||
|
m_isShown = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notifications::update(const ZoneInfo &zone)
|
||||||
|
{
|
||||||
|
bool supportsUpdate = m_thing->thingClassId() == ThingClassId("f0dd4c03-0aca-42cc-8f34-9902457b05de")
|
||||||
|
&& m_thing->paramValue("service").toString() == "FB-GCM"
|
||||||
|
// Updating is only supported with versions that have the notificationId param
|
||||||
|
&& !m_thing->thingClass().actionTypes().findByName("notify").paramTypes().findByName("notificationId").id().isNull();
|
||||||
|
|
||||||
|
QString notificationId = "humidityalert-" + zone.id().toString();
|
||||||
|
QString title = "High humidity alert";
|
||||||
|
QString text = QString("Humidity in zone %1: %2 %").arg(zone.name()).arg(zone.humidity());
|
||||||
|
if (zone.zoneStatus().testFlag(ZoneInfo::ZoneStatusFlagHighHumidity)) {
|
||||||
|
if (!m_isShown) {
|
||||||
|
// show
|
||||||
|
updateNotification(notificationId, title, text, false, false);
|
||||||
|
} else if (supportsUpdate) {
|
||||||
|
// update
|
||||||
|
updateNotification(notificationId, title, text, false, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_isShown && supportsUpdate) {
|
||||||
|
// remove
|
||||||
|
updateNotification(notificationId, title, text, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationId = "airalert-" + zone.id().toString();
|
||||||
|
title = "Bad air alert";
|
||||||
|
text = QString("Bad air in zone %1: %2").arg(zone.name());
|
||||||
|
QStringList airValues;
|
||||||
|
if (zone.voc() >= 660) {
|
||||||
|
airValues.append(QString("%1 ppm").arg(zone.voc()));
|
||||||
|
}
|
||||||
|
if (zone.pm25() >= 25) {
|
||||||
|
airValues.append(QString("%1 µg/m³").arg(zone.pm25()));
|
||||||
|
}
|
||||||
|
text = text.arg(airValues.join(","));
|
||||||
|
if (zone.zoneStatus().testFlag(ZoneInfo::ZoneStatusFlagBadAir)) {
|
||||||
|
if (!m_isShown) {
|
||||||
|
// show
|
||||||
|
updateNotification(notificationId, title, text, false, false);
|
||||||
|
} else if (supportsUpdate) {
|
||||||
|
// update
|
||||||
|
updateNotification(notificationId, title, text, false, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_isShown && supportsUpdate) {
|
||||||
|
// remove
|
||||||
|
updateNotification(notificationId, title, text, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notifications::updateNotification(const QString &id, const QString &title, const QString &text, bool sound, bool remove)
|
||||||
|
{
|
||||||
|
ActionType actionType = m_thing->thingClass().actionTypes().findByName("notify");
|
||||||
|
Action action(actionType.id(), m_thing->id(), Action::TriggeredByRule);
|
||||||
|
|
||||||
|
ParamList params = ParamList{
|
||||||
|
Param(actionType.paramTypes().findByName("title").id(), title),
|
||||||
|
Param(actionType.paramTypes().findByName("body").id(), text),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_thing->thingClassId() == ThingClassId("f0dd4c03-0aca-42cc-8f34-9902457b05de")) {
|
||||||
|
QUrlQuery data;
|
||||||
|
data.addQueryItem("open", "airconditioning");
|
||||||
|
params.append(Param(actionType.paramTypes().findByName("data").id(), data.toString()));
|
||||||
|
|
||||||
|
// For backwards compatibility, only add those if the plugin already has them
|
||||||
|
if (!m_thing->thingClass().actionTypes().findByName("notify").paramTypes().findByName("notificationId").id().isNull()) {
|
||||||
|
params.append(Param(actionType.paramTypes().findByName("notificationId").id(), id));
|
||||||
|
params.append(Param(actionType.paramTypes().findByName("sound").id(), sound));
|
||||||
|
params.append(Param(actionType.paramTypes().findByName("remove").id(), remove));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action.setParams(params);
|
||||||
|
|
||||||
|
ThingActionInfo *info = m_thingManager->executeAction(action);
|
||||||
|
connect(info, &ThingActionInfo::finished, this, [=](){
|
||||||
|
if (info->status() == Thing::ThingErrorNoError) {
|
||||||
|
m_isShown = !remove;
|
||||||
|
m_clearTimer.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
37
notifications.h
Normal file
37
notifications.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef NOTIFICATIONS_H
|
||||||
|
#define NOTIFICATIONS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <integrations/thing.h>
|
||||||
|
#include <integrations/thingmanager.h>
|
||||||
|
|
||||||
|
#include "zoneinfo.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Notifications : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Notifications(ThingManager *thingManager, Thing *thing, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void update(const ZoneInfo &zone);
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateNotification(const QString &id, const QString &title, const QString &text, bool sound, bool remove);
|
||||||
|
private:
|
||||||
|
ThingManager *m_thingManager = nullptr;
|
||||||
|
Thing *m_thing = nullptr;
|
||||||
|
|
||||||
|
ZoneInfo::ZoneStatus m_zoneStatus;
|
||||||
|
|
||||||
|
bool m_isShown = false;
|
||||||
|
|
||||||
|
// For devices that don't support updates/removals, we'll assume after some time that it's gone and we may need to show again
|
||||||
|
QTimer m_clearTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NOTIFICATIONS_H
|
||||||
@ -12,6 +12,7 @@ include(../config.pri)
|
|||||||
HEADERS += experiencepluginairconditioning.h \
|
HEADERS += experiencepluginairconditioning.h \
|
||||||
airconditioningjsonhandler.h \
|
airconditioningjsonhandler.h \
|
||||||
airconditioningmanager.h \
|
airconditioningmanager.h \
|
||||||
|
notifications.h \
|
||||||
temperatureschedule.h \
|
temperatureschedule.h \
|
||||||
thermostat.h \
|
thermostat.h \
|
||||||
zoneinfo.h
|
zoneinfo.h
|
||||||
@ -19,6 +20,7 @@ HEADERS += experiencepluginairconditioning.h \
|
|||||||
SOURCES += experiencepluginairconditioning.cpp \
|
SOURCES += experiencepluginairconditioning.cpp \
|
||||||
airconditioningjsonhandler.cpp \
|
airconditioningjsonhandler.cpp \
|
||||||
airconditioningmanager.cpp \
|
airconditioningmanager.cpp \
|
||||||
|
notifications.cpp \
|
||||||
temperatureschedule.cpp \
|
temperatureschedule.cpp \
|
||||||
thermostat.cpp \
|
thermostat.cpp \
|
||||||
zoneinfo.cpp
|
zoneinfo.cpp
|
||||||
|
|||||||
@ -128,3 +128,13 @@ void Thermostat::setWindowOpen(bool windowOpen)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Thermostat::hasTemperatureSensor() const
|
||||||
|
{
|
||||||
|
return m_thing->thingClass().interfaces().contains("temperaturesensor");
|
||||||
|
}
|
||||||
|
|
||||||
|
double Thermostat::temperature() const
|
||||||
|
{
|
||||||
|
return m_thing->stateValue("temperature").toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,9 @@ public:
|
|||||||
void setTargetTemperature(double targetTemperature, bool force = false);
|
void setTargetTemperature(double targetTemperature, bool force = false);
|
||||||
void setWindowOpen(bool windowOpen);
|
void setWindowOpen(bool windowOpen);
|
||||||
|
|
||||||
|
bool hasTemperatureSensor() const;
|
||||||
|
double temperature() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
50
zoneinfo.cpp
50
zoneinfo.cpp
@ -139,6 +139,16 @@ void ZoneInfo::setOutdoorSensors(const QList<ThingId> &outdoorSensors)
|
|||||||
m_outdoorSensors = outdoorSensors;
|
m_outdoorSensors = outdoorSensors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<ThingId> ZoneInfo::notifications() const
|
||||||
|
{
|
||||||
|
return m_notifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneInfo::setNotifications(const QList<ThingId> ¬ifications)
|
||||||
|
{
|
||||||
|
m_notifications = notifications;
|
||||||
|
}
|
||||||
|
|
||||||
ZoneInfo::ZoneStatus ZoneInfo::zoneStatus() const
|
ZoneInfo::ZoneStatus ZoneInfo::zoneStatus() const
|
||||||
{
|
{
|
||||||
return m_zoneStatus;
|
return m_zoneStatus;
|
||||||
@ -154,6 +164,46 @@ void ZoneInfo::setZoneStatusFlag(ZoneStatusFlag flag, bool set)
|
|||||||
m_zoneStatus.setFlag(flag, set);
|
m_zoneStatus.setFlag(flag, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double ZoneInfo::temperature() const
|
||||||
|
{
|
||||||
|
return m_temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneInfo::setTemperature(double temperature)
|
||||||
|
{
|
||||||
|
m_temperature = temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ZoneInfo::humidity() const
|
||||||
|
{
|
||||||
|
return m_humidity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneInfo::setHumidity(double humidity)
|
||||||
|
{
|
||||||
|
m_humidity = humidity;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ZoneInfo::voc() const
|
||||||
|
{
|
||||||
|
return m_voc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneInfo::setVoc(uint voc)
|
||||||
|
{
|
||||||
|
m_voc = voc;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ZoneInfo::pm25() const
|
||||||
|
{
|
||||||
|
return m_pm25;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneInfo::setPm25(double pm25)
|
||||||
|
{
|
||||||
|
m_pm25 = pm25;
|
||||||
|
}
|
||||||
|
|
||||||
TemperatureWeekSchedule ZoneInfo::weekSchedule() const
|
TemperatureWeekSchedule ZoneInfo::weekSchedule() const
|
||||||
{
|
{
|
||||||
return m_weekSchedule;
|
return m_weekSchedule;
|
||||||
|
|||||||
25
zoneinfo.h
25
zoneinfo.h
@ -53,7 +53,12 @@ class ZoneInfo
|
|||||||
Q_PROPERTY(QList<ThingId> windowSensors READ windowSensors)
|
Q_PROPERTY(QList<ThingId> windowSensors READ windowSensors)
|
||||||
Q_PROPERTY(QList<ThingId> indoorSensors READ indoorSensors)
|
Q_PROPERTY(QList<ThingId> indoorSensors READ indoorSensors)
|
||||||
Q_PROPERTY(QList<ThingId> outdoorSensors READ outdoorSensors)
|
Q_PROPERTY(QList<ThingId> outdoorSensors READ outdoorSensors)
|
||||||
|
Q_PROPERTY(QList<ThingId> notifications READ notifications)
|
||||||
Q_PROPERTY(ZoneStatus zoneStatus READ zoneStatus)
|
Q_PROPERTY(ZoneStatus zoneStatus READ zoneStatus)
|
||||||
|
Q_PROPERTY(double temperature READ temperature)
|
||||||
|
Q_PROPERTY(double humidity READ humidity)
|
||||||
|
Q_PROPERTY(uint voc READ voc)
|
||||||
|
Q_PROPERTY(double pm25 READ pm25)
|
||||||
Q_PROPERTY(TemperatureWeekSchedule weekSchedule READ weekSchedule)
|
Q_PROPERTY(TemperatureWeekSchedule weekSchedule READ weekSchedule)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -109,10 +114,25 @@ public:
|
|||||||
QList<ThingId> outdoorSensors() const;
|
QList<ThingId> outdoorSensors() const;
|
||||||
void setOutdoorSensors(const QList<ThingId> &outdoorSensors);
|
void setOutdoorSensors(const QList<ThingId> &outdoorSensors);
|
||||||
|
|
||||||
|
QList<ThingId> notifications() const;
|
||||||
|
void setNotifications(const QList<ThingId> ¬ifications);
|
||||||
|
|
||||||
ZoneInfo::ZoneStatus zoneStatus() const;
|
ZoneInfo::ZoneStatus zoneStatus() const;
|
||||||
void setZoneStatus(ZoneStatus zoneStatus);
|
void setZoneStatus(ZoneStatus zoneStatus);
|
||||||
void setZoneStatusFlag(ZoneStatusFlag flag, bool set);
|
void setZoneStatusFlag(ZoneStatusFlag flag, bool set);
|
||||||
|
|
||||||
|
double temperature() const;
|
||||||
|
void setTemperature(double temperature);
|
||||||
|
|
||||||
|
double humidity() const;
|
||||||
|
void setHumidity(double humidity);
|
||||||
|
|
||||||
|
uint voc() const;
|
||||||
|
void setVoc(uint voc);
|
||||||
|
|
||||||
|
double pm25() const;
|
||||||
|
void setPm25(double pm25);
|
||||||
|
|
||||||
TemperatureWeekSchedule weekSchedule() const;
|
TemperatureWeekSchedule weekSchedule() const;
|
||||||
void setWeekSchedule(const TemperatureWeekSchedule &weekSchedule);
|
void setWeekSchedule(const TemperatureWeekSchedule &weekSchedule);
|
||||||
|
|
||||||
@ -128,7 +148,12 @@ private:
|
|||||||
QList<ThingId> m_windowSensors;
|
QList<ThingId> m_windowSensors;
|
||||||
QList<ThingId> m_indoorSensors;
|
QList<ThingId> m_indoorSensors;
|
||||||
QList<ThingId> m_outdoorSensors;
|
QList<ThingId> m_outdoorSensors;
|
||||||
|
QList<ThingId> m_notifications;
|
||||||
ZoneStatus m_zoneStatus = ZoneStatusFlagNone;
|
ZoneStatus m_zoneStatus = ZoneStatusFlagNone;
|
||||||
|
double m_temperature = 0;
|
||||||
|
double m_humidity = 0;
|
||||||
|
uint m_voc = 0;
|
||||||
|
double m_pm25 = 0;
|
||||||
TemperatureWeekSchedule m_weekSchedule;
|
TemperatureWeekSchedule m_weekSchedule;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(ZoneInfo)
|
Q_DECLARE_METATYPE(ZoneInfo)
|
||||||
|
|||||||
Reference in New Issue
Block a user