Guest User

Valetudo FHEM

a guest
Dec 13th, 2019
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const fs = require("fs");
  2. const path = require("path");
  3. const Jimp = require("jimp");
  4.  
  5.  
  6. const chargerImagePath = path.join(__dirname, '../assets/img/charger.png');
  7. const robotImagePath = path.join(__dirname, '../assets/img/robot.png');
  8.  
  9. //Define Zones for Rendering, Get Coordinates from RoborockIP/Zone/
  10. const ZONES = [
  11.     [23726, 23687, 26368, 26159],
  12.     [26355, 23700, 28046, 26133],
  13.     [19953, 22074, 22646, 26198],
  14.     [22646, 22425, 23583, 26224],
  15.     [19732, 19810, 23557, 22022],
  16.     [21501, 17832, 23596, 19979],
  17.     [20109, 17806, 20564, 19888],
  18.     [23492, 18860, 25131, 23765],
  19.     [25092, 19732, 28163, 21618],
  20.     [25756, 19029, 28124, 19823]
  21. ];
  22.  
  23. //Define some Stuff for Rendering
  24. var allowDraw = [];
  25. var maxheight = 0;
  26. var maxwidth = 0;
  27. var minheight = 0;
  28. var minwidth = 0;
  29.  
  30. // Enable MapCleaning or not, could removed if function like "IF Zones !=NULL than enable..."
  31. const enableMapCleanUp = true;
  32.  
  33. const Tools = {
  34.     DIMENSION_PIXELS: 1024,
  35.     DIMENSION_MM: 50 * 1024,
  36.  
  37.     MK_DIR_PATH: function(filepath) {
  38.         var dirname = path.dirname(filepath);
  39.         console.log("dir" + dirname);
  40.         console.log(filepath);
  41.         if (!fs.existsSync(dirname)) {
  42.             Tools.MK_DIR_PATH(dirname);
  43.         }
  44.         if (!fs.existsSync(filepath)) {
  45.             fs.mkdirSync(filepath);
  46.         }
  47.     },
  48.  
  49.     /**
  50.      *
  51.      * @param options {object}
  52.      * @param options.parsedMapData
  53.      * @param options.settings
  54.      * @param callback {function}
  55.      * @constructor
  56.      */
  57.  
  58. //Create Table with Drawable Coordinates, all coordinats from Zones calculated
  59.  
  60.     CreateAllowToDraw: function(zones, left, top) {
  61.         zones.forEach(function(zone) {
  62.             zone = {
  63.                 fromx: Math.trunc(zone[0] / 50 - left),
  64.                 fromy: Math.trunc(zone[1] / 50 - top),
  65.                 tox: Math.trunc(zone[2] / 50 - left),
  66.                 toy: Math.trunc(zone[3] / 50 - top)
  67.             }
  68.  
  69.             //Build allowDraw array and check if position already exists
  70.  
  71.             for (x = zone.fromx; x < zone.tox; x++) {
  72.                 for (y = zone.fromy; y < zone.toy; y++) {
  73.                     if (!Tools.isItemInArray([x, y])) {
  74.                         allowDraw.push([x, y]);
  75.                     }
  76.                 }
  77.             }
  78.         });
  79.  
  80. //Set new Max|Min vales to shrink the map size, because some data arround the importent stuff is deleted
  81.  
  82.         maxheight = Math.max.apply(Math, allowDraw.map(function(o) { return o[1]; }));
  83.         maxwidth = Math.max.apply(Math, allowDraw.map(function(o) { return o[0]; }));
  84.         minheight = Math.min.apply(Math, allowDraw.map(function(o) { return o[1]; }));
  85.         minwidth = Math.min.apply(Math, allowDraw.map(function(o) { return o[0]; }));
  86.  
  87.         maxwidth = maxwidth - minwidth;
  88.         maxheight = maxheight - minheight;
  89.  
  90.     },
  91. //function to check, if current location is allowed to draw
  92.  
  93.     isItemInArray: function(item) {
  94.         for (var i = 0; i < allowDraw.length; i++) {
  95.             // This if statement depends on the format of your array
  96.             if (allowDraw[i][0] == item[0] && allowDraw[i][1] == item[1]) {
  97.                 return true; // Found it
  98.             }
  99.         }
  100.         return false; // Not found
  101.     },
  102.  
  103. //only private stuff, to trigger my Smarthome when a new map exists :) this avoids constant reloading from map.
  104.  
  105.     TriggerMapUpdate: function() {
  106.         var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
  107.         var Http = new XMLHttpRequest();
  108.         const url = 'http://localhost:8083/fhem/?cmd=setReading%20Roborock%20mapURL%20http://debian:3001/api/map/image?_='+Date.now()+'&fwcsrf=&XHR=1';
  109.         Http.open("GET", url);
  110.         Http.send();
  111.     },
  112.  
  113.  
  114.     DRAW_MAP_PNG: function(options, callback) {
  115.         const COLORS = {
  116.             floor: Jimp.rgbaToInt(0, 118, 255, 255),
  117.             obstacle_weak: Jimp.rgbaToInt(102, 153, 255, 255),
  118.             obstacle_strong: Jimp.rgbaToInt(82, 174, 255, 255),
  119.             path: Jimp.rgbaToInt(255, 255, 255, 255)
  120.         };
  121.  
  122. //Activate Drawable Coordinates creation and overwrite the max values
  123.  
  124.         if (enableMapCleanUp) {
  125.             Tools.CreateAllowToDraw(ZONES, options.parsedMapData.image.position.left, options.parsedMapData.image.position.top);
  126.             options.parsedMapData.image.dimensions.height = maxheight;
  127.             options.parsedMapData.image.dimensions.width = maxwidth;
  128.         }
  129.         else {
  130.             minwidth = 0;
  131.             minheight = 0;
  132.         };
  133.  
  134.  
  135.         const DIMENSIONS = {
  136.             width: options.parsedMapData.image.dimensions.width,
  137.             height: options.parsedMapData.image.dimensions.height
  138.         };
  139.  
  140.  
  141.         const settings = Object.assign({
  142.             drawPath: true,
  143.             drawCharger: true,
  144.             drawRobot: true,
  145.             border: 2,
  146.             scale: 4
  147.         }, options.settings);
  148.  
  149.  
  150.  
  151.  
  152.         new Jimp(DIMENSIONS.width, DIMENSIONS.height, function(err, image) {
  153.             if (!err) {
  154.                 //Step 1: Draw Map + calculate viewport
  155.                 Object.keys(options.parsedMapData.image.pixels).forEach(key => {
  156.                     const color = COLORS[key];
  157.                     options.parsedMapData.image.pixels[key].forEach(function drawPixel(px) {
  158. //check if this pixel is drawable/arrange the map with min values (default min values are 0)
  159.                         if (!enableMapCleanUp || Tools.isItemInArray([px[0], px[1]])) {
  160.                             image.setPixelColor(color, px[0] - minwidth, px[1] - minheight);
  161.                         }
  162.                     })
  163.                 });
  164.  
  165.                 //Step 2: Scale
  166.                 image.scale(settings.scale, Jimp.RESIZE_NEAREST_NEIGHBOR);
  167.  
  168.                 //Step 3: Draw Path
  169.                 const coords = options.parsedMapData.path.points.map(point => {
  170.                     return [
  171. //add image arrange, to center the map and cut unused space arround the coordinates, arrange the map with min values (default min values are 0)
  172.  
  173.                         Math.floor(((point[0] / 50 - options.parsedMapData.image.position.left) - minwidth) * settings.scale),
  174.                         Math.floor(((point[1] / 50 - options.parsedMapData.image.position.top) - minheight) * settings.scale)
  175.                     ]
  176.                 });
  177.  
  178.                 let first = true;
  179.                 let oldPathX, oldPathY; // old Coordinates
  180.                 let dx, dy; //delta x and y
  181.                 let step, x, y, i;
  182.                 coords.forEach(function(coord) {
  183.                     if (!first && settings.drawPath) {
  184.                         dx = (coord[0] - oldPathX);
  185.                         dy = (coord[1] - oldPathY);
  186.                         if (Math.abs(dx) >= Math.abs(dy)) {
  187.                             step = Math.abs(dx);
  188.                         }
  189.                         else {
  190.                             step = Math.abs(dy);
  191.                         }
  192.                         dx = dx / step;
  193.                         dy = dy / step;
  194.                         x = oldPathX;
  195.                         y = oldPathY;
  196.                         i = 1;
  197.                         while (i <= step) {
  198.                             image.setPixelColor(COLORS.path, x, y);
  199.                             x = x + dx;
  200.                             y = y + dy;
  201.                             i = i + 1;
  202.                         }
  203.                     }
  204.                     oldPathX = coord[0];
  205.                     oldPathY = coord[1];
  206.                     first = false;
  207.                 });
  208.  
  209.                 Jimp.read(chargerImagePath, function(err, chargerImage) {
  210.                     if (!err) {
  211.                         Jimp.read(robotImagePath, function(err, robotImage) {
  212.                             if (!err) {
  213.                                 //Step 6: Draw Charger
  214.                                 if (settings.drawCharger === true && options.parsedMapData.charger) {
  215.                                     const chargerCoords = {
  216. //add image arrange, to center the map and cut unused space arround the coordinates, arrange the map with min values (default min values are 0)
  217.                                         x: (options.parsedMapData.charger[0] / 50 - options.parsedMapData.image.position.left) - minwidth,
  218.                                         y: (options.parsedMapData.charger[1] / 50 - options.parsedMapData.image.position.top) - minheight
  219.                                     };
  220.  
  221.                                     image.composite(
  222.                                         chargerImage,
  223.                                         chargerCoords.x * settings.scale - chargerImage.bitmap.width / 2,
  224.                                         chargerCoords.y * settings.scale - chargerImage.bitmap.height / 2
  225.                                     );
  226.                                 }
  227.  
  228.                                 //Step 7: Draw Robot
  229.                                 if (settings.drawRobot === true && options.parsedMapData.robot) {
  230.                                     const robotCoords = {
  231. //add image arrange, to center the map and cut unused space arround the coordinates, arrange the map with min values (default min values are 0)
  232.                                         x: (options.parsedMapData.robot[0] / 50 - options.parsedMapData.image.position.left) - minwidth,
  233.                                         y: (options.parsedMapData.robot[1] / 50 - options.parsedMapData.image.position.top) - minheight
  234.                                     };
  235.  
  236.                                     image.composite(
  237.                                         robotImage.rotate(-1 * options.parsedMapData.path.current_angle - 90),
  238.                                         robotCoords.x * settings.scale - robotImage.bitmap.width / 2,
  239.                                         robotCoords.y * settings.scale - robotImage.bitmap.height / 2
  240.                                     )
  241.                                 }
  242.  
  243.                                 image.getBuffer(Jimp.AUTO, callback);
  244.                                 Tools.TriggerMapUpdate();
  245.                             }
  246.                             else {
  247.                                 callback(err);
  248.                             }
  249.                         })
  250.                     }
  251.                     else {
  252.                         callback(err);
  253.                     }
  254.                 });
  255.             }
  256.             else {
  257.                 callback(err);
  258.             }
  259.         });
  260.     }
  261. };
  262.  
  263. module.exports = Tools;
Advertisement
Add Comment
Please, Sign In to add comment