Skip to content

Instantly share code, notes, and snippets.

@okets
Last active August 29, 2024 16:01
Show Gist options
  • Save okets/b2bdf3ba2ab96c27ad58274372298261 to your computer and use it in GitHub Desktop.
Save okets/b2bdf3ba2ab96c27ad58274372298261 to your computer and use it in GitHub Desktop.
figure out the room Valetudo robot is right now.
const mapData = msg.payload;
const _pixelSize = mapData.pixelSize;
let _robotXY = null;
for (let i = 0; i < mapData.entities.length; i++) {
if (mapData.entities[i].type == "robot_position") {
_robotXY = {
x: Math.floor(mapData.entities[i].points[0] / _pixelSize),
y: Math.floor(mapData.entities[i].points[1] / _pixelSize)
};
break;
}
}
// Test Data
// _robotXY = {
// x: 1000,
// y: 1000
// };
const _nearestPoint = {
x: mapData.size.x,
y: mapData.size.y,
distance: Math.pow(mapData.size.x,2) + Math.pow(mapData.size.y,2), //Just a placeholder with the biggest distance possible
foundRoom:{
segmentId: null,
name: null
}
}
if (mapData.metaData?.version === 2 && Array.isArray(mapData.layers)) {
mapData.layers.forEach(layer => {
if (layer.pixels.length === 0 && layer.compressedPixels.length !== 0 && layer.type == "segment") {
for (let i = 0; i < layer.compressedPixels.length; i = i + 3) {
const xStart = layer.compressedPixels[i];
const y = layer.compressedPixels[i + 1]
const count = layer.compressedPixels[i + 2]
for (let j = 0; j < count; j++) {
let x = xStart + j;
let _distanceX = x - _robotXY.x;
let _distanceY = y - _robotXY.y;
//const _pointToRobotDistance = Math.sqrt(Math.pow(_distanceX, 2) + Math.pow(_distanceY, 2));
const _pointToRobotDistance = Math.pow(_distanceX, 2) + Math.pow(_distanceY, 2);//sqrt is the "correct" trig function, but I only need to compare relative to other points, not exact distance, so I dropped the "sqrt" function for efficiancy
if (_nearestPoint.distance > _pointToRobotDistance){
_nearestPoint.distance = _pointToRobotDistance;
_nearestPoint.x = x;
_nearestPoint.y = y;
_nearestPoint.foundRoom= {
segmentId: layer.metaData.segmentId,
name: layer.metaData.name
};
}
if (_nearestPoint.distance==0) {
return;
}
}
}
}
})
}
return _nearestPoint.foundRoom;
@okets
Copy link
Author

okets commented Sep 26, 2023

The parsed data should be in:
robot_info: object

the object there contains my calculations output.
also, remember to update your robot to the latest valetudo version if you haven't already.

@killone78
Copy link

I dati analizzati dovrebbero essere in: robot_info: object

l'oggetto lì contiene l'output dei miei calcoli. inoltre, ricordati di aggiornare il tuo robot all'ultima versione di valetudo se non l'hai già fatto.

yes!!! {"state":"returning","battery_level":96,"main_brush_remaining":{"value":16860,"unit":"minutes"},"side_right_brush_remaining":{"value":6060,"unit":"minutes"},"main_filter_remaining":{"value":6060,"unit":"minutes"},"currentLocation":{"segmentId":"15","name":"Camera da letto"},"_linkSource":[]}

so every time I start the robot will the flow process the computation data or will it only do it when I start the timestamp node?

How can I view them in Home Assistant? Thanks a lot!

@okets
Copy link
Author

okets commented Sep 26, 2023

My code only calculates the robot's info, most importantly, it tells you where the robot is, the official API does not.
You can now call this in your own NodeRed automations and make decisions based on this information.
It's up to you and what you want to do with this information.

@killone78
Copy link

killone78 commented Sep 26, 2023

it tells you where the robot is, the official API does not.

And that's exactly what interests me... :)
To get the value of "currentLocation" and use it with home assistant automations do I have to create a new topic by adding an node mqtt out? but where should I connect it?

@okets
Copy link
Author

okets commented Sep 26, 2023

I am doing most of my automations in NodeRed, so I don't export this info to home assistant.
if you want to export this info to home assistant you can create a sensor, put my info in the sensors' attributes and publish it to home assistant.
You can do it in MQTT or using the node-red-contrib-home-assistant-websocket integration.
its out of the scope of this topic though, just research "Creating a sensor in home assistant using NodeRed".

@carefulcomputer
Copy link

carefulcomputer commented Sep 26, 2023

Good Morning Guys, I updated the code and removed the pako dependency. give it a shot and let me know if it solved your issues. https://github.com/okets/Valetudo-NodeRed-Extensions

Hi @okets , thanks for updating the code. I am bit puzzled by payload handling. In my case, I received a zipped payload, whereas in your code it expects an unzipped payload. Is it because of different versions of valetudo we are using ?

Edit: i think I know what is going on after studying your flow. In your flow, you are making a rest call to valetudo to fetch the data, in my case, I am listening to MQTT events published by valetudo. Valetudo sends the packed map info json, whereas when you make a rest call, it will return unzipped json.

@okets
Copy link
Author

okets commented Sep 27, 2023

@carefulcomputer you are right, the mqtt data is compressed (the data that is sent to homeassistant entities created by Valetudo).
In my custom card for the robot, the map data is still compressed.
I don't quite remember when they changed the API to return uncompressed data. I routinely update to the latest version and fix compatibility issues in my flows.

@killone78
Copy link

I am doing most of my automations in NodeRed, so I don't export this info to home assistant. if you want to export this info to home assistant you can create a sensor, put my info in the sensors' attributes and publish it to home assistant. You can do it in MQTT or using the node-red-contrib-home-assistant-websocket integration. its out of the scope of this topic though, just research "Creating a sensor in home assistant using NodeRed".

@okets Thanks for info, but I find it really difficult to understand how to do it, I'm really a node-red noob...^_^; in the end what I would like to do is simply publish via mqtt "currentLocation" with "segmentId": and "name":
Even if it has nothing to do with the purpose of this topic, could you help me? Thank you so much :)

@okets
Copy link
Author

okets commented Sep 27, 2023

@killone78, I wouldn't know where to start.
Your request sounds simple but it has some complexities.
My code isn't monitoring the robot's activity, it only tells you where it is at the moment you run it.
I can help you with guidelines:

  1. you should monitor the state of your robot.
  2. on any state change publish mqtt message with the location of the robot.
    2.1) if the robot is in a moving state (not "docked"/"error"/"paused") publish the position in a regular interval (5 sec. Seems fine)
    2.2) if its not moving, stop the interval.

In my opinion, it would be easier to just write whatever automation you are trying to write in homeassistant directly in NodeRed.
It is a much better automation engine and it can work alongside homeassistant's automation engine, you don't have to transfer existing automations.

@coxtor
Copy link

coxtor commented May 22, 2024

@carefulcomputer sorry for the delayed response. home with the flu... I uploaded my complete flow to this repo: https://github.com/okets/Valetudo-NodeRed-Extensions Feel free to add/change whatever you want.

This is so simple and brilliant thank you so much for this!

@web2brain
Copy link

Thanks for the script! With the help of NodeRed I made a small automation to disable obstacle recognition in a certain segment, that the robot can't pass with it enabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment