From 69d579297279c85fa58c536d87d32761a8ce3d3e Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 25 Feb 2023 17:03:01 +0100 Subject: [PATCH] Support notification alerts for air condintioning --- .../airconditioningmanager.cpp | 54 ++++++++--- .../airconditioning/airconditioningmanager.h | 4 +- experiences/airconditioning/zoneinfo.cpp | 64 +++++++++++++ experiences/airconditioning/zoneinfo.h | 31 +++++++ libnymea-app/thingsproxy.cpp | 3 +- .../nymeaapp/NymeaAppNotificationService.java | 58 ++++++++---- .../airconditioning/BigZoneStatusIcons.qml | 14 +-- .../airconditioning/EditZoneThingsPage.qml | 39 ++++++++ .../airconditioning/ZoneInfoWrapper.qml | 90 +------------------ .../ui/mainviews/airconditioning/ZoneView.qml | 10 +-- .../mainviews/airconditioning/ZonesView.qml | 2 +- 11 files changed, 240 insertions(+), 129 deletions(-) diff --git a/experiences/airconditioning/airconditioningmanager.cpp b/experiences/airconditioning/airconditioningmanager.cpp index d8fb87f4..40aaf780 100644 --- a/experiences/airconditioning/airconditioningmanager.cpp +++ b/experiences/airconditioning/airconditioningmanager.cpp @@ -136,9 +136,9 @@ int AirConditioningManager::setZoneWeekSchedule(const QUuid &zoneId, Temperature return m_engine->jsonRpcClient()->sendCommand("AirConditioning.SetZoneWeekSchedule", params, this, "setZoneWeekScheduleResponse"); } -int AirConditioningManager::setZoneThings(const QUuid &zoneId, const QList &thermostats, const QList &windowSensors, const QList &indoorSensors, const QList &outdoorSensors) +int AirConditioningManager::setZoneThings(const QUuid &zoneId, const QList &thermostats, const QList &windowSensors, const QList &indoorSensors, const QList &outdoorSensors, const QList ¬ifications) { - QVariantList thermostatIds, windowSensorIds, indoorSensorIds, outdoorSensorIds; + QVariantList thermostatIds, windowSensorIds, indoorSensorIds, outdoorSensorIds, notificationIds; foreach (const QUuid &thingId, thermostats) { thermostatIds.append(thingId); } @@ -151,12 +151,16 @@ int AirConditioningManager::setZoneThings(const QUuid &zoneId, const QListjsonRpcClient()->sendCommand("AirConditioning.SetZoneThings", params, this, "setZoneThingsResponse"); } @@ -167,7 +171,7 @@ int AirConditioningManager::addZoneThermostat(const QUuid &zoneId, const QUuid & if (!zoneInfo) { return -1; } - return setZoneThings(zoneId, zoneInfo->thermostats() << thermostat, zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors()); + return setZoneThings(zoneId, zoneInfo->thermostats() << thermostat, zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors(), zoneInfo->notifications()); } int AirConditioningManager::removeZoneThermostat(const QUuid &zoneId, const QUuid &thermostat) @@ -178,7 +182,7 @@ int AirConditioningManager::removeZoneThermostat(const QUuid &zoneId, const QUui } QList thermostats = zoneInfo->thermostats(); thermostats.removeAll(thermostat); - return setZoneThings(zoneId, thermostats, zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors()); + return setZoneThings(zoneId, thermostats, zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors(), zoneInfo->notifications()); } int AirConditioningManager::addZoneWindowSensor(const QUuid &zoneId, const QUuid &windowSensor) @@ -187,7 +191,7 @@ int AirConditioningManager::addZoneWindowSensor(const QUuid &zoneId, const QUuid if (!zoneInfo) { return -1; } - return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors() << windowSensor, zoneInfo->indoorSensors(), zoneInfo->outdoorSensors()); + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors() << windowSensor, zoneInfo->indoorSensors(), zoneInfo->outdoorSensors(), zoneInfo->notifications()); } int AirConditioningManager::removeWindowSensor(const QUuid &zoneId, const QUuid &windowSensor) @@ -198,7 +202,7 @@ int AirConditioningManager::removeWindowSensor(const QUuid &zoneId, const QUuid } QList windowSensors = zoneInfo->windowSensors(); windowSensors.removeAll(windowSensor); - return setZoneThings(zoneId, zoneInfo->thermostats(), windowSensors, zoneInfo->indoorSensors(), zoneInfo->outdoorSensors()); + return setZoneThings(zoneId, zoneInfo->thermostats(), windowSensors, zoneInfo->indoorSensors(), zoneInfo->outdoorSensors(), zoneInfo->notifications()); } int AirConditioningManager::addZoneIndoorSensor(const QUuid &zoneId, const QUuid &indoorSensor) @@ -207,7 +211,7 @@ int AirConditioningManager::addZoneIndoorSensor(const QUuid &zoneId, const QUuid if (!zoneInfo) { return -1; } - return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors() << indoorSensor, zoneInfo->outdoorSensors()); + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors() << indoorSensor, zoneInfo->outdoorSensors(), zoneInfo->notifications()); } int AirConditioningManager::removeZoneIndoorSensor(const QUuid &zoneId, const QUuid &indoorSensor) @@ -218,7 +222,7 @@ int AirConditioningManager::removeZoneIndoorSensor(const QUuid &zoneId, const QU } QList indoorSensors = zoneInfo->indoorSensors(); indoorSensors.removeAll(indoorSensor); - return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), indoorSensors, zoneInfo->outdoorSensors()); + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), indoorSensors, zoneInfo->outdoorSensors(), zoneInfo->notifications()); } @@ -228,7 +232,7 @@ int AirConditioningManager::addZoneOutdoorSensor(const QUuid &zoneId, const QUui if (!zoneInfo) { return -1; } - return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors() << outdoorSensor); + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors() << outdoorSensor, zoneInfo->notifications()); } int AirConditioningManager::removeZoneOutdoorSensor(const QUuid &zoneId, const QUuid &outdoorSensor) @@ -239,7 +243,27 @@ int AirConditioningManager::removeZoneOutdoorSensor(const QUuid &zoneId, const Q } QList outdoorSensors = zoneInfo->outdoorSensors(); outdoorSensors.removeAll(outdoorSensor); - return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors(), outdoorSensors); + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors(), outdoorSensors, zoneInfo->notifications()); +} + +int AirConditioningManager::addZoneNotification(const QUuid &zoneId, const QUuid ¬ification) +{ + ZoneInfo *zoneInfo = m_zoneInfos->getZoneInfo(zoneId); + if (!zoneInfo) { + return -1; + } + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors(), zoneInfo->notifications() << notification); +} + +int AirConditioningManager::removeZoneNotification(const QUuid &zoneId, const QUuid ¬ification) +{ + ZoneInfo *zoneInfo = m_zoneInfos->getZoneInfo(zoneId); + if (!zoneInfo) { + return -1; + } + QList notifications = zoneInfo->notifications(); + notifications.removeAll(notification); + return setZoneThings(zoneId, zoneInfo->thermostats(), zoneInfo->windowSensors(), zoneInfo->indoorSensors(), zoneInfo->outdoorSensors(), notifications); } void AirConditioningManager::notificationReceived(const QVariantMap &data) @@ -352,6 +376,10 @@ ZoneInfo *AirConditioningManager::unpack(const QVariantMap &zoneMap, ZoneInfo *z } qCDebug(dcAirConditioningExperience()) << "Zone status:" << zoneStatus; zone->setZoneStatus(zoneStatus); + zone->setTemperature(zoneMap.value("temperature").toDouble()); + zone->setHumidity(zoneMap.value("humidity").toDouble()); + zone->setVoc(zoneMap.value("voc").toUInt()); + zone->setPm25(zoneMap.value("pm25").toDouble()); zone->setCurrentSetpoint(zoneMap.value("currentSetpoint").toDouble()); zone->setStandbySetpoint(zoneMap.value("standbySetpoint").toDouble()); QMetaEnum modeEnum = QMetaEnum::fromType(); @@ -368,7 +396,7 @@ ZoneInfo *AirConditioningManager::unpack(const QVariantMap &zoneMap, ZoneInfo *z zone->weekSchedule()->get(day)->createSchedule(scheduleMap.value("startTime").toTime(), scheduleMap.value("endTime").toTime(), scheduleMap.value("temperature").toDouble()); } } - QList thermostats, windowSensors, indoorSensors, outdoorSensors; + QList thermostats, windowSensors, indoorSensors, outdoorSensors, notifications; foreach (const QVariant &variant, zoneMap.value("thermostats").toList()) { thermostats.append(variant.toUuid()); } @@ -381,9 +409,13 @@ ZoneInfo *AirConditioningManager::unpack(const QVariantMap &zoneMap, ZoneInfo *z foreach (const QVariant &variant, zoneMap.value("outdoorSensors").toList()) { outdoorSensors.append(variant.toUuid()); } + foreach (const QVariant &variant, zoneMap.value("notifications").toList()) { + notifications.append(variant.toUuid()); + } zone->setThermostats(thermostats); zone->setWindowSensors(windowSensors); zone->setIndoorSensors(indoorSensors); zone->setOutdoorSensors(outdoorSensors); + zone->setNotifications(notifications); return zone; } diff --git a/experiences/airconditioning/airconditioningmanager.h b/experiences/airconditioning/airconditioningmanager.h index a6d67fe2..7501f332 100644 --- a/experiences/airconditioning/airconditioningmanager.h +++ b/experiences/airconditioning/airconditioningmanager.h @@ -37,7 +37,7 @@ public: Q_INVOKABLE int setZoneStandbySetpoint(const QUuid &zoneId, double standbySetpoint); Q_INVOKABLE int setZoneSetpointOverride(const QUuid &zoneId, double setpointOverride, ZoneInfo::SetpointOverrideMode mode, uint minutes); Q_INVOKABLE int setZoneWeekSchedule(const QUuid &zoneId, TemperatureWeekSchedule *weekSchedule); - Q_INVOKABLE int setZoneThings(const QUuid &zoneId, const QList &thermostats, const QList &windowSensors, const QList &indoorSensors, const QList &outdoorSensors); + Q_INVOKABLE int setZoneThings(const QUuid &zoneId, const QList &thermostats, const QList &windowSensors, const QList &indoorSensors, const QList &outdoorSensors, const QList ¬ificationIds); Q_INVOKABLE int addZoneThermostat(const QUuid &zoneId, const QUuid &thermostat); Q_INVOKABLE int removeZoneThermostat(const QUuid &zoneId, const QUuid &thermostat); @@ -47,6 +47,8 @@ public: Q_INVOKABLE int removeZoneIndoorSensor(const QUuid &zoneId, const QUuid &indoorSensor); Q_INVOKABLE int addZoneOutdoorSensor(const QUuid &zoneId, const QUuid &outdoorSensor); Q_INVOKABLE int removeZoneOutdoorSensor(const QUuid &zoneId, const QUuid &outdoorSensor); + Q_INVOKABLE int addZoneNotification(const QUuid &zoneId, const QUuid ¬ification); + Q_INVOKABLE int removeZoneNotification(const QUuid &zoneId, const QUuid ¬ification); signals: void engineChanged(); diff --git a/experiences/airconditioning/zoneinfo.cpp b/experiences/airconditioning/zoneinfo.cpp index c1272249..0303dcb5 100644 --- a/experiences/airconditioning/zoneinfo.cpp +++ b/experiences/airconditioning/zoneinfo.cpp @@ -146,6 +146,70 @@ void ZoneInfo::setOutdoorSensors(const QList &outdoorSensors) } } +QList ZoneInfo::notifications() const +{ + return m_notifications; +} + +void ZoneInfo::setNotifications(const QList ¬ifications) +{ + if (m_notifications != notifications) { + m_notifications = notifications; + } +} + +double ZoneInfo::temperature() const +{ + return m_temperature; +} + +void ZoneInfo::setTemperature(double temperature) +{ + if (m_temperature != temperature) { + m_temperature = temperature; + emit temperatureChanged(); + } +} + +double ZoneInfo::humidity() const +{ + return m_humidity; +} + +void ZoneInfo::setHumidity(double humidity) +{ + if (m_humidity != humidity) { + m_humidity = humidity; + emit humidityChanged(); + } +} + +uint ZoneInfo::voc() const +{ + return m_voc; +} + +void ZoneInfo::setVoc(uint voc) +{ + if (m_voc != voc) { + m_voc = voc; + emit vocChanged(); + } +} + +double ZoneInfo::pm25() const +{ + return m_pm25; +} + +void ZoneInfo::setPm25(double pm25) +{ + if (m_pm25 != pm25) { + m_pm25 = pm25; + emit pm25Changed(); + } +} + QVariant ZoneInfos::data(const QModelIndex &index, int role) const { switch (role) { diff --git a/experiences/airconditioning/zoneinfo.h b/experiences/airconditioning/zoneinfo.h index 67475472..59344bdd 100644 --- a/experiences/airconditioning/zoneinfo.h +++ b/experiences/airconditioning/zoneinfo.h @@ -23,6 +23,11 @@ class ZoneInfo : public QObject Q_PROPERTY(QList windowSensors READ windowSensors NOTIFY windowSensorsChanged) Q_PROPERTY(QList indoorSensors READ indoorSensors NOTIFY indoorSensorsChanged) Q_PROPERTY(QList outdoorSensors READ outdoorSensors NOTIFY outdoorSensorsChanged) + Q_PROPERTY(QList notifications READ notifications NOTIFY notificationsChanged) + Q_PROPERTY(double temperature READ temperature NOTIFY temperatureChanged) + Q_PROPERTY(double humidity READ humidity NOTIFY humidityChanged) + Q_PROPERTY(uint voc READ voc NOTIFY vocChanged) + Q_PROPERTY(double pm25 READ pm25 NOTIFY pm25Changed) public: enum ZoneStatusFlag { ZoneStatusFlagNone = 0x00, @@ -80,6 +85,21 @@ public: QList outdoorSensors() const; void setOutdoorSensors(const QList &outdoorSensors); + QList notifications() const; + void setNotifications(const QList ¬ifications); + + 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); + signals: void nameChanged(); void zoneStatusChanged(); @@ -90,6 +110,12 @@ signals: void windowSensorsChanged(); void indoorSensorsChanged(); void outdoorSensorsChanged(); + void notificationsChanged(); + + void temperatureChanged(); + void humidityChanged(); + void vocChanged(); + void pm25Changed(); private: QUuid m_id; @@ -105,6 +131,11 @@ private: QList m_windowSensors; QList m_indoorSensors; QList m_outdoorSensors; + QList m_notifications; + double m_temperature = 0; + double m_humidity = 0; + uint m_voc = 0; + double m_pm25 = 0; }; class ZoneInfos: public QAbstractListModel diff --git a/libnymea-app/thingsproxy.cpp b/libnymea-app/thingsproxy.cpp index 1d13692a..b750181a 100644 --- a/libnymea-app/thingsproxy.cpp +++ b/libnymea-app/thingsproxy.cpp @@ -56,6 +56,7 @@ void ThingsProxy::setEngine(Engine *engine) m_engine = engine; emit engineChanged(); if (!m_engine) { + setSourceModel(nullptr); return; } @@ -660,7 +661,7 @@ bool ThingsProxy::filterAcceptsRow(int source_row, const QModelIndex &source_par } } - ThingClass *thingClass = m_engine->thingManager()->thingClasses()->getThingClass(thing->thingClassId()); + ThingClass *thingClass = thing->thingClass(); if (!m_shownInterfaces.isEmpty()) { bool foundMatch = false; foreach (const QString &filterInterface, m_shownInterfaces) { diff --git a/nymea-app/platformintegration/android/java-firebase/io/guh/nymeaapp/NymeaAppNotificationService.java b/nymea-app/platformintegration/android/java-firebase/io/guh/nymeaapp/NymeaAppNotificationService.java index bd6ca12c..6aba9707 100644 --- a/nymea-app/platformintegration/android/java-firebase/io/guh/nymeaapp/NymeaAppNotificationService.java +++ b/nymea-app/platformintegration/android/java-firebase/io/guh/nymeaapp/NymeaAppNotificationService.java @@ -27,6 +27,14 @@ public class NymeaAppNotificationService extends FirebaseMessagingService { private static final String TAG = "nymea-app: NymeaAppNotificationService"; + private int hashId(String id) { + int hash = 7; + for (int i = 0; i < id.length(); i++) { + hash = hash * 31 + id.charAt(i); + } + return hash; + } + public static boolean checkPlayServices() { Log.d(TAG, "Checking for Google Play services"); try { @@ -41,11 +49,36 @@ public class NymeaAppNotificationService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { - Intent intent = new Intent(this, NymeaAppActivity.class); -// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); -// PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT); - Log.d(TAG, "adding extra data to intent: " + remoteMessage.getData().get("nymeaData")); + NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + // Make sure channels exist + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel alertChannel = new NotificationChannel("alert", "Alerts about your nymea system", NotificationManager.IMPORTANCE_HIGH); + notificationManager.createNotificationChannel(alertChannel); + NotificationChannel infoChannel = new NotificationChannel("info", "Information about your nymea system", NotificationManager.IMPORTANCE_LOW); + notificationManager.createNotificationChannel(infoChannel); + } + + + Intent intent = new Intent(this, NymeaAppActivity.class); + Log.d(TAG, "Notification data: " + remoteMessage.getData()); + + String notificationIdString = remoteMessage.getData().get("notificationId"); + Log.d(TAG, "NotificationID " + notificationIdString); + int notificationId = new Random().nextInt(60000);; + if (notificationIdString != null) { + notificationId = hashId(notificationIdString); + } + + boolean sound = remoteMessage.getData().get("sound") == null || remoteMessage.getData().get("sound").equals("true"); + boolean remove = remoteMessage.getData().get("remove") != null && remoteMessage.getData().get("remove").equals("true"); + Log.d(TAG, "NotificationID " + notificationIdString + " int " + notificationId + " remove: " + (remove ? "yes" : "no") + " sound: " + (sound ? "yes" : "no")); + + if (remove) { + notificationManager.cancel(notificationId); + return; + } intent.setAction(Intent.ACTION_SEND); intent.putExtra("notificationData", remoteMessage.getData().get("nymeaData")); @@ -60,15 +93,19 @@ public class NymeaAppNotificationService extends FirebaseMessagingService { Log.d(TAG, "notification icon resource: " + resId + " Package:" + getPackageName()); - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "notify_001") + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, sound ? "alert" : "info") .setSmallIcon(resId) .setColor(0xFF57BAAE) .setContentTitle(remoteMessage.getData().get("title")) .setContentText(remoteMessage.getData().get("body")) .setAutoCancel(true) - .setSound(android.provider.Settings.System.DEFAULT_RINGTONE_URI) .setContentIntent(pendingIntent); + if (sound) { + notificationBuilder.setSound(android.provider.Settings.System.DEFAULT_RINGTONE_URI); + } + + // Action tests // Intent actionIntent = new Intent(this, NymeaAppActivity.class); // actionIntent.setAction(Intent.ACTION_SEND); @@ -80,15 +117,6 @@ public class NymeaAppNotificationService extends FirebaseMessagingService { // notificationBuilder.addAction(resId, "70%", actionPendingIntent); // Action tests end - NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel channel = new NotificationChannel("notify_001", "Notifications from your nymea system", NotificationManager.IMPORTANCE_HIGH); - notificationManager.createNotificationChannel(channel); - } - - - int notificationId = new Random().nextInt(60000); Log.d(TAG, "Posting Notification: " + remoteMessage.getMessageId()); notificationManager.notify(notificationId, notificationBuilder.build()); diff --git a/nymea-app/ui/mainviews/airconditioning/BigZoneStatusIcons.qml b/nymea-app/ui/mainviews/airconditioning/BigZoneStatusIcons.qml index b56552cb..ec9d39ae 100644 --- a/nymea-app/ui/mainviews/airconditioning/BigZoneStatusIcons.qml +++ b/nymea-app/ui/mainviews/airconditioning/BigZoneStatusIcons.qml @@ -64,7 +64,7 @@ Item { icon: "sensors/temperature", color: Style.iconColor, activeColor: Style.accentColor, - text: Types.toUiValue(zoneWrapper.zoneTemperature.toFixed(1), Types.UnitDegreeCelsius) + Types.toUiUnit(Types.UnitDegreeCelsius), + text: Types.toUiValue(zone.temperature.toFixed(1), Types.UnitDegreeCelsius) + Types.toUiUnit(Types.UnitDegreeCelsius), visible: zoneWrapper.indoorTempSensors.count > 0 && zoneWrapper.thermostats.count == 0, alertVisible: false }, @@ -73,18 +73,18 @@ Item { icon: "sensors/humidity", color: app.interfaceToColor("humiditysensor"), activeColor: app.interfaceToColor("humiditysensor"), - text: qsTr("%1% humidity").arg(zoneWrapper.zoneHumidity.toFixed(0)), - activeText:qsTr("%1% humidity").arg(zoneWrapper.zoneHumidity.toFixed(0)), + text: qsTr("%1% humidity").arg(zone.humidity.toFixed(0)), + activeText:qsTr("%1% humidity").arg(zone.humidity.toFixed(0)), visible: zoneWrapper.indoorHumiditySensors.count > 0, alertVisible: (root.zone.zoneStatus & ZoneInfo.ZoneStatusFlagHighHumidity) > 0 }, { value: ZoneInfo.ZoneStatusFlagBadAir, icon: "weathericons/weather-clouds", - color: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zoneWrapper.zoneVOC).color, - activeColor: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zoneWrapper.zoneVOC).color, - text: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zoneWrapper.zoneVOC).text, - activeText: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zoneWrapper.zoneVOC).text,// qsTr("Air quality alert!"), + color: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zone.voc).color, + activeColor: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zone.voc).color, + text: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zone.voc).text, + activeText: AirQualityIndex.currentIndex(AirQualityIndex.iaqVoc, zone.voc).text,// qsTr("Air quality alert!"), visible: zoneWrapper.indoorVocSensors.count > 0 || zoneWrapper.indoorPm25Sensors.count > 0, alertVisible: (root.zone.zoneStatus & ZoneInfo.ZoneStatusFlagBadAir) > 0 } diff --git a/nymea-app/ui/mainviews/airconditioning/EditZoneThingsPage.qml b/nymea-app/ui/mainviews/airconditioning/EditZoneThingsPage.qml index 8138ca73..718227b1 100644 --- a/nymea-app/ui/mainviews/airconditioning/EditZoneThingsPage.qml +++ b/nymea-app/ui/mainviews/airconditioning/EditZoneThingsPage.qml @@ -187,6 +187,45 @@ SettingsPageBase { } } + SettingsPageSectionHeader { + text: qsTr("Notifications") + } + + Repeater { + model: zoneWrapper.notifications + delegate: ThingDelegate { + Layout.fillWidth: true + thing: zoneWrapper.notifications.get(index) + progressive: false + canDelete: true + onDeleteClicked: { + acManager.removeZoneNotification(zone.id, thing.id) + } + } + } + + Button { + Layout.fillWidth: true + Layout.margins: Style.margins + text: qsTr("Add notification target") + onClicked: { + var page = pageStack.push(selectThingComponent, { + acManager: acManager, + zone: zone, + interfaces: ["notifications"], + hiddenThingIds: zone.outdoorSensors, + title: qsTr("Select notification target"), + placeHolderTitle: qsTr("No notification things installed"), + placeHolderText: qsTr("Before a notification target can be assigned to this zone, it needs to be connected to nymea."), + placeHolderButtonText: qsTr("Setup notification targets"), + placeHolderFilterInterface: "notifications" + }) + page.selected.connect(function(thingId) { + acManager.addZoneNotification(zone.id, thingId) + }) + } + } + Component { id: selectThingComponent SettingsPageBase { diff --git a/nymea-app/ui/mainviews/airconditioning/ZoneInfoWrapper.qml b/nymea-app/ui/mainviews/airconditioning/ZoneInfoWrapper.qml index 72fc8083..32cf347b 100644 --- a/nymea-app/ui/mainviews/airconditioning/ZoneInfoWrapper.qml +++ b/nymea-app/ui/mainviews/airconditioning/ZoneInfoWrapper.qml @@ -44,10 +44,6 @@ Item { property ZoneInfo zone: null - readonly property double zoneTemperature: d.zoneTemperature - readonly property double zoneHumidity: d.zoneHumidity - readonly property double zoneVOC: d.zoneVOC - readonly property ThingsProxy thermostats: ThingsProxy { engine: zone.thermostats.length > 0 ? _engine : null shownThingIds: zone.thermostats @@ -118,88 +114,8 @@ Item { shownInterfaces: ["pm25sensor"] } - QtObject { - id: d - property double zoneTemperature - function updateZoneTemperature() { - var value = undefined; - if (thermostats.count > 0) { - for (var i = 0; i < thermostats.count; i++) { - var tempState = thermostats.get(i).stateByName("temperature") - if (!tempState) { - continue; - } - - if (value == undefined || tempState.value > value) { - value = tempState.value - } - } - } - if (value == undefined) { - for (var i = 0; i < indoorTempSensors.count; i++) { - var t = indoorTempSensors.get(i).stateByName("temperature").value - if (value == undefined || t > value) { - value = t - } - } - } - if (value != undefined) { - zoneTemperature = value; - } - } - - property double zoneHumidity - function updateZoneHumidity() { - var value = undefined; - for (var i = 0; i < indoorHumiditySensors.count; i++) { - var t = indoorHumiditySensors.get(i).stateByName("humidity").value - if (value == undefined || t > value) { - value = t; - } - } - if (value != undefined) { - zoneHumidity = value; - } - } - - property double zoneVOC - function updateZoneVOC() { - var value = undefined; - for (var i = 0; i < indoorVocSensors.count; i++) { - var t = indoorVocSensors.get(i).stateByName("voc").value - if (value == undefined || t > value) { - value = t; - } - } - if (value != undefined) { - zoneVOC = value; - } - } - } - - Repeater { - id: thingsRepeater - model: ThingsProxy { - engine: zone.thermostats.length > 0 || zone.indoorSensors.length > 0 ? _engine : null - shownThingIds: zone.thermostats.concat(zone.indoorSensors) - } - - delegate: Item { - readonly property Thing thing: index < thermostats.count ? thermostats.get(index) : indoorTempSensors.get(index - thermostats.count) - readonly property State temperatureState: thing ? thing.stateByName("temperature") : null - property double temp: temperatureState ? temperatureState.value : 0 - onTempChanged: d.updateZoneTemperature() - readonly property State humidityState: thing ? thing.stateByName("humidity") : null - property double humidity: humidityState ? humidityState.value : 0 - onHumidityChanged: d.updateZoneHumidity() - readonly property State vocState: thing ? thing.stateByName("voc") : null - property double voc: vocState ? vocState.value : 0 - onVocChanged: d.updateZoneVOC() - } - onCountChanged: { - d.updateZoneTemperature() - d.updateZoneHumidity() - d.updateZoneVOC() - } + readonly property ThingsProxy notifications: ThingsProxy { + engine: root.zone.notifications.length > 0 ? _engine : null + shownThingIds: root.zone.notifications } } diff --git a/nymea-app/ui/mainviews/airconditioning/ZoneView.qml b/nymea-app/ui/mainviews/airconditioning/ZoneView.qml index 21ceb674..27d062f5 100644 --- a/nymea-app/ui/mainviews/airconditioning/ZoneView.qml +++ b/nymea-app/ui/mainviews/airconditioning/ZoneView.qml @@ -43,7 +43,7 @@ Item { precision: 0.5 value: root.zone.currentSetpoint color: pendingValue < activeValue ? Style.blue : Style.red - activeValue: zoneWrapper.zoneTemperature + activeValue: zone.temperature onMoved: { acManager.setZoneSetpointOverride(root.zone.id, value, ZoneInfo.SetpointOverrideModeEventual, 0) @@ -72,17 +72,15 @@ Item { text: Types.toUiValue(zone.currentSetpoint, Types.UnitDegreeCelsius).toFixed(1) font.pixelSize: Math.min(Style.hugeFont.pixelSize, thermostat.contentItem.height / 8) horizontalAlignment: Text.AlignHCenter - color: zoneWrapper.zoneTemperature == undefined - ? Stype.foregroundColor - : zone.currentSetpoint > zoneWrapper.zoneTemperature + color: zone.currentSetpoint > zone.temperature ? Style.red - : zone.currentSetpoint < zoneWrapper.zoneTemperature + : zone.currentSetpoint < zone.temperature ? Style.blue : Style.foregroundColor } Label { Layout.fillWidth: true - text: Types.toUiValue(zoneWrapper.zoneTemperature, Types.UnitDegreeCelsius).toFixed(1) + text: Types.toUiValue(zone.temperature, Types.UnitDegreeCelsius).toFixed(1) font.pixelSize: Math.min(Style.largeFont.pixelSize, thermostat.contentItem.height / 12) wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter diff --git a/nymea-app/ui/mainviews/airconditioning/ZonesView.qml b/nymea-app/ui/mainviews/airconditioning/ZonesView.qml index 81af1183..5ddb0ffd 100644 --- a/nymea-app/ui/mainviews/airconditioning/ZonesView.qml +++ b/nymea-app/ui/mainviews/airconditioning/ZonesView.qml @@ -105,7 +105,7 @@ Flickable { color: app.interfaceToColor("temperaturesensor") } Label { - text: Types.toUiValue(zoneWrapper.zoneTemperature, Types.UnitDegreeCelsius).toFixed(1) + Types.toUiUnit(Types.UnitDegreeCelsius) + text: Types.toUiValue(zoneDelegate.zone.temperature, Types.UnitDegreeCelsius).toFixed(1) + Types.toUiUnit(Types.UnitDegreeCelsius) } }