Skip to content

Instantly share code, notes, and snippets.

@okets
Last active May 22, 2024 20:51
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 16, 2022

Hi @Hypfer,
I made the function more efficient and tested it with "holes" and even robot positions outside the map.
It works 100% of the time, I don't see how it would fail.

  • If the robot is positioned in a zone, it will 100% give you the zone (with distance 0).
  • If the robot is in an empty spot, it will look for the nearest point of all zones and get you the zone nearest to the robot.
    If the "hole" is in the middle of a zone, obviously it will return the correct Zone.
    If the "hole" is in the border between zones (extremely rare) it will report the zone that is closest to the robot.

My logic is sound and tested.
I hope you reconsider adding this to the official API, getting the Robot's current location will be helpful to a lot of people.

@Kisty
Copy link

Kisty commented Dec 1, 2022

Would be a great feature (I thought it would already know its current segment). This sort of thing seems like a solved problem in computer science. Could be a case of using fuzzy logic or some other algo to compute it.

As a basic fix: what if you were to debounce/poll the segment every 30s or a minute so that if the robot thinks it's going to another segment, it would check after a given timeframe if it's in the same new segment then report that as the new segment? That would counter any issues with holes.

@Hypfer
Copy link

Hypfer commented Dec 1, 2022

I hope you reconsider adding this to the official API, getting the Robot's current location will be helpful to a lot of people.

Would be a great feature

Yes, no one ever questioned that.
As I said multiple times now, the issue is that given that it just approximates data, there will be some unexpected breakage.
If not now then further down the line. Maybe in a few months? Maybe in three years?.

Someone is going to be responsible to fix those bugs and that someone is not going to be any of the users that requested said feature.
As I also said many times now, I am not interested in being that someone.

Again: I'm not saying that it's a bad idea.
I just don't want to be responsible for it and any issues/support requests that come with it. You need to accept that.

What users need to understand is that no means no.
It does not mean

  • please guilt-trip me into doing what you want
  • please just ask the same thing over and over again until I say yes
  • please find any execute any other way of pressuring me into doing what you want

Even if this was closed-source software, that kind of behavior would be abusive.
However here it's even worse, because there's both an open API and Open Source.
Anyone desperately wanting that feature could either layer it on top of the API or just patch the code and run a patched build.

Of course that would mean that they're then also responsible for keeping it working, which is something people even have complained about before. While doing that, they did not realize (or care) that the same pain they've felt there would've been my pain if I would've added such a functionality.

@okets
Copy link
Author

okets commented Dec 1, 2022

Hello @Hypfer,
I appreciate your work and am thankful for what you have accomplished.
I don't know who you are addressing with this comment, if it was me that upset you, my sincere apologies.

Please allow me to pass my input as I consider myself a possible contributor:

  • I will never try to impose; I shared a piece of code that I wrote and thought to contribute back.
  • I didn't try to contribute it because I understood that your no means no. I actively read your code and tried to open a conversation. had it been more open, I would have loved to join the project.
  • One last comment (I hope you won't take it as guilt tripping you into adding it), API endpoints can be flagged as experimental until they prove themselves reliable, developers know what experimental means.

I know how to code, and I don't really need my suggestions implemented. I already have them up and running.
In fact, I built a whole lot of functionality using that piece of code.

valetudo
valetudo 2

I did way more than improving the GUI, I added a set of capabilities around the robot's location.
I used to work on the F35 jet fighter, calculating 2D coordinates of a vacuum cleaner isn't rocket science.

@carefulcomputer
Copy link

@okets , thanks for creating this code. Would love to see if you can publish it as a repo. I have similar needs (to find the room robot is in) and would love to use this feature. IMHO Having a separate git repo will solve it for all. People who want it can get it from your repo and some folks might even contribute further. WDYT ?

@carefulcomputer
Copy link

carefulcomputer commented Feb 24, 2023

@okets , I see that you are using node-red in your code. When I popped your code in NR, it didn't work out of the box. I had to decode the payload buffer.
For it to work I had to 'inflate' the payload before feeding it to the function. Here is what i did

  1. Make sure to filter mqtt messages topic (using switch node) to match the topic of message to 'homeassistant/[your robot name]/MapData/map-data'. Make sure it matches the topic exactly. There is another similar topic which sends png image as payload for home assistant consumption. You do not want to get that message.
  2. Create a function node which receives input from above switch node.
  3. Add package 'pako' in function node's 'setup' section
    image
  4. Copy paste above code into function node and then replaced first line of function like this
//const mapData = msg.payload;
const mapData = JSON.parse(pako.inflate(msg.payload, { to: 'string' }));

Now output of this function node can be used as you desire. It contains both the segment Id and name of segment. For me, I am feeding it to a HA sensor state.
Then based on the that sensor state you can do more automations (like track which rooms were cleaned, or turn mop/carpet feature when it reaches a certain room)

Hopefully it helps other folks who are looking for same solution.

@okets
Copy link
Author

okets commented Feb 24, 2023

Hi @carefulcomputer,

I'm glad to hear that you were able to use my code. Just to clarify, my intention was to contribute it to the official API, not for external use in node red.

Unfortunately, the owner of the project, Hypfer, strongly objected to the idea so I had to drop it. I don't have the time to fork Valetudo and continue maintaining it. I just wanted to share a code I wrote back to the project.

However, I'm confident that the code is working well since I've been using it for a long time. If you encounter any issues, please let me know.

I hope you enjoy using it!

@carefulcomputer
Copy link

@okets my request was for not forking valetudo , but creating a new repo with just your code instead of it being a gist. That way other folks can add/suggest more details/improvements. Like current version of valetudo seem to send compressed map whereas your code assumes it is not (which was probably true in earlier versions). I will be happy to create a public repo with your permissions (and giving credits to you), if you do not have time.

@carefulcomputer
Copy link

@okets ?

@okets
Copy link
Author

okets commented Feb 28, 2023

@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.

@carefulcomputer
Copy link

@okets apologies for the nag. I hope you are feeling better now.

@carefulcomputer
Copy link

And thanks for creating the repo !

@killone78
Copy link

@okets thanks for your code, but I can't get it to work, if you could help me I would be grateful.
I imported the flow (json) from your public repo, changed IP address
but when I start the switch timestamp I have the following error : node: Get Robot Info
msg : string[31]
"Missing return node information"
Could you help me? what I'm interested in is getting the ID and name of the room where the robot is located to create an automation in home assistant that notifies me when the cleaning of each individual room is finished.. Thanks a lot :)

@carefulcomputer
Copy link

carefulcomputer commented Sep 24, 2023

@killone78 , try this and let me know if this works..
Before you use this node, you will need to import 'pako' in 'setup' tab of function node.
After you give it a try, please confirm if this worked for you.

// parse map and find segment and location of robot
const mapData = JSON.parse(pako.inflate(msg.payload, { to: 'string' }));

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;
    }
}

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;
                    }
                }
            }
        }
    })
}
msg.foundLocation = _nearestPoint;
return msg;

