Skip to content

Commit

Permalink
- optimized performance/reduced DB
Browse files Browse the repository at this point in the history
transactions
- dynamically adjust min/max limits for 'targetTemp' and 'setFanSpeed'
- added more documentation
  • Loading branch information
Black-Thunder committed May 26, 2020
1 parent 1bc65b8 commit 77627e4
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 83 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ Documentation:

## Changelog

### 0.0.3-alpha2 26.05.2020
* (Black-Thunder) optimized performance/reduced DB transactions
* (Black-Thunder) dynamically adjust min/max limits for 'targetTemp' and 'setFanSpeed'
* (Black-Thunder) added more documentation

### 0.0.3 26.05.2020
* (Black-Thunder) added indicator if device is reachable
* (Black-Thunder) corrected role of "targetTemp", "power" and "deviceName"
Expand Down
61 changes: 59 additions & 2 deletions docs/de/melcloud.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,62 @@
### Einstellungen des Adapters
# MELCloud - Benutzerhandbuch

## Voraussetzungen

Um diesen Adapter korrekt verwenden zu können, müssen folgende Vorbereitungen getroffen werden:

* Mitsubishi Klimaanlage mit einem Wi-Fi-Adapter MAC-567IF (pro zu steuerndem Gerät einer nötig)
* MELCloud-Account unter der [offiziellen Website](https://app.melcloud.com/) angelegt
* Alle Klimageräte wurden im Account registriert und vollständig eingerichtet

## Konfiguration

![Einstellungen des Adapters](img/adapter_settings.png)

TODO
An dieser Stelle kann die jeweilige Adapter-Instanz konfiguriert werden. Zwingedn nötig für die Funktionalität sind die Zugangsdaten (E-Mail-Adresse und Passwort) des MELCloud-Accounts. Zusätzlich kann die Region des Accounts angegeben werden.
Zusätzlich wird hier das Intervall (in Minuten) angegeben, wie oft Daten von der MELCloud abgerufen und gespeichert werden sollen. Das kleinstmögliche Intervall ist eine Minute.

## Objekte

Nachdem die Adpater-INstanz (X) erfolgreich (=grün) gestartet wurde, werden die Geräte inklusive Daten aus der MELCloud abgerufen. Für jedes Gerät (Y) wird ein separater Objekt-Knoten angelegt.

### melcoud.X.info

| id | read | write | comment |
|--- |--- |--- |--- |
| connection | X | - | Gibt den Verbindungsstatus zur MELCloud an |

### melcloud.X.device.Y.info

| id | read | write | comment |
|--- |--- |--- |--- |
| actualFanSpeed | X | - | Tatsächliche Lüfterstufe im Automatikmodus |
| buildingId | X | - | Zugeordnete Gebäude-ID |
| canCool | X | - | Fähigkeit zu kühlen |
| canHeat | X | - | Fähigkeit zu heizen |
| canDry | X | - | Fähigkeit zu entfeuchten |
| deviceName | X | - | Name des Geräts |
| deviceOnline | X | - | Gibt an, ob das Gerät erreichbar ist |
| floorId | X | - | Zugeordnete Etagen-ID |
| lastCommunication | X | - | Zeitstempel der letzten Kommunikation (MELCloud -> Gerät) |
| minTempCoolDry | X | - | Minimale Temperatur (Kühlen/Entfeuchten) |
| maxTempCoolDry | X | - | Maximale Temperatur (Kühlen/Entfeuchten) |
| minTempHeat | X | - | Minimale Temperatur (Heizen) |
| maxTempHeat | X | - | Maximale Temperatur (Heizen) |
| minTempAuto | X | - | Minimale Temperatur (Automatik) |
| maxTempAuto | X | - | Maximale Temperatur (Automatik) |
| macAddress | X | - | MAC-Adresse des Geräts |
| nextCommunication | X | - | Zeitstempel der nächsten Kommunikation (MELCloud -> Gerät) |
| numberOfFanSpeeds | X | - | Anzahl der verfügbaren Lüfterstufen |
| roomTemp | X | - | Aktuelle Raumtemperatur |
| serialNumber | X | - | Seriennummer des Geräts |

### melcloud.X.device.Y.control

| id | read | write | comment |
|--- |--- |--- |--- |
| fanSpeed | X | X | Aktuelle Lüfterstufe des Geräts (0=Automatik, 1...'numberOfFanSpeeds'= minimale bis maximale Stufe) |
| mode | X | X | Betriebsmodus des Geräts (1=Heizen, 2=Entfeuchten, 3=Kühlen, 7=Lüften, 8=Automatik) |
| power | X | X | Hauptschalter (schaltet Gerät ein bzw. aus) |
| targetTemp | X | X | Zieltemperatur des Geräts |
| vaneHorizontalDirection | X | X | Aktuelle hoizontale Ausrichtung des Luftauslasses (0=Automatik, 1...5=minimal bis maximal, 12=Swing) |
| vaneVerticalDirection | X | X | Aktuelle vertikale Ausrichtung des Luftauslasses (0=Automatik, 1...5=minimal bis maximal, 12=Swing) |
32 changes: 26 additions & 6 deletions docs/en/melcloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

In order to use this adapter, there are a few things you have to prepare in advance:

* Mitsubishi air conditioning system with Wi-Fi-Adapter MAC-567IF
* Mitsubishi air conditioning system with Wi-Fi-Adapter MAC-567IF (per device you want to control)
* MELCloud account at the [official webpage](https://app.melcloud.com/)
* All devices registered and set-up in your MELCloud account

Expand All @@ -27,16 +27,36 @@ After successful start of the adapter instance (X) your devices are queried from

### melcloud.X.device.Y.info

TODO

| id | read | write | comment |
|--- |--- |--- |--- |
| actualFanSpeed | X | - | Actual fan speed when fan is set to auto mode |
| buildingId | X | - | Assigned building ID |
| canCool | X | - | Ability to cool |
| canHeat | X | - | Ability to heat |
| canDry | X | - | Ability to dry |
| deviceName | X | - | Name of the device |
| deviceOnline | X | - | Indicates if device is reachable |
| floorId | X | - | Assigned floor ID |
| lastCommunication | X | - | Last communication date/time (MELCloud to device) |
| minTempCoolDry | X | - | Minimal temperature (Cool/Dry) |
| maxTempCoolDry | X | - | Maximal temperature (Cool/Dry) |
| minTempHeat | X | - | Minimal temperature (Heat) |
| maxTempHeat | X | - | Maximal temperature (Heat) |
| minTempAuto | X | - | Minimal temperature (Auto) |
| maxTempAuto | X | - | Maximal temperature (Auto) |
| macAddress | X | - | MAC address of the device |
| nextCommunication | X | - | Next communication date/time (MELCloud to device) |
| numberOfFanSpeeds | X | - | Number of available fan speeds |
| roomTemp | X | - | Current room temperature |
| serialNumber | X | - | Serial number of the device |

### melcloud.X.device.Y.control

TODO

| id | read | write | comment |
|--- |--- |--- |--- |
| fanSpeed | X | X | Current fan speed of your device (0=auto, 1...'numberOfFanSpeeds'= low to max fan speed) |
| fanSpeed | X | X | Current fan speed of the device (0=Auto, 1...'numberOfFanSpeeds'= low to max fan speed) |
| mode | X | X | Operation mode of the device (1=Heat, 2=Dry, 3=Cool, 7=Vent, 8=Auto) |
| power | X | X | Power switch (turns device on/off) |
| targetTemp | X | X | Target temperature of the device |
| vaneHorizontalDirection | X | X | Current horizontal direction of the device's vane (0=Auto, 1...5=min to max, 12=Swing) |
| vaneVerticalDirection | X | X | Current vertical direction of the device's vane (0=Auto, 1...5=min to max, 7=Swing) |
2 changes: 1 addition & 1 deletion io-package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"common": {
"name": "melcloud",
"version": "0.0.3",
"version": "0.0.3-alpha2",
"news": {
"0.0.3": {
"en": "added indicator if device is reachable\ncorrected role of 'targetTemp', 'power' and 'deviceName'\nadded new states 'macAddress' and 'actualFanSpeed' (indicates fan speed when running in auto mode)\nadded translations",
Expand Down
1 change: 0 additions & 1 deletion lib/commonDefines.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ exports.AdapterDatapointIDs = Object.freeze({
exports.AdapterStateIDs = Object.freeze({
// info
Connection: "connection",
ContextKey: "contextKey",
// device.XXX.info
DeviceName: "deviceName",
SerialNumber: "serialNumber",
Expand Down
101 changes: 92 additions & 9 deletions lib/melcloudDevice.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ class MelcloudDevice {
this.vaneHorizontalDirection = 0;
}

async Save() {
// Creates all necessery states and channels and writes the values into the DB
async CreateAndSave() {
//// INFO
let infoPrefix = commonDefines.AdapterDatapointIDs.Devices + "." + this.id + "." + commonDefines.AdapterDatapointIDs.Info;
await gthat.setObjectNotExistsAsync(infoPrefix, {
Expand Down Expand Up @@ -395,15 +396,17 @@ class MelcloudDevice {
});
await gthat.setStateAsync(controlPrefix + commonDefines.AdapterStateIDs.Mode, this.operationMode, true);

const minTemp = Math.min(this.minTempAuto, this.minTempCoolDry, this.minTempHeat);
const maxTemp = Math.max(this.maxTempAuto, this.maxTempCoolDry, this.maxTempHeat);
await gthat.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.TargetTemp, {
type: "state",
common: {
name: "Target temperature",
type: "number",
role: "level.temperature",
unit: this.platform.UseFahrenheit ? "°F" : "°C",
min: 10,
max: 40,
min: minTemp,
max: maxTemp,
read: true,
write: true,
desc: "Target temperature of the device"
Expand Down Expand Up @@ -485,10 +488,49 @@ class MelcloudDevice {
native: {}
});
await gthat.setStateAsync(controlPrefix + commonDefines.AdapterStateIDs.VaneHorizontalDirection, this.vaneHorizontalDirection, true);
//// END CONTROL

gthat.log.debug("Created and saved device " + this.id + " (" + this.name + ")");
}

// Only writes changed data into the DB
async Update() {
//// INFO
const infoPrefix = commonDefines.AdapterDatapointIDs.Devices + "." + this.id + "." + commonDefines.AdapterDatapointIDs.Info + ".";

await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.DeviceName, this.name, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.SerialNumber, this.serialNumber, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MacAddress, this.macAddress, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.BuildingId, this.buildingId, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.FloorId, this.floorId, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.CanCool, this.canCool, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.CanHeat, this.canHeat, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.CanDry, this.canDry, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MinTempCoolDry, this.minTempCoolDry, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MaxTempCoolDry, this.maxTempCoolDry, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MinTempHeat, this.minTempHeat, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MaxTempHeat, this.maxTempHeat, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MinTempAuto, this.minTempAuto, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.MaxTempAuto, this.maxTempAuto, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.RoomTemp, this.roomTemp, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.FanSpeedAuto, this.actualFanSpeed, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.NumberOfFanSpeeds, this.numberOfFanSpeeds, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.LastCommunication, this.lastCommunication, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.NextCommunication, this.nextCommunication, true);
await gthat.setStateChangedAsync(infoPrefix + commonDefines.AdapterStateIDs.DeviceOnline, this.deviceOnline, true);
//// END INFO

//// CONTROL
const controlPrefix = commonDefines.AdapterDatapointIDs.Devices + "." + this.id + "." + commonDefines.AdapterDatapointIDs.Control + ".";
await gthat.setStateChangedAsync(controlPrefix + commonDefines.AdapterStateIDs.Power, this.power, true);
await gthat.setStateChangedAsync(controlPrefix + commonDefines.AdapterStateIDs.Mode, this.operationMode, true);
await gthat.setStateChangedAsync(controlPrefix + commonDefines.AdapterStateIDs.TargetTemp, this.targetTemp, true);
await gthat.setStateChangedAsync(controlPrefix + commonDefines.AdapterStateIDs.FanSpeedManual, this.fanSpeed, true);
await gthat.setStateChangedAsync(controlPrefix + commonDefines.AdapterStateIDs.VaneVerticalDirection, this.vaneVerticalDirection, true);
await gthat.setStateChangedAsync(controlPrefix + commonDefines.AdapterStateIDs.VaneHorizontalDirection, this.vaneHorizontalDirection, true);
//// END CONTROL

gthat.log.debug("Saved device: " + this.id + " (" + this.name + ")");
gthat.log.debug("Updated device data for device " + this.id + " (" + this.name + ")");
}

getDeviceInfo(callback, deviceOption, value) {
Expand Down Expand Up @@ -533,6 +575,8 @@ class MelcloudDevice {
gthat.log.info("Changing device option '" + deviceOption.id + "' to '" + (value.value ? value.value : value) + "'...");
const r = gthis.airInfo;

value = gthis.verifyDeviceOptionValue(deviceOption, value);

if (deviceOption == commonDefines.DeviceOptions.TargetHeatingCoolingState) {
switch (value) {
case commonDefines.DeviceOperationModes.OFF:
Expand Down Expand Up @@ -572,10 +616,6 @@ class MelcloudDevice {
r.EffectiveFlags = commonDefines.DeviceOptions.TargetTemperature.effectiveFlags;
}
else if (deviceOption == commonDefines.DeviceOptions.FanSpeed) {
if(value > r.NumberOfFanSpeeds) {
gthat.log.info("Fan speed limited to " + r.NumberOfFanSpeeds + " because device can't handle more than that!");
value = r.NumberOfFanSpeeds;
}
r.SetFanSpeed = value;
r.EffectiveFlags = commonDefines.DeviceOptions.FanSpeed.effectiveFlags;
}
Expand Down Expand Up @@ -624,10 +664,53 @@ class MelcloudDevice {
gthis.vaneVerticalDirection = jsonObject.VaneVertical;
gthis.vaneHorizontalDirection = jsonObject.VaneHorizontal;
gthis.deviceOnline = !jsonObject.Offline;
gthis.Save(); // write updated values
gthis.Update(); // write updated values
}
});
}

verifyDeviceOptionValue(deviceOption, value) {
switch(deviceOption)
{
case commonDefines.DeviceOptions.FanSpeed:
if(value > gthis.numberOfFanSpeeds) {
gthat.log.info("Fan speed limited to " + gthis.numberOfFanSpeeds + " because device can't handle more than that!");
return gthis.numberOfFanSpeeds;
}
return value;
case commonDefines.DeviceOptions.TargetTemperature:
let min, max;
switch (gthis.operationMode) {
case commonDefines.DeviceOperationModes.COOL.value:
case commonDefines.DeviceOperationModes.DRY.value:
min = gthis.minTempCoolDry;
max = gthis.maxTempCoolDry;
break;
case commonDefines.DeviceOperationModes.HEAT.value:
min = gthis.minTempHeat;
max = gthis.maxTempHeat;
break;
case commonDefines.DeviceOperationModes.AUTO.value:
min = gthis.minTempAuto;
max = gthis.maxTempAuto;
break;
default:
min = gthis.platform.UseFahrenheit ? 60 : 16;
max = gthis.platform.UseFahrenheit ? 104 : 40;
break;
}
if (value < min) {
value = min;
gthat.log.info("SetTemperature limited to " + min + " because device can't handle lower than that!");
}
else if (value > max) {
value = max;
gthat.log.info("SetTemperature limited to " + max + " because device can't handle more than that!");
}
return value;
default: return value;
}
}
}

exports.MelCloudDevice = MelcloudDevice;
6 changes: 3 additions & 3 deletions lib/melcloudPlatform.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class MelcloudPlatform {
}
}

async SaveDevices(newDevices) {
async CreateAndSaveDevices(newDevices) {
gthat.log.info("Saving device data...");
const currentDeviceIDs = gthat.getCurrentKnownDeviceIDs();
const newDeviceIDs = [];
Expand All @@ -192,9 +192,9 @@ class MelcloudPlatform {
for (let d = 0; d < newDevices.length; d++) {
const device = newDevices[d];
if (!deviceIDsToAdd.includes(device.id)) {
gthat.log.debug("Device already known: " + device.id + " (" + device.name + ")");
gthat.log.silly("Device already known: " + device.id + " (" + device.name + ")");
}
await device.Save();
await device.CreateAndSave();
}
}
}
Expand Down
Loading

0 comments on commit 77627e4

Please sign in to comment.