Skip to content

Commit

Permalink
Dev (#648)
Browse files Browse the repository at this point in the history
* Fix typo

* Add missing attributes S7 Max Ultra

* Update translations.json

* Add robotModel to errors where possible

* Add missing features to S7 Max Ultra

* Fix docking station status detection

* Adjust docking station states like the roborock app

* Update README.md

* Revert "Fix docking station status detection"

This reverts commit 3ee972d.

* Fix dss processing

* Improve dss handling

* Add support for remote devices outside of the network

* Fix remote device detection

* Update README.md

* Improve docking station feature handling
  • Loading branch information
copystring authored Sep 12, 2024
1 parent 2fdf4be commit be1d61e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 63 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ This feature only works when map creation is enabled in the adapter options!
### **WORK IN PROGRESS**
-->
### **WORK IN PROGRESS**
* (copystring) Bug fixes
* (copystring) Add basic support for S8 MaxV Ultra
* (copystring) Newly found attributes are now warning instead of error
* (copystring) Improve detection of `home_sec`
* (copystring) Fix docking station detection
* (copystring) BREAKING: Adjust docking station states to reflect the smart phone app
* (copystring) Detect remote devices and connect via mqtt instead
* (copystring) Improve docking station feature handling

### 0.6.12 (2024-09-08)
* (copystring) Change go2rtc github to go2rtc-static npm
Expand Down
2 changes: 1 addition & 1 deletion admin/i18n/en/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
"msg_ver": "Message Version",
"option1": "option1",
"option2": "",
"rdt": "???",
"rdt": "Remaining dry time",
"resetConsumables_description": "Consumables available for reset",
"reset_dust_collection_work_times": "Dust collection",
"reset_filter_element_work_time": "Filter element",
Expand Down
77 changes: 47 additions & 30 deletions lib/deviceFeatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ const dockTypes = {
9: "Empty Wash Fill Dry Dock (Q Revo Pro)",
};

const dockingStationStates = ["cleaning_solution", "water_filter", "dust_container", "dirty_water", "clean_water", "unknown"];

const firmwareFeatures = {
111: "isSupportFDSEndPoint",
Expand Down Expand Up @@ -288,6 +287,9 @@ const actions = {
set_monitor_status: () => {
deviceStates.monitor_status = "number";
},
set_clean_fluid: () => {
deviceStates.clean_fluid = "number";
}
};

class deviceFeatures {
Expand Down Expand Up @@ -413,13 +415,6 @@ class deviceFeatures {
deviceStates.corner_clean_mode = "number";
}

isDssBelievable() {
// process docking station states
for (const [, state] of Object.entries(dockingStationStates)) {
this.adapter.createDockingStationObject(this.duid, state);
}
}

isCameraSupported() {
deviceStates.distance_off = "number";
deviceStates.camera_status = "number";
Expand Down Expand Up @@ -573,7 +568,6 @@ class deviceFeatures {
isPhotoUploadSupported: !!(65536 & this.features),
isAvoidCollisionSupported: !!(134217728 & this.features),
isCornerCleanModeSupported: !!(2147483648 & this.features),
isDssBelievable: this.featuresStr && !!(131072 & parseInt("0x" + this.featuresStr.slice(-8))),
// isCameraSupported: [p.Products.TanosV_CN, p.Products.TanosV_CE, p.Products.TopazSV_CN, p.Products.TopazSV_CE, p.Products.TanosSV].hasElement(p.DMM.currentProduct),
isCameraSupported: !!["roborock.vacuum.a10", "roborock.vacuum.a27", "roborock.vacuum.a51", "roborock.vacuum.a87"].includes(this.model),
isSupportSetSwitchMapMode: !!(268435456 & this.features),
Expand Down Expand Up @@ -723,6 +717,9 @@ class deviceFeatures {
"set_back_type",
"set_charge_status",
"set_clean_percent",
"set_switch_status",
"set_clean_fluid",
"set_cleaned_area",
],
// S8 Pro Ultra
"roborock.vacuum.a70": [
Expand Down Expand Up @@ -913,27 +910,47 @@ class deviceFeatures {
}

processDockType(dockType) {
// for now this is needed for S7 only, a special case
if (this.model == "roborock.vacuum.a15") {
switch (dockType) {
case 0: // Charging dock
// nothing to do here
break;
case 1: // Auto-Empty Dock
this.isDustCollectionSettingSupported();
break;
case 2: // Empty Wash Fill Dock
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
break;
case 3: // Empty Wash Fill (Dry) Dock
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
this.isSupportedDrying();
break;
default:
break;
}
switch (dockType) {
case 0: // Charging dock
// nothing to do here
break;
case 1: // Auto-Empty Dock - Onyx: S7+/S7Plus (Empty Dock)
this.isDustCollectionSettingSupported();
break;
case 2: // Empty Wash Fill Dock - Onyx2: G10
this.isWashThenChargeCmdSupported();
break;
case 3: // Empty Wash Fill (Dry) Dock - Onyx3: S7 Pro, MaxV Ultra
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
this.isSupportedDrying();
break;
case 5: // Onyx-C: S8, S8 Plus, Q8, Q8 Max
this.isDustCollectionSettingSupported();
break;
case 6: // Onyx3 Plus: S7 Max Ultra
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
this.isSupportedDrying();
break;
case 7: // Onyx4: S8 Pro Ultra
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
this.isSupportedDrying();
break;
case 8: // PEARL: Q Revo, P10
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
this.isSupportedDrying();
break;
// Not much info on this one. Might be missing some features
case 9: // Unknown codename for now: Q Revo Pro
this.isDustCollectionSettingSupported();
this.isWashThenChargeCmdSupported();
this.isSupportedDrying();
break;
default:
break;
}
}

Expand Down
4 changes: 3 additions & 1 deletion lib/localConnector.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ class localConnector {
reject(error);
});
}).catch((error) => {
this.adapter.catchError(`Failed to create tcp client: ${error.stack}`, `function createClient`, duid);
this.adapter.log.info(`error on tcp client for ${duid}. Marking this device as remote device. Connecting via MQTT instead ${error.message}`);
this.adapter.remoteDevices.add(duid);
// this.adapter.catchError(`Failed to create tcp client: ${error.stack}`, `function createClient`, duid);
});

client.on("data", async (message) => {
Expand Down
31 changes: 16 additions & 15 deletions lib/vacuum.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class vacuum {
}
}
} catch (error) {
this.adapter.catchError(error, "get_map_v1", duid);
this.adapter.catchError(error, "get_map_v1", duid), this.robotModel;
}
}
}
Expand All @@ -118,7 +118,7 @@ class vacuum {
mapData: JSON.stringify(parsedData),
};
} catch (error) {
this.adapter.catchError(error, "get_clean_record_map", duid);
this.adapter.catchError(error, "get_clean_record_map", duid, this.robotModel);

return null;
}
Expand Down Expand Up @@ -215,7 +215,7 @@ class vacuum {
}
}
} catch (error) {
this.adapter.catchError(error, parameter, duid);
this.adapter.catchError(error, parameter, duid, this.robotModel);
}
}

