I worked on a very quick n dirty script to make it work with the MQTT Cover integration. It connects to the websocket port of maveo and runs commands over it. Docs on Maveo API is here but my god it’s awful.
This will most likely NOT work on your setup since the IDs could be very different, but I wanted to share it as a starting point in case anyone wants to build something useful. You also need a token which you can get from nymea-cli (note: my default port was 2223)
What SHOULD happen is that one must call Integrations.GetThings and find the garage door IDs from there, then retrieving stateTypeId and actionTypeId, but I am beyond lazy.
This covers all the requirements, including notifications of open/close/opening/closing, etc since it’s using JSONRPC websockets.
Once again, I whipped this up in like an hour, so the code is miserable and I really didn’t have time to clean it up, but I hope it helps anyone out there!
configuration.yaml
cover:
- platform: mqtt
name: "Garage Door"
command_topic: "home-assistant/garage/set"
state_topic: "home-assistant/garage/state"
retain: true
device_class: "garage"
NodeJS code that needs to run in background
var WebSocketClient = require('websocket').client;
var mqtt = require('mqtt')
var client = new WebSocketClient();
let maveoIP = "<MAVEO IP>"; //maveo box IP
let mqttIP = "<MQTT IP>"; //MQTT IP
let token = "<TOKEN>"; //get this from nymea-cli
let garageID = "<DEVICE ID>"; //get this deviceId from Devices.GetConfiguredDevices (see below)
let garageClassID = "{ca6baab8-3708-4478-8ca2-7d4d6d542937}"; //get this deviceClassId from Devices.GetConfiguredDevices. Not used now but you'll need it for GetActionTypes and GetStateTypes if you have to get their IDs
client.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
});
//putting those here for MQTT
let open = {
id: 6,
method: "Actions.ExecuteAction",
params: {
actionTypeId: "{5a1a68cb-a5ef-4bc9-8672-bc067b6c4d48}", //NOTE: this could be different on your setup. You can get it from Devices.GetActionTypes (pass in param deviceClassId)
deviceId: garageID
},
token: token,
}
let close = {
id: 7,
method: "Actions.ExecuteAction",
token: token,
params: {
actionTypeId: "{6a32c34f-763d-4065-acfc-2b88bfd9eb34}", //NOTE: this could be different on your setup. You can get it from Devices.GetActionTypes (pass in param deviceClassId)
deviceId: garageID
}
}
let stop = {
id: 8,
method: "Actions.ExecuteAction",
token: token,
params: {
actionTypeId: "{fcb767de-e8d7-43da-ab21-17afea7eba24}", //NOTE: this could be different on your setup. You can get it from Devices.GetActionTypes (pass in param deviceClassId)
deviceId: garageID
}
}
//need this here for MQTT part to access send()
let send = undefined;
client.on('connect', function(connection) {
send = (obj) => {
if (connection.connected) {
console.log("=>", obj);
connection.sendUTF(JSON.stringify(obj));
}
else {
console.log("Not connected");
}
}
let getDoorState = () => {
send({
"id": 1, //I've reserved 1 for door state so I can handle it in the websocket response.
"method": "Devices.GetStateValue",
token: token,
params: {
deviceId: garageID,
stateTypeId: "{6f113f20-11ed-4f69-bda5-449363ab71d0}" //NOTE: this could be different on your setup. You can get it from Devices.GetStateTypes (pass in param deviceClassId)
}
})
}
let getMethod = (method, params) => {
send({
"id": 2,
"method": method,
token: token,
params
})
}
console.log('WebSocket Client Connected');
connection.on('error', function(error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function() {
console.log('Connection Closed');
});
connection.on('message', function(message) {
if (message.type === 'utf8') {
let obj = JSON.parse(message.utf8Data);
if (obj.id == 0) {
getDoorState();
// getStates();
}
else if (obj.id == 1) {
//report door state
report(obj.params.value);
}
else if (obj.notification) {
//NOTE: stateTypeId might be different on your setup.
if (obj.notification == "Devices.StateChanged" && obj.params.stateTypeId == "{6f113f20-11ed-4f69-bda5-449363ab71d0}") {
//report door state
report(obj.params.value);
}
}
else {
//just print it out
console.dir(obj, {depth: null});
}
}
});
let hello = {
"id": 0,
"method": "JSONRPC.Hello",
"params": {
"locale": "en_US"
}
}
send(hello);
//enable notifications of open/opening/etc on this websocket.
getMethod("JSONRPC.SetNotificationStatus", {enabled: true});
//start here to get your device IDs
// getMethod("Devices.GetConfiguredDevices");
});
client.connect(`ws://${maveoIP}:4445/`);
//MQTT part
var c = mqtt.connect(`mqtt://${mqttIP}`)
c.on('connect', function () {
//listen to commands from Home Assistant
c.subscribe('home-assistant/garage/set', function (err) {
if (err) {
console(err);
}
})
})
c.on('message', function (topic, message) {
//make sure the send function is available
if (!send) return;
// message is Buffer
let msg = message.toString();
console.log(msg)
switch (msg) {
case "OPEN":
send(open);
break;
case "CLOSE":
send(close);
break;
case "STOP":
send(stop);
break;
default:
break;
};
})
//report garage state to Home Assistant
function report(state) {
console.log(state);
//there is no 'intermediate' state in HA
if (state == "intermediate") {
state = "open";
}
c.publish('home-assistant/garage/state', state);
}