@killone78
Copy link

@carefulcomputer I'm not very familiar with nodered, I have to modify the function node Locate Robot Segment & extract States with your code right? I have nodered installed in home assistant as an add-on, how do I add pako? It's not there in Manage Palette-install. Thanks for your help

@okets
Copy link
Author

okets 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

@killone78
Copy link

killone78 commented Sep 26, 2023

@okets Thanks!!! I imported the json stream changed Robot_IP but now how do I start it to test it? timestamp is no longer there. Sorry if it's a stupid question but I don't know node-red...I'm trying to use it just for your code :) Also how do I integrate it into home assistant?

@okets
Copy link
Author

okets commented Sep 26, 2023

just add an inject node and a debug node to a call link.
you can import this to get you started:

[
    {
        "id": "68210ec37d259197",
        "type": "link call",
        "z": "9f65cbcec408475d",
        "name": "",
        "links": [
            "88d70eed23d2244a"
        ],
        "linkType": "static",
        "timeout": "30",
        "x": 2040,
        "y": 1940,
        "wires": [
            [
                "621873f956d45dec"
            ]
        ]
    },
    {
        "id": "c2be63af5597ec74",
        "type": "inject",
        "z": "9f65cbcec408475d",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 1840,
        "y": 1940,
        "wires": [
            [
                "68210ec37d259197"
            ]
        ]
    },
    {
        "id": "621873f956d45dec",
        "type": "debug",
        "z": "9f65cbcec408475d",
        "name": "result",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 2230,
        "y": 1940,
        "wires": []
    }
]

@killone78
Copy link

msg : Object
object
_msgid: "99934942dcd05226"
payload: 1695721029654
topic: ""
originalPayload: null
statusCode: 200
headers: object
responseUrl: "http://192.168.1.122/api/v2/robot/state"
redirectList: array[0]
retry: 0
robot_info: object
_event: "node:82edb3154bea08ce"

@killone78
Copy link