Expand Down Expand Up @@ -259,7 +259,7 @@ class vacuum {

if (!(await this.adapter.getObjectAsync(`Devices.${duid}.deviceStatus.${attribute}`))) {
this.adapter.log.warn(
`Unsported attribute: ${attribute} of get_status with value ${deviceStatus[0][attribute]}. Please contact the dev to add the newly found attribute of your robot. Model: ${this.robotModel}`
`Unsupported attribute: ${attribute} of get_status with value ${deviceStatus[0][attribute]}. Please contact the dev to add the newly found attribute of your robot. Model: ${this.robotModel}`
);
continue; // skip unsupported attributes
}
Expand All @@ -278,6 +278,7 @@ class vacuum {
this.adapter.vacuums[duid].features.processDockType(attribute);
break;
case "dss":
await this.adapter.createDockingStationObject(duid);
const dockingStationStatus = await this.parseDockingStationStatus(deviceStatus[0][attribute]);

for (const state in dockingStationStatus) {
Expand Down Expand Up @@ -424,7 +425,7 @@ class vacuum {

this.unzipBuffer(photoresponse, (error, photoData) => {
if (error) {
this.adapter.catchError(error, "get_photo", duid);
this.adapter.catchError(error, "get_photo", duid, this.robotModel);

if (this.adapter.supportsFeature && this.adapter.supportsFeature("PLUGINS")) {
if (this.adapter.sentryInstance) {
Expand Down Expand Up @@ -483,14 +484,14 @@ class vacuum {
// this.adapter.setStateAsync("Devices." + duid + "." + targetFolder + "." + mode, { val: attribute_val[0], ack: true });
if (typeof unknown_parameter_val == "object") {
if (typeof unknown_parameter_val[0] != "number") {
this.adapter.catchError(`Unknown parameter: ${JSON.stringify(unknown_parameter_val)}`, parameter, duid);
this.adapter.catchError(`Unknown parameter: ${JSON.stringify(unknown_parameter_val)}`, parameter, duid, this.robotModel);
}
} else {
this.adapter.catchError(`Unknown parameter: ${unknown_parameter_val}`, parameter, duid);
this.adapter.catchError(`Unknown parameter: ${unknown_parameter_val}`, parameter, duid, this.robotModel);
}
}
} catch (error) {
this.adapter.catchError(error, parameter, duid);
this.adapter.catchError(error, parameter, duid, this.robotModel);
}
}

Expand All @@ -510,12 +511,12 @@ class vacuum {
async parseDockingStationStatus(dss) {

return {
cleaning_solution: (dss >> 10) & 0b11,
water_filter: (dss >> 8) & 0b11,
dust_container: (dss >> 6) & 0b11,
dirty_water: (dss >> 4) & 0b11,
clean_water: (dss >> 2) & 0b11,
unknown: dss & 0b11,
cleanFluidStatus: (dss >> 10) & 0b11,
waterBoxFilterStatus: (dss >> 8) & 0b11,
dustBagStatus: (dss >> 6) & 0b11,
dirtyWaterBoxStatus: (dss >> 4) & 0b11,
clearWaterBoxStatus: (dss >> 2) & 0b11,
isUpdownWaterReady: dss & 0b11,
};
}
async getCleanSummary(duid) {
Expand Down Expand Up @@ -562,7 +563,7 @@ class vacuum {
}
}
} catch (error) {
this.adapter.catchError(error, "get_clean_summary", duid);
this.adapter.catchError(error, "get_clean_summary", duid, this.robotModel);
}
}

Expand Down
38 changes: 22 additions & 16 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const deviceFeatures = require("./lib/deviceFeatures").deviceFeatures;
const messageQueueHandler = require("./lib/messageQueueHandler").messageQueueHandler;
let socketServer, webserver;

const dockingStationStates = ["cleanFluidStatus", "waterBoxFilterStatus", "dustBagStatus", "dirtyWaterBoxStatus", "clearWaterBoxStatus", "isUpdownWaterReady"];

class Roborock extends utils.Adapter {
/**
* @param {Partial<utils.AdapterOptions>} [options={}]
Expand Down Expand Up @@ -54,6 +56,7 @@ class Roborock extends utils.Adapter {
this.pendingRequests = new Map();

this.localDevices = {};
this.remoteDevices = new Set();
}

/**
Expand Down Expand Up @@ -622,8 +625,9 @@ class Roborock extends utils.Adapter {
if (homedata && typeof homedata.val == "string") {
const homedataJSON = JSON.parse(homedata.val);
const receivedDevice = homedataJSON.receivedDevices.find((device) => device.duid == duid);
const remoteDevice = this.remoteDevices.has(duid);

if (receivedDevice) {
if (receivedDevice || remoteDevice) {
return true;
}

Expand Down Expand Up @@ -965,22 +969,24 @@ class Roborock extends utils.Adapter {
});
}

async createDockingStationObject(duid, state) {
const path = `Devices.${duid}.dockingStationStatus.${state}`;
const name = this.translations[state];
async createDockingStationObject(duid) {
for (const state of dockingStationStates) {
const path = `Devices.${duid}.dockingStationStatus.${state}`;
const name = this.translations[state];

this.setObjectAsync(path, {
type: "state",
common: {
name: name,
type: "number",
role: "value",
read: true,
write: false,
states: { 0: "UNKNOWN", 1: "ERROR", 2: "OK" },
},
native: {},
});
this.setObjectNotExistsAsync(path, {
type: "state",
common: {
name: name,
type: "number",
role: "value",
read: true,
write: false,
states: { 0: "UNKNOWN", 1: "ERROR", 2: "OK" },
},
native: {},
});
}
}

async createConsumable(duid, state, type, states, unit) {
Expand Down

0 comments on commit be1d61e

Please sign in to comment.