"http://192.168.1.122/api/v2/robot/state" show this: {"__class":"RobotState","metaData":{"version":1},"attributes":[{"__class":"AttachmentStateAttribute","metaData":{},"type":"dustbin","attached":true},{"__class":"AttachmentStateAttribute","metaData":{},"type":"watertank","attached":false},{"__class":"AttachmentStateAttribute","metaData":{},"type":"mop","attached":false},{"__class":"StatusStateAttribute","metaData":{},"value":"docked","flag":"none"},{"__class":"PresetSelectionStateAttribute","metaData":{},"type":"fan_speed","value":"max"},{"__class":"BatteryStateAttribute","metaData":{},"level":100,"flag":"charged"},{"__class":"PresetSelectionStateAttribute","metaData":{},"type":"water_grade","value":"high"},{"__class":"PresetSelectionStateAttribute","metaData":{},"type":"operation_mode","value":"vacuum"},{"__class":"ConsumableStateAttribute","metaData":{},"type":"brush","subType":"main","remaining":{"value":16860,"unit":"minutes"}},{"__class":"ConsumableStateAttribute","metaData":{},"type":"brush","subType":"side_right","remaining":{"value":6060,"unit":"minutes"}},{"__class":"ConsumableStateAttribute","metaData":{},"type":"filter","subType":"main","remaining":{"value":6060,"unit":"minutes"}},{"__class":"ConsumableStateAttribute","metaData":{},"type":"mop","subType":"main","remaining":{"value":8040,"unit":"minutes"}}],"map":{"__class":"ValetudoMap","metaData":{"vendorMapId":1615973578,"version":2,"nonce":"a35955e8-1fa1-4981-a7cf-1ef31efa18b7","totalLayerArea":484475},"size":{"x":4000,"y":4000},"pixelSize":5,"layers":[{"__class":"MapLayer","metaData":{"area":95150},"type":"floor","pixels":[],"dimensions":{"x":{"min":386,"max":539,"mid":463,"avg":472},"y":{"min":196,"max":459,"mid":328,"avg":326},"pixelCount":3806},"compressedPixels":[453,196,8,452,197,10,464,197,10,462,198,12,467,199,1,441,205,1,493,209,13,510,209,6,493,210,14,510,210,18,492,211,15,510,211,18,492,212,17,510,212,18,492,213,17,510,213,18,492,214,17,510,214,12,523,214,5,492,215,17,510,215,18,492,216,16,510,216,18,495,217,12,510,217,18,510,218,18,510,219,7,518,219,10,510,220,7,519,220,9,510,221,18,510,222,18,511,223,17,512,224,16,512,225,16,434,226,1,514,226,13,433,227,2,517,227,10,519,230,5,518,231,9,518,232,9,518,233,9,518,234,9,518,235,9,518,236,9,518,237,9,518,238,9,518,239,9,518,240,6,518,241,5,518,242,6,517,243,9,517,244,9,517,245,9,517,246,9,517,247,9,517,248,9,517,249,9,517,250,9,517,251,9,517,254,6,412,255,10,517,255,8,412,256,10,517,256,8,412,257,12,517,257,8,413,258,11,427,258,1,517,258,8,414,259,10,427,259,1,517,259,8,414,260,8,423,260,1,516,260,9,414,261,1,516,261,9,516,262,9,517,263,6,414,264,1,413,265,4,423,265,1,411,266,13,411,267,14,411,268,14,411,269,14,411,270,14,411,271,14,411,272,14,426,272,1,411,273,10,411,274,11,411,275,14,427,275,4,410,276,14,428,276,5,410,277,15,428,277,4,410,278,13,428,278,5,462,278,1,410,279,3,417,279,2,429,279,2,450,284,2,450,285,4,450,286,5,450,287,4,464,290,3,464,291,3,469,291,3,464,292,3,469,292,2,464,293,3,469,293,2,464,294,3,469,294,2,411,295,1,422,295,1,464,295,3,468,295,3,411,296,3,416,296,1,422,296,3,427,296,1,468,296,3,411,297,7,422,297,6,464,297,6,411,298,6,422,298,5,464,298,5,414,299,3,421,299,6,428,299,2,462,299,6,414,300,3,421,300,8,415,301,1,421,301,8,421,302,3,425,302,5,429,303,1,416,304,1,421,304,3,429,304,1,416,305,6,423,305,4,428,305,2,500,305,2,414,306,13,428,306,2,500,306,6,414,307,13,428,307,2,499,307,7,414,308,13,428,308,2,495,308,1,498,308,10,423,309,5,495,309,13,405,310,3,409,310,4,414,310,2,422,310,3,494,310,15,404,311,11,420,311,6,494,311,16,404,312,23,494,312,16,403,313,24,494,313,16,404,314,23,494,314,16,408,315,17,495,315,15,513,315,1,518,315,1,410,316,15,495,316,13,512,316,7,412,317,12,495,317,1,497,317,22,406,318,4,412,318,15,499,318,20,404,319,23,501,319,2,506,319,12,400,320,27,508,320,1,511,320,1,400,321,15,416,321,11,400,322,15,416,322,11,497,322,1,499,322,1,399,323,16,416,323,10,496,323,4,416,324,10,462,324,4,496,324,6,462,325,4,496,325,6,462,326,4,496,326,6,462,327,4,496,327,1,499,327,3,500,328,2,465,332,1,465,333,1,463,334,3,498,334,2,463,335,3,494,335,2,497,335,3,463,336,3,493,336,7,493,337,6,493,338,4,491,339,4,512,339,2,530,339,8,460,340,2,490,340,6,507,340,1,509,340,7,523,340,1,529,340,9,460,341,1,490,341,5,503,341,1,505,341,33,460,342,1,490,342,5,503,342,37,487,343,1,492,343,6,503,343,37,492,344,48,490,345,50,460,346,1,490,346,50,460,347,1,490,347,50,490,348,50,489,349,51,489,350,51,489,351,51,489,352,51,489,353,51,489,354,51,489,355,51,489,356,51,489,357,51,489,358,51,489,359,51,502,360,38,510,361,6,517,361,23,510,362,1,512,362,4,517,362,23,515,363,1,517,363,1,523,363,17,526,364,14,532,365,7,536,366,3,538,367,1,399,381,4,399,382,4,410,382,5,399,383,4,410,383,2,413,383,2,417,383,5,399,384,4,408,384,7,417,384,6,398,385,9,408,385,3,417,385,5,456,385,1,478,385,1,395,386,12,408,386,3,413,386,5,420,386,1,478,386,1,394,387,8,403,387,4,408,387,1,410,387,1,413,387,5,478,387,1,394,388,8,404,388,5,413,388,5,478,388,1,386,389,5,394,389,8,405,389,5,413,389,5,434,389,3,386,390,6,394,390,8,405,390,5,413,390,5,434,390,3,475,390,3,386,391,6,394,391,1,406,391,4,413,391,6,434,391,3,442,391,1,444,391,1,386,392,6,419,392,1,434,392,3,386,393,6,421,393,1,386,394,6,473,394,4,386,395,6,473,395,4,386,396,6,473,396,4,386,397,6,473,397,4,386,398,6,393,398,1,473,398,4,388,399,4,393,399,2,474,399,1,388,400,4,393,400,2,473,400,3,387,401,5,393,401,3,472,401,5,386,402,6,393,402,3,472,402,4,386,403,5,393,403,3,472,403,4,386,404,5,393,404,3,472,404,4,386,405,5,393,405,4,485,405,3,386,406,5,393,406,5,484,406,4,495,406,1,386,407,5,392,407,7,451,407,5,484,407,4,493,407,2,386,408,5,392,408,7,452,408,5,464,408,8,473,408,5,483,408,5,493,408,2,386,409,5,392,409,7,451,409,6,465,409,7,473,409,5,484,409,1,493,409,2,386,410,5,392,410,7,452,410,1,455,410,2,465,410,7,473,410,5,386,411,5,392,411,7,470,411,2,386,412,4,395,412,3,428,412,2,471,412,1,386,413,5,396,413,2,427,413,3,386,414,8,396,414,2,386,415,8,396,415,2,386,416,8,396,416,2,426,416,4,390,417,4,396,417,3,426,417,4,390,418,4,396,418,3,426,418,4,391,419,3,395,419,4,426,419,5,391,420,3,395,420,12,426,420,5,391,421,3,395,421,4,426,421,5,391,422,3,395,422,3,426,422,5,391,423,3,395,423,2,408,423,1,426,423,5,391,424,3,395,424,2,408,424,1,427,424,4,391,425,3,395,425,2,408,425,2,428,425,3,394,426,3,408,426,1,394,427,3,394,428,3,394,429,3,391,430,6,391,431,6,391,432,6,391,433,6,391,434,6,391,435,6,391,436,6,391,437,6,391,438,6,391,439,6,474,439,3,391,440,6,473,440,4,391,441,6,473,441,4,473,442,1,475,442,1,391,443,5,391,444,5,391,445,5,422,448,3,422,449,4,422,450,4,421,451,4,421,452,4,472,452,1,474,452,1,421,453,4,467,453,1,472,453,5,421,454,4,454,454,7,472,454,5,421,455,4,456,455,5,472,455,5,421,456,5,421,457,9,421,458,10,421,459,3,425,459,3]},{"__class":"MapLayer","metaData":{"area":70650},"type":"wall","pixels":[],"dimensions":{"x":{"min":385,"max":540,"mid":463,"avg":454},"y":{"min":195,"max":460,"mid":328,"avg":329},"pixelCount":2826},"compressedPixels":[452,195,10,451,196,2,461,196,14,451,197,1,462,197,2,474,197,1,451,198,1,474,198,1,451,199,1,474,199,1,451,200,1,474,200,1,451,201,1,474,201,1,451,202,1,474,202,1,451,203,1,474,203,1,440,204,5,451,204,1,473,204,2,440,205,1,444,205,8,473,205,1,440,206,1,451,206,1,473,206,6,440,207,1,451,207,1,473,207,2,478,207,1,440,208,1,451,208,1,473,208,2,478,208,1,492,208,15,509,208,8,440,209,1,451,209,2,473,209,2,478,209,1,492,209,1,506,209,2,509,209,1,516,209,13,440,210,2,451,210,2,473,210,2,478,210,1,491,210,2,507,210,1,509,210,1,528,210,1,441,211,1,450,211,3,473,211,2,478,211,1,491,211,1,507,211,3,528,211,1,439,212,3,450,212,2,478,212,1,491,212,1,509,212,1,528,212,1,439,213,1,445,213,7,478,213,1,491,213,1,509,213,1,528,213,1,439,214,1,448,214,2,451,214,1,478,214,1,491,214,1,509,214,1,522,214,1,528,214,1,439,215,1,449,215,4,478,215,1,491,215,1,509,215,1,528,215,1,439,216,1,450,216,3,478,216,1,491,216,1,508,216,2,528,216,1,438,217,2,450,217,2,478,217,1,491,217,4,507,217,3,528,217,1,438,218,1,450,218,2,478,218,30,509,218,1,528,218,1,437,219,2,450,219,2,497,219,13,517,219,1,528,219,1,437,220,1,449,220,2,508,220,2,517,220,2,528,220,1,437,221,1,449,221,2,508,221,2,528,221,1,437,222,1,447,222,3,508,222,2,528,222,1,434,223,5,446,223,3,509,223,2,528,223,1,434,224,1,438,224,9,509,224,3,528,224,1,433,225,2,442,225,5,510,225,2,528,225,1,432,226,2,446,226,1,510,226,4,527,226,2,431,227,2,512,227,5,527,227,1,430,228,2,480,228,1,513,228,15,430,229,1,487,229,1,516,229,1,518,229,7,430,230,1,516,230,3,524,230,4,430,231,1,516,231,2,527,231,1,430,232,1,516,232,2,527,232,1,430,233,1,516,233,2,527,233,1,430,234,1,516,234,2,527,234,1,430,235,1,516,235,2,527,235,1,430,236,1,516,236,2,527,236,1,430,237,2,477,237,1,516,237,2,527,237,1,431,238,1,443,238,6,516,238,2,527,238,1,431,239,1,443,239,8,485,239,2,516,239,2,527,239,1,431,240,1,443,240,1,449,240,3,471,240,2,515,240,3,524,240,4,431,241,1,443,241,1,449,241,3,471,241,2,487,241,2,515,241,1,517,241,1,523,241,2,431,242,1,443,242,1,449,242,2,471,242,2,487,242,2,515,242,3,524,242,3,431,243,1,442,243,2,449,243,2,515,243,2,526,243,1,431,244,1,442,244,2,449,244,2,490,244,2,498,244,1,515,244,2,526,244,1,430,245,2,442,245,2,448,245,3,515,245,2,526,245,1,430,246,1,442,246,3,448,246,1,450,246,1,515,246,2,526,246,1,430,247,1,442,247,1,444,247,5,450,247,1,515,247,2,526,247,1,430,248,1,442,248,1,450,248,1,515,248,2,526,248,1,430,249,1,442,249,1,450,249,1,515,249,2,526,249,1,430,250,1,442,250,1,450,250,1,499,250,1,515,250,2,526,250,1,429,251,2,442,251,1,450,251,1,469,251,1,491,251,1,515,251,2,526,251,1,429,252,1,442,252,1,450,252,1,461,252,1,469,252,1,515,252,12,429,253,1,442,253,4,449,253,2,461,253,1,490,253,1,515,253,9,411,254,12,429,254,1,445,254,5,490,254,1,498,254,1,515,254,2,523,254,3,411,255,1,422,255,1,428,255,2,515,255,2,525,255,1,411,256,1,422,256,3,427,256,2,515,256,2,525,256,1,411,257,1,424,257,1,426,257,2,514,257,3,525,257,1,411,258,2,424,258,1,426,258,1,514,258,1,516,258,1,525,258,1,412,259,2,424,259,1,426,259,1,461,259,2,469,259,1,477,259,1,514,259,3,525,259,1,413,260,1,424,260,1,426,260,1,484,260,2,490,260,1,498,260,1,514,260,2,525,260,1,413,261,1,424,261,1,426,261,1,490,261,1,514,261,2,525,261,1,413,262,1,426,262,1,514,262,2,525,262,1,413,263,1,426,263,1,514,263,3,523,263,3,412,264,2,424,264,1,426,264,1,471,264,1,511,264,4,516,264,8,410,265,3,424,265,1,426,265,1,471,265,2,487,265,1,510,265,2,410,266,1,424,266,3,471,266,1,487,266,1,507,266,4,410,267,1,425,267,2,477,267,1,487,267,1,507,267,1,410,268,1,425,268,2,483,268,1,506,268,2,410,269,1,425,269,2,506,269,1,410,270,1,425,270,1,506,270,1,410,271,1,425,271,1,506,271,1,410,272,1,425,272,1,506,272,1,410,273,1,421,273,8,506,273,1,410,274,1,422,274,35,505,274,2,409,275,2,431,275,3,456,275,1,505,275,1,409,276,1,456,276,1,505,276,1,409,277,1,456,277,1,505,277,1,409,278,1,423,278,2,456,278,2,505,278,1,409,279,1,419,279,5,431,279,3,457,279,13,505,279,1,409,280,3,418,280,2,430,280,2,469,280,1,505,280,2,469,281,1,506,281,1,468,282,2,506,282,1,450,283,1,468,283,1,492,283,3,506,283,1,468,284,1,491,284,2,494,284,13,468,285,1,491,285,1,449,286,1,468,286,1,491,286,1,449,287,1,454,287,2,468,287,6,490,287,2,449,288,6,473,288,1,489,288,2,438,289,21,463,289,5,473,289,1,489,289,1,438,290,1,458,290,1,463,290,1,467,290,7,489,290,3,438,291,1,458,291,1,463,291,1,467,291,2,491,291,1,438,292,1,458,292,1,463,292,1,467,292,2,491,292,1,438,293,1,447,293,1,458,293,1,463,293,1,467,293,2,491,293,1,410,294,1,438,294,1,447,294,12,463,294,1,467,294,2,491,294,1,410,295,1,417,295,1,428,295,1,438,295,1,447,295,8,463,295,1,467,295,1,491,295,1,410,296,1,417,296,2,428,296,1,438,296,3,447,296,1,454,296,1,463,296,5,491,296,1,410,297,1,438,297,10,454,297,1,463,297,1,491,297,1,410,298,1,429,298,2,438,298,1,445,298,1,454,298,1,461,298,3,491,298,1,410,299,4,438,299,1,454,299,5,461,299,1,491,299,1,438,300,1,458,300,1,461,300,1,491,300,1,414,301,1,437,301,2,458,301,1,461,301,1,491,301,1,437,302,1,458,302,4,491,302,1,422,303,1,430,303,1,437,303,1,491,303,1,430,304,1,436,304,2,491,304,1,501,304,2,415,305,1,430,305,1,436,305,1,491,305,1,502,305,5,430,306,1,435,306,2,491,306,1,506,306,1,430,307,1,435,307,1,491,307,1,494,307,2,506,307,3,413,308,1,430,308,1,434,308,2,491,308,1,494,308,1,508,308,1,406,309,1,410,309,2,415,309,8,429,309,2,434,309,1,491,309,1,493,309,2,508,309,2,421,310,1,425,310,4,433,310,2,491,310,1,493,310,1,509,310,2,426,311,2,433,311,1,490,311,2,493,311,1,510,311,1,427,312,1,432,312,2,490,312,2,493,312,1,510,312,1,427,313,1,432,313,1,491,313,1,493,313,1,510,313,1,403,314,1,427,314,1,431,314,2,491,314,1,493,314,1,510,314,1,512,314,1,519,314,1,403,315,5,425,315,3,431,315,1,491,315,1,493,315,2,510,315,3,519,315,1,407,316,3,425,316,1,431,316,1,457,316,4,490,316,2,494,316,1,508,316,4,519,316,1,407,317,5,424,317,4,431,317,1,457,317,1,460,317,2,489,317,2,494,317,1,519,317,1,410,318,2,427,318,1,431,318,1,457,318,1,461,318,2,489,318,1,494,318,1,519,318,1,427,319,1,431,319,1,457,319,1,462,319,3,489,319,1,503,319,3,518,319,2,427,320,1,431,320,1,457,320,1,464,320,2,489,320,2,502,320,2,505,320,3,512,320,7,415,321,1,427,321,1,430,321,4,440,321,6,450,321,1,455,321,3,465,321,1,490,321,1,507,321,2,511,321,2,415,322,1,427,322,1,430,322,1,441,322,1,445,322,1,455,322,3,465,322,3,490,322,1,495,322,2,415,323,1,426,323,2,430,323,1,441,323,1,445,323,4,457,323,1,461,323,7,490,323,1,495,323,1,500,323,3,398,324,18,426,324,1,430,324,1,441,324,1,448,324,1,457,324,1,461,324,1,466,324,2,490,324,1,495,324,1,502,324,1,415,325,12,430,325,4,440,325,2,448,325,1,457,325,1,461,325,1,466,325,2,485,325,6,495,325,1,502,325,1,433,326,8,448,326,10,461,326,1,466,326,2,485,326,1,489,326,1,495,326,1,502,326,1,461,327,1,466,327,2,485,327,1,489,327,1,495,327,1,502,327,1,461,328,7,481,328,5,489,328,1,495,328,1,502,328,1,467,329,1,481,329,1,485,329,1,489,329,1,501,329,2,466,330,2,481,330,1,485,330,1,489,330,1,464,331,3,481,331,1,485,331,5,464,332,1,480,332,2,462,333,3,480,333,1,462,334,1,480,334,1,493,334,2,462,335,1,480,335,1,492,335,2,462,336,1,480,336,1,492,336,1,462,337,4,480,337,1,492,337,1,465,338,1,480,338,1,492,338,1,513,338,2,531,338,8,393,339,13,459,339,7,480,339,1,489,339,2,514,339,3,522,339,1,538,339,1,393,340,1,405,340,1,459,340,1,464,340,2,480,340,1,489,340,1,506,340,1,516,340,7,538,340,1,393,341,1,405,341,1,459,341,1,464,341,2,480,341,1,489,341,1,495,341,2,502,341,1,538,341,3,393,342,1,405,342,1,459,342,1,464,342,2,480,342,10,495,342,4,502,342,1,540,342,1,393,343,1,405,343,1,459,343,7,488,343,4,498,343,5,540,343,1,393,344,1,405,344,1,464,344,2,488,344,4,540,344,1,393,345,1,405,345,1,459,345,6,488,345,2,540,345,1,393,346,1,397,346,1,405,346,2,445,346,12,459,346,1,488,346,2,540,346,1,393,347,5,406,347,17,445,347,1,456,347,1,459,347,1,488,347,2,540,347,1,397,348,1,408,348,2,422,348,24,456,348,1,459,348,1,487,348,3,540,348,1,396,349,2,442,349,2,456,349,1,459,349,1,487,349,2,540,349,1,396,350,1,456,350,1,459,350,1,487,350,2,540,350,1,396,351,1,451,351,1,456,351,1,459,351,1,487,351,2,540,351,1,396,352,1,451,352,2,456,352,1,459,352,1,487,352,2,540,352,1,394,353,3,451,353,2,456,353,1,459,353,1,487,353,2,540,353,1,394,354,1,452,354,5,459,354,1,487,354,2,540,354,1,394,355,1,452,355,5,459,355,1,487,355,2,540,355,1,390,356,5,456,356,1,459,356,1,487,356,2,540,356,1,390,357,1,394,357,2,456,357,1,459,357,1,487,357,2,540,357,1,390,358,1,394,358,2,456,358,1,459,358,1,487,358,2,540,358,1,390,359,1,394,359,2,456,359,4,487,359,2,540,359,1,389,360,2,394,360,3,487,360,15,540,360,1,389,361,1,396,361,2,403,361,1,479,361,9,501,361,9,516,361,1,540,361,1,389,362,1,401,362,5,479,362,1,516,362,1,540,362,1,389,363,1,404,363,2,479,363,1,516,363,1,540,363,1,389,364,4,404,364,2,479,364,1,540,364,1,392,365,1,404,365,2,479,365,1,539,365,2,392,366,1,396,366,2,405,366,1,479,366,1,539,366,1,392,367,8,479,367,1,539,367,1,399,368,1,414,368,9,479,368,1,539,368,1,399,369,1,412,369,3,422,369,2,479,369,1,399,370,1,405,370,2,411,370,2,423,370,19,479,370,1,399,371,1,405,371,2,411,371,1,441,371,2,479,371,1,399,372,1,411,372,1,442,372,1,479,372,1,399,373,1,411,373,1,442,373,1,479,373,1,399,374,1,411,374,1,442,374,13,479,374,1,399,375,1,411,375,1,454,375,6,479,375,1,399,376,1,411,376,1,458,376,2,479,376,1,399,377,1,405,377,2,411,377,1,458,377,1,479,377,1,399,378,1,405,378,7,458,378,1,479,378,1,399,379,7,458,379,1,479,379,1,398,380,6,458,380,1,479,380,1,398,381,1,403,381,1,409,381,7,458,381,3,476,381,4,398,382,1,403,382,1,409,382,1,415,382,8,460,382,2,476,382,1,398,383,1,403,383,1,407,383,3,415,383,2,422,383,2,460,383,2,476,383,1,397,384,2,403,384,5,415,384,2,423,384,1,455,384,6,476,384,4,394,385,4,407,385,1,411,385,6,455,385,1,479,385,1,393,386,2,407,386,1,411,386,2,418,386,2,455,386,1,479,386,1,393,387,1,402,387,1,407,387,1,411,387,2,418,387,2,455,387,1,479,387,1,385,388,7,393,388,1,402,388,2,411,388,2,418,388,1,433,388,5,455,388,1,479,388,1,385,389,1,391,389,3,402,389,3,412,389,1,418,389,1,433,389,1,437,389,1,455,389,1,478,389,2,385,390,1,392,390,2,402,390,1,404,390,1,410,390,1,412,390,1,418,390,2,433,390,1,437,390,1,441,390,1,445,390,1,455,390,1,472,390,3,478,390,1,385,391,1,392,391,2,401,391,2,404,391,2,410,391,1,412,391,1,419,391,2,433,391,1,437,391,1,440,391,2,445,391,3,455,391,1,471,391,2,474,391,5,385,392,1,392,392,2,401,392,12,420,392,3,433,392,1,437,392,4,447,392,9,470,392,2,385,393,1,392,393,2,422,393,5,433,393,6,469,393,2,472,393,6,385,394,1,392,394,6,426,394,10,469,394,1,472,394,1,477,394,1,385,395,1,392,395,1,397,395,1,469,395,1,472,395,1,477,395,1,385,396,1,392,396,1,394,396,4,469,396,1,472,396,1,477,396,1,385,397,1,392,397,3,469,397,1,472,397,1,477,397,1,385,398,1,392,398,1,469,398,1,472,398,1,385,399,3,392,399,1,469,399,1,472,399,2,386,400,2,392,400,1,469,400,4,385,401,2,392,401,1,470,401,2,385,402,1,392,402,1,470,402,2,476,402,2,385,403,1,391,403,2,470,403,2,476,403,1,385,404,1,391,404,2,431,404,14,470,404,2,476,404,1,486,404,1,385,405,1,391,405,2,431,405,1,444,405,17,469,405,8,496,405,1,385,406,1,391,406,2,431,406,1,450,406,7,460,406,10,385,407,1,391,407,1,431,407,1,456,407,2,463,407,16,385,408,1,391,408,1,431,408,1,457,408,1,472,408,1,478,408,1,385,409,1,391,409,1,431,409,1,457,409,1,472,409,1,478,409,1,482,409,2,385,410,1,391,410,1,431,410,1,450,410,2,457,410,1,472,410,1,478,410,1,385,411,1,391,411,1,430,411,2,451,411,1,456,411,2,472,411,7,385,412,1,390,412,5,430,412,1,472,412,1,385,413,1,391,413,5,430,413,1,472,413,1,385,414,1,394,414,2,420,414,11,385,415,1,394,415,2,420,415,11,385,416,1,394,416,2,415,416,1,420,416,1,425,416,1,430,416,1,385,417,5,394,417,2,415,417,1,420,417,1,425,417,1,430,417,1,389,418,1,394,418,2,415,418,1,420,418,1,425,418,1,430,418,2,389,419,2,394,419,1,415,419,1,420,419,1,425,419,1,431,419,1,390,420,1,394,420,1,415,420,1,420,420,1,425,420,1,431,420,1,390,421,1,394,421,1,415,421,1,420,421,1,425,421,1,431,421,1,390,422,1,394,422,1,415,422,1,420,422,1,425,422,1,431,422,1,390,423,1,394,423,1,415,423,1,420,423,1,425,423,1,431,423,1,390,424,1,394,424,1,415,424,1,420,424,1,425,424,1,431,424,1,390,425,1,394,425,1,415,425,1,420,425,1,425,425,1,431,425,1,390,426,4,415,426,1,420,426,1,425,426,7,393,427,1,415,427,2,420,427,1,431,427,1,393,428,1,416,428,1,420,428,1,431,428,1,390,429,4,416,429,1,420,429,1,424,429,1,431,429,1,390,430,1,416,430,9,431,430,1,390,431,1,416,431,1,424,431,1,431,431,1,390,432,1,424,432,1,431,432,1,390,433,1,424,433,1,431,433,1,390,434,1,424,434,1,431,434,1,390,435,1,424,435,1,431,435,1,390,436,1,424,436,1,431,436,1,390,437,1,424,437,1,431,437,1,390,438,1,424,438,10,473,438,5,390,439,1,433,439,37,472,439,2,477,439,1,390,440,1,461,440,2,469,440,1,472,440,1,477,440,1,390,441,1,461,441,2,469,441,1,472,441,1,477,441,1,390,442,8,461,442,2,469,442,1,472,442,1,476,442,2,390,443,1,396,443,12,461,443,1,468,443,2,472,443,1,476,443,1,390,444,1,396,444,1,407,444,8,460,444,2,468,444,1,390,445,1,396,445,1,414,445,3,420,445,3,460,445,1,468,445,1,390,446,7,416,446,6,460,446,1,468,446,1,421,447,1,460,447,1,468,447,1,421,448,1,460,448,1,468,448,1,421,449,1,460,449,1,468,449,1,420,450,2,460,450,2,468,450,1,420,451,1,460,451,2,468,451,1,471,451,1,475,451,1,420,452,1,461,452,3,468,452,1,471,452,1,475,452,3,420,453,1,461,453,1,463,453,1,468,453,1,471,453,1,477,453,1,420,454,1,444,454,7,461,454,1,463,454,6,471,454,1,477,454,1,420,455,1,444,455,1,450,455,6,461,455,1,471,455,1,477,455,1,420,456,1,444,456,1,455,456,7,471,456,7,420,457,1,431,457,14,420,458,1,431,458,1,420,459,1,424,459,1,428,459,4,420,460,9]},{"__class":"MapLayer","metaData":{"segmentId":"10","active":false,"name":"Cameretta","area":38200},"type":"segment","pixels":[],"dimensions":{"x":{"min":390,"max":455,"mid":423,"avg":423},"y":{"min":340,"max":378,"mid":359,"avg":359},"pixelCount":1528},"compressedPixels":[394,340,11,394,341,11,394,342,11,394,343,11,394,344,11,394,345,11,394,346,3,398,346,7,398,347,8,446,347,10,393,348,4,398,348,10,410,348,12,446,348,10,392,349,4,398,349,44,444,349,12,392,350,4,397,350,59,391,351,5,397,351,54,452,351,4,391,352,5,397,352,54,453,352,3,391,353,3,397,353,54,453,353,3,391,354,3,395,354,57,391,355,3,395,355,57,395,356,61,391,357,3,396,357,60,391,358,3,396,358,60,391,359,3,396,359,60,391,360,3,397,360,59,390,361,6,398,361,5,404,361,52,390,362,11,406,362,50,390,363,14,406,363,50,393,364,11,406,364,50,393,365,11,406,365,50,393,366,3,398,366,7,406,366,50,400,367,56,400,368,14,423,368,33,400,369,12,424,369,32,400,370,5,407,370,4,442,370,14,400,371,5,407,371,4,443,371,13,400,372,11,443,372,13,400,373,11,443,373,13,400,374,11,455,374,1,400,375,11,400,376,11,400,377,5,407,377,4,400,378,5]},{"__class":"MapLayer","metaData":{"segmentId":"11","active":false,"name":"Bagno","area":17775},"type":"segment","pixels":[],"dimensions":{"x":{"min":431,"max":457,"mid":444,"avg":446},"y":{"min":290,"max":325,"mid":308,"avg":309},"pixelCount":711},"compressedPixels":[439,290,19,439,291,19,439,292,19,439,293,8,448,293,10,439,294,8,439,295,8,455,295,2,441,296,6,448,296,6,455,296,2,448,297,6,455,297,2,439,298,6,446,298,8,455,298,2,439,299,15,439,300,19,439,301,18,438,302,19,438,303,19,438,304,19,437,305,20,437,306,20,436,307,21,436,308,21,435,309,22,435,310,22,434,311,23,434,312,23,433,313,24,433,314,24,432,315,25,432,316,25,432,317,25,432,318,25,432,319,25,432,320,25,434,321,6,446,321,4,451,321,4,431,322,10,442,322,3,446,322,9,431,323,10,442,323,3,449,323,8,431,324,10,442,324,6,449,324,8,434,325,6,442,325,6,449,325,8]},{"__class":"MapLayer","metaData":{"segmentId":"12","active":false,"name":"Soggiorno","area":54050},"type":"segment","pixels":[],"dimensions":{"x":{"min":426,"max":466,"mid":446,"avg":448},"y":{"min":198,"max":278,"mid":238,"avg":240},"pixelCount":2162},"compressedPixels":[452,198,10,452,199,15,452,200,15,452,201,15,452,202,15,452,203,15,450,204,1,452,204,15,442,205,2,452,205,15,441,206,10,452,206,15,441,207,10,452,207,15,441,208,10,452,208,14,441,209,10,453,209,13,442,210,9,453,210,13,442,211,8,453,211,13,442,212,8,452,212,14,440,213,5,452,213,14,440,214,8,450,214,1,452,214,14,440,215,9,453,215,13,440,216,10,453,216,13,440,217,10,452,217,14,439,218,11,452,218,14,439,219,11,452,219,14,438,220,11,451,220,15,438,221,11,451,221,15,438,222,9,450,222,16,439,223,7,449,223,17,435,224,3,447,224,18,435,225,7,447,225,18,435,226,11,447,226,18,435,227,30,432,228,33,431,229,34,431,230,34,431,231,34,431,232,34,431,233,34,431,234,34,431,235,34,431,236,34,432,237,33,432,238,11,449,238,16,432,239,11,451,239,13,432,240,11,444,240,5,452,240,12,432,241,11,444,241,5,452,241,12,432,242,11,444,242,5,451,242,13,432,243,10,444,243,5,451,243,13,432,244,10,444,244,5,451,244,13,432,245,10,444,245,4,451,245,13,431,246,11,445,246,3,449,246,1,451,246,13,431,247,11,443,247,1,449,247,1,451,247,13,431,248,11,443,248,7,451,248,13,431,249,11,443,249,7,451,249,13,431,250,11,443,250,7,451,250,13,431,251,11,443,251,7,451,251,13,430,252,12,443,252,7,451,252,10,462,252,2,430,253,12,446,253,3,451,253,10,462,253,2,430,254,15,450,254,13,430,255,33,429,256,34,428,257,35,428,258,35,428,259,33,427,260,36,427,261,36,427,262,36,427,263,36,427,264,36,427,265,36,427,266,36,427,267,36,427,268,36,427,269,36,426,270,36,426,271,36,427,272,35,429,273,33,457,274,5,457,275,5,457,276,5,457,277,5,458,278,4]},{"__class":"MapLayer","metaData":{"segmentId":"13","active":false,"name":"Cucina","area":81625},"type":"segment","pixels":[],"dimensions":{"x":{"min":462,"max":515,"mid":489,"avg":486},"y":{"min":199,"max":286,"mid":243,"avg":249},"pixelCount":3265},"compressedPixels":[468,199,6,467,200,7,467,201,7,467,202,7,467,203,7,467,204,6,467,205,6,474,205,2,467,206,6,467,207,6,475,207,3,466,208,7,475,208,3,466,209,7,475,209,3,466,210,7,475,210,3,466,211,7,475,211,3,466,212,12,466,213,12,466,214,12,466,215,12,466,216,12,466,217,12,466,218,12,466,219,31,466,220,42,466,221,42,466,222,42,466,223,43,465,224,44,465,225,45,465,226,45,465,227,47,465,228,15,481,228,32,465,229,22,488,229,28,465,230,51,465,231,51,465,232,51,465,233,51,465,234,51,465,235,51,465,236,51,465,237,12,478,237,38,465,238,51,464,239,21,487,239,29,464,240,7,473,240,42,464,241,7,473,241,14,489,241,26,464,242,7,473,242,14,489,242,26,464,243,51,464,244,26,492,244,6,499,244,16,464,245,51,464,246,51,464,247,51,464,248,51,464,249,51,464,250,35,500,250,15,464,251,5,470,251,21,492,251,23,464,252,5,470,252,45,464,253,26,491,253,24,463,254,27,491,254,7,499,254,16,463,255,52,463,256,52,463,257,51,463,258,51,463,259,6,470,259,7,478,259,36,463,260,21,486,260,4,491,260,7,499,260,15,463,261,27,491,261,23,463,262,51,463,263,51,463,264,8,472,264,39,463,265,8,473,265,14,488,265,22,463,266,8,472,266,15,488,266,19,463,267,14,478,267,9,488,267,19,463,268,20,484,268,22,463,269,43,462,270,44,462,271,44,462,272,44,462,273,44,462,274,43,462,275,43,462,276,43,462,277,43,463,278,42,470,279,35,470,280,35,470,281,36,470,282,36,469,283,23,495,283,11,469,284,22,469,285,22,469,286,22]},{"__class":"MapLayer","metaData":{"segmentId":"14","active":false,"name":"Corridoio","area":55750},"type":"segment","pixels":[],"dimensions":{"x":{"min":456,"max":490,"mid":473,"avg":473},"y":{"min":287,"max":382,"mid":335,"avg":333},"pixelCount":2230},"compressedPixels":[474,287,16,474,288,15,474,289,15,474,290,15,472,291,19,471,292,20,471,293,20,471,294,20,471,295,20,471,296,20,470,297,21,469,298,22,468,299,23,462,300,29,457,301,1,462,301,29,457,302,1,462,302,29,457,303,34,457,304,34,457,305,34,457,306,34,457,307,34,457,308,34,457,309,34,457,310,34,457,311,33,457,312,33,457,313,34,457,314,34,457,315,34,461,316,29,462,317,27,463,318,26,490,318,1,465,319,24,490,319,1,466,320,23,466,321,24,468,322,22,468,323,22,468,324,22,468,325,17,468,326,17,486,326,3,468,327,17,486,327,3,468,328,13,486,328,3,468,329,13,482,329,3,486,329,3,468,330,13,482,330,3,486,330,3,467,331,14,484,331,1,466,332,14,466,333,14,466,334,14,466,335,14,466,336,14,466,337,14,466,338,14,466,339,14,462,340,2,466,340,14,461,341,3,466,341,14,461,342,3,466,342,14,466,343,21,462,344,2,466,344,22,465,345,23,461,346,27,461,347,27,460,348,27,460,349,27,460,350,27,460,351,27,460,352,27,460,353,27,460,354,27,460,355,27,460,356,27,460,357,27,460,358,27,460,359,27,456,360,31,456,361,23,456,362,23,456,363,23,456,364,23,456,365,23,456,366,23,456,367,23,456,368,23,456,369,23,456,370,23,456,371,23,456,372,23,456,373,23,456,374,23,460,375,19,460,376,19,459,377,20,459,378,20,459,379,20,459,380,20,461,381,15,462,382,14]},{"__class":"MapLayer","metaData":{"segmentId":"15","active":false,"name":"Camera da letto","area":71275},"type":"segment","pixels":[],"dimensions":{"x":{"min":394,"max":477,"mid":436,"avg":429},"y":{"min":383,"max":457,"mid":420,"avg":419},"pixelCount":2851},"compressedPixels":[462,383,14,461,384,15,457,385,21,456,386,22,456,387,22,456,388,22,456,389,22,456,390,16,395,391,6,456,391,15,394,392,7,413,392,6,441,392,6,456,392,14,394,393,27,439,393,30,398,394,28,436,394,33,395,395,2,398,395,71,398,396,71,395,397,74,394,398,75,395,399,74,395,400,74,396,401,74,396,402,74,396,403,74,396,404,35,445,404,25,397,405,34,461,405,8,398,406,33,399,407,32,399,408,32,399,409,32,399,410,32,399,411,31,398,412,30,398,413,29,398,414,22,398,415,22,398,416,17,416,416,4,421,416,4,399,417,16,416,417,4,421,417,4,399,418,16,416,418,4,421,418,4,399,419,16,416,419,4,421,419,4,407,420,8,416,420,4,421,420,4,399,421,16,416,421,4,421,421,4,398,422,17,416,422,4,421,422,4,397,423,11,409,423,6,416,423,4,421,423,4,397,424,11,409,424,6,416,424,4,421,424,4,426,424,1,397,425,11,410,425,5,416,425,4,421,425,4,426,425,2,397,426,11,409,426,6,416,426,4,421,426,4,397,427,18,417,427,3,421,427,10,397,428,19,417,428,3,421,428,10,397,429,19,417,429,3,421,429,3,425,429,6,397,430,19,425,430,6,397,431,19,417,431,7,425,431,6,397,432,27,425,432,6,397,433,27,425,433,6,397,434,27,425,434,6,397,435,27,425,435,6,397,436,27,425,436,6,397,437,27,425,437,6,397,438,27,397,439,36,397,440,64,463,440,6,397,441,64,463,441,6,398,442,63,463,442,6,408,443,53,462,443,6,399,444,8,415,444,45,462,444,6,400,445,6,407,445,7,417,445,3,423,445,37,461,445,7,422,446,38,461,446,7,422,447,38,461,447,7,425,448,35,461,448,7,426,449,34,461,449,7,426,450,34,462,450,6,425,451,35,462,451,6,425,452,36,464,452,4,425,453,36,464,453,3,425,454,19,451,454,3,425,455,19,445,455,5,426,456,18,445,456,4,430,457,1]}],"entities":[{"__class":"PointMapEntity","metaData":{"angle":179.98497688677162},"points":[1967,1993],"type":"robot_position"},{"__class":"PointMapEntity","metaData":{"angle":179.98497688677162},"points":[1982,1994],"type":"charger_location"}]}}

@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!

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