added widgets
This commit is contained in:
BIN
Widgets/.DS_Store
vendored
Normal file
BIN
Widgets/.DS_Store
vendored
Normal file
Binary file not shown.
157
Widgets/topology/topology.js
Normal file
157
Widgets/topology/topology.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
self.onInit = function () {
|
||||||
|
//self.onResize();
|
||||||
|
//self.draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onDataUpdated = function () {
|
||||||
|
//self.draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
//function for scaling a canvas
|
||||||
|
function fitToContainer(canvas) {
|
||||||
|
canvas.style.width = "100%";
|
||||||
|
canvas.style.height = "100%";
|
||||||
|
canvas.width = canvas.offsetWidth;
|
||||||
|
canvas.height = canvas.offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
constructor(id, x, y, radius, data) {
|
||||||
|
this.id = id;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.radius = Math.min(radius, 25);
|
||||||
|
this.lineLength = 25;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
this.node = new Path2D();
|
||||||
|
this.node.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
|
||||||
|
self.ctx.canvas.textAlign = "center";
|
||||||
|
self.ctx.canvas.textBaseline = "middle";
|
||||||
|
self.ctx.canvas.strokeText(this.data, this.x, this.y);
|
||||||
|
self.ctx.canvas.fillStyle = "White";
|
||||||
|
self.ctx.canvas.stroke(this.node);
|
||||||
|
self.ctx.canvas.fill(this.node);
|
||||||
|
}
|
||||||
|
setX(x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
setY(y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
setRadius(radius) {
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Edge {
|
||||||
|
constructor(source, target) {
|
||||||
|
this.source = source;
|
||||||
|
this.target = target;
|
||||||
|
//this.draw();
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
self.ctx.canvas.moveTo(self.nodes[this.source].x, self.nodes[this.source].y);
|
||||||
|
self.ctx.canvas.lineTo(self.nodes[this.target].x, self.nodes[this.target].y);
|
||||||
|
self.ctx.canvas.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDepth(edges) {
|
||||||
|
var depth = 1;
|
||||||
|
console.log(edges);
|
||||||
|
if (Object.keys(edges).length > 0) {
|
||||||
|
Object.keys(edges).forEach((target) => {
|
||||||
|
console.log("Target: " + target);
|
||||||
|
Object.keys(edges).forEach((nTarget) => {
|
||||||
|
edges[nTarget].forEach((edge) => {
|
||||||
|
console.log("Source: " + edge.source);
|
||||||
|
if (edge.source == target) {
|
||||||
|
console.log("recurse");
|
||||||
|
var slice = Object.fromEntries(Object.entries(edges).slice(0, Object.keys(edges).indexOf(target)) + Object.entries(edges).slice(Object.keys(edges).indexOf(target)) + 1);
|
||||||
|
depth = depth + getDepth(slice);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("Depth: " + depth);
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeNodes() {
|
||||||
|
var numSourceNodes = Object.keys(self.nodes).length - Object.keys(self.edges).length;
|
||||||
|
var depth = getDepth(self.edges);
|
||||||
|
console.log(depth);
|
||||||
|
|
||||||
|
if (Object.keys(self.nodes).length == 1) {
|
||||||
|
self.nodes[Object.keys(self.nodes)[0]].setX(self.canvas.width / 2);
|
||||||
|
self.nodes[Object.keys(self.nodes)[0]].setY(self.canvas.height / 2);
|
||||||
|
self.nodes[Object.keys(self.nodes)[0]].setRadius(self.canvas.height * 0.1);
|
||||||
|
} else {
|
||||||
|
var counter = 0;
|
||||||
|
Object.keys(self.edges).forEach((target) => {
|
||||||
|
self.edges[target].forEach((edge) => {
|
||||||
|
self.nodes[edge.source].setX(self.canvas.width * (1 / (Object.keys(self.edges).length + 2)));
|
||||||
|
self.nodes[edge.source].setY(self.canvas.height * ((counter + 1) / (numSourceNodes + 1)));
|
||||||
|
self.nodes[edge.source].setRadius(self.canvas.height * (1 / (2 * (Object.keys(self.nodes).length + 1))));
|
||||||
|
|
||||||
|
self.nodes[edge.target].setX(self.canvas.width * (2 / (Object.keys(self.edges).length + 2)));
|
||||||
|
self.nodes[edge.target].setY(self.canvas.height * ((Object.keys(self.edges).indexOf(target) + 1) / (Object.keys(self.edges).length + 1)));
|
||||||
|
self.nodes[edge.target].setRadius(self.canvas.height * (1 / (2 * (Object.keys(self.nodes).length + 1))));
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.draw = function () {
|
||||||
|
self.canvas = document.getElementById("topology");
|
||||||
|
self.ctx.canvas = self.canvas.getContext("2d");
|
||||||
|
fitToContainer(self.canvas);
|
||||||
|
self.ctx.canvas.globalCompositeOperation = "destination-over";
|
||||||
|
var collapse = false;
|
||||||
|
self.nodes = {};
|
||||||
|
let numNodes = 9;
|
||||||
|
//var centerNode = new Node(100, self.canvas.width * 0.11, self.canvas.height * 0.5, self.canvas.height * (1 / (2 * (numNodes + 1))), 1);
|
||||||
|
for (let i = 0; i < numNodes; i++) {
|
||||||
|
self.nodes[i] = new Node(i, 0, 0, 0, i);
|
||||||
|
//self.nodes[i] = new Node(i, self.canvas.width * 0.11, self.canvas.height * ((i + 1) / (numNodes + 1)), self.canvas.height * (1 / (2 * (numNodes + 1))), (Math.random() * 10).toFixed(2));
|
||||||
|
//self.nodes[i].draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.edges = { 0: [new Edge(3, 0), new Edge(4, 0), new Edge(5, 0), new Edge(6, 0)], 8: [new Edge(0, 8)], 7: [new Edge(8, 7)], 2: [new Edge(1, 2)] };
|
||||||
|
|
||||||
|
placeNodes();
|
||||||
|
Object.keys(self.nodes).forEach((key) => {
|
||||||
|
self.nodes[key].draw();
|
||||||
|
});
|
||||||
|
Object.keys(self.edges).forEach((target) => {
|
||||||
|
self.edges[target].forEach((edge) => {
|
||||||
|
edge.draw();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//self.edges.push(new Edge(0,0));
|
||||||
|
/*let rNodes = Math.round(numNodes * 0.5);
|
||||||
|
for (let i = 0; i < rNodes; i++) {
|
||||||
|
self.nodes[i + numNodes] = new Node(i + numNodes, self.canvas.width * 0.89, self.canvas.height * ((i + 1) / (rNodes + 1)), self.canvas.height * (1 / (2 * (rNodes + 1))), (Math.random() * 20).toFixed(2));
|
||||||
|
self.nodes[i + numNodes].draw();
|
||||||
|
}
|
||||||
|
//self.nodes["hidden1"] = new Node("hidden1", self.canvas.width * 0.3, self.canvas.height * 0.5, 0, "");
|
||||||
|
//self.nodes["hidden2"] = new Node("hidden2", self.canvas.width * 0.6, self.canvas.height * 0.5, 0, "");
|
||||||
|
|
||||||
|
for (i = 0; i < numNodes; i++) {
|
||||||
|
new Edge(i, "hidden1");
|
||||||
|
}
|
||||||
|
new Edge("hidden1", "hidden2");
|
||||||
|
for (i = numNodes; i < numNodes + rNodes; i++) {
|
||||||
|
new Edge("hidden2", i);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onResize = function () {
|
||||||
|
self.draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onDestroy = function () {};
|
||||||
205
Widgets/vessels/vessels.js
Normal file
205
Widgets/vessels/vessels.js
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
self.onInit = function () {
|
||||||
|
volume = 0;
|
||||||
|
fluidLevel = 0;
|
||||||
|
self.ctx.$container.append(
|
||||||
|
"<div><canvas id='vessel" + self.ctx.defaultSubscription.id + "'></canvas></div>"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
self.onResize = function () {
|
||||||
|
self.draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
//function for scaling a canvas
|
||||||
|
function fitToContainer(canvas) {
|
||||||
|
canvas.style.width = "100%";
|
||||||
|
canvas.style.height = "100%";
|
||||||
|
canvas.width = canvas.offsetWidth;
|
||||||
|
canvas.height = canvas.offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.onDataUpdated = function () {
|
||||||
|
self.ctx.detectChanges();
|
||||||
|
//setup variables
|
||||||
|
self.volume = 0;
|
||||||
|
self.fluidLevel = 0;
|
||||||
|
for (let i = 0; i < self.ctx.defaultSubscription.data.length; i++) {
|
||||||
|
if (self.ctx.defaultSubscription.data[i].dataKey.name === self.ctx.settings.vessels[0].volumeKey) {
|
||||||
|
self.volume = typeof self.ctx.defaultSubscription.data[i].data[0] !== "undefined" ? self.ctx.defaultSubscription.data[i].data[0][1] : 0;
|
||||||
|
} else if (self.ctx.defaultSubscription.data[i].dataKey.name === self.ctx.settings.vessels[0].fluidLevelKey) {
|
||||||
|
self.fluidLevel = typeof self.ctx.defaultSubscription.data[i].data[0] !== "undefined" ? self.ctx.defaultSubscription.data[i].data[0][1] : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.maxHeight = typeof self.ctx.settings.maxHeight !== "undefined" ? self.ctx.settings.maxHeight : 10;
|
||||||
|
self.fluidLevelPercent = self.fluidLevel / self.maxHeight;
|
||||||
|
//draw a new canvas
|
||||||
|
self.draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.drawTank = function (ctx, compartmentWidth, compartmentHeight) {
|
||||||
|
ctx.moveTo(compartmentWidth * 0.05, compartmentHeight * 0.05);
|
||||||
|
ctx.lineTo(compartmentWidth * 0.05, compartmentHeight * 0.95);
|
||||||
|
ctx.ellipse(compartmentWidth / 2, compartmentHeight * 0.95, compartmentWidth / 2 - compartmentWidth * 0.05, compartmentHeight * 0.025, 0, Math.PI, 0, true);
|
||||||
|
ctx.lineTo(compartmentWidth * 0.95, compartmentHeight * 0.05);
|
||||||
|
ctx.ellipse(compartmentWidth / 2, compartmentHeight * 0.05, compartmentWidth / 2 - compartmentWidth * 0.05, compartmentHeight * 0.025, 0, 0, 2 * Math.PI);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.drawPond = function (ctx, compartmentWidth, compartmentHeight) {
|
||||||
|
ctx.moveTo(compartmentWidth * 0.05, compartmentHeight * 0.05);
|
||||||
|
ctx.lineTo(compartmentWidth * 0.15, compartmentHeight * 0.95);
|
||||||
|
ctx.lineTo(compartmentWidth * 0.85, compartmentHeight * 0.95);
|
||||||
|
ctx.lineTo(compartmentWidth * 0.95, compartmentHeight * 0.05);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.drawVessels = function (ctx, canvas, numVessels, cols, rows) {
|
||||||
|
if (numVessels <= cols * rows) {
|
||||||
|
//vessel
|
||||||
|
ctx.beginPath();
|
||||||
|
for (let i = 1; i <= numVessels; i++) {
|
||||||
|
for (let j = 0; j < self.ctx.defaultSubscription.data.length; j++) {
|
||||||
|
//console.log(self.ctx.settings.vessels[i - 1].volumeKey);
|
||||||
|
//console.log(self.ctx.settings.vessels[i - 1].fluidLevelKey);
|
||||||
|
if (self.ctx.defaultSubscription.data[j].dataKey.name === self.ctx.settings.vessels[i - 1].volumeKey) {
|
||||||
|
self.volume = typeof self.ctx.defaultSubscription.data[j].data[0] !== "undefined" ? self.ctx.defaultSubscription.data[j].data[0][1] : 0;
|
||||||
|
} else if (self.ctx.defaultSubscription.data[j].dataKey.name === self.ctx.settings.vessels[i - 1].fluidLevelKey) {
|
||||||
|
self.fluidLevel = typeof self.ctx.defaultSubscription.data[j].data[0] !== "undefined" ? self.ctx.defaultSubscription.data[j].data[0][1] : 0;
|
||||||
|
}
|
||||||
|
//console.log(self.volume);
|
||||||
|
//console.log(self.fluidLevel);
|
||||||
|
}
|
||||||
|
self.maxHeight = typeof self.ctx.settings.vessels[i - 1].maxHeight !== "undefined" ? self.ctx.settings.vessels[i - 1].maxHeight : 10;
|
||||||
|
self.fluidLevelPercent = self.fluidLevel / self.maxHeight;
|
||||||
|
var vesselType = typeof self.ctx.settings.vessels[i - 1].vesselType !== "undefined" ? self.ctx.settings.vessels[i - 1].vesselType : "Tank";
|
||||||
|
var fluidColor = typeof self.ctx.settings.vessels[i - 1].fluidColor !== "undefined" ? self.ctx.settings.vessels[i - 1].fluidColor : "Water";
|
||||||
|
var compartmentWidth = canvas.width / cols;
|
||||||
|
var compartmentHeight = canvas.height / rows;
|
||||||
|
//gradient used as water
|
||||||
|
const grad = ctx.createLinearGradient(0, compartmentHeight * 0.05, 0, compartmentHeight * 0.95);
|
||||||
|
switch(fluidColor){
|
||||||
|
case "Water": grad.addColorStop(0, "rgba(70,220,210,0.75)");grad.addColorStop(0.4, "rgba(0,120,240,0.75)");break;
|
||||||
|
case "Produced Water": grad.addColorStop(0, "rgba(170, 100, 30,1)");grad.addColorStop(0.4, "rgba(85, 50, 15,1");break;
|
||||||
|
case "Oil": grad.addColorStop(0,"rgba(100,100,100,0.75)");grad.addColorStop(0.3, "rgba(25,25,25, 0.85");break;
|
||||||
|
default: grad.addColorStop(0,fluidColor);break;
|
||||||
|
}
|
||||||
|
|
||||||
|
grad.addColorStop(1, "rgba(0,0,0, 0.8)");
|
||||||
|
//draw the vessel
|
||||||
|
switch (vesselType) {
|
||||||
|
case "Pond":
|
||||||
|
self.drawPond(ctx, compartmentWidth, compartmentHeight);
|
||||||
|
break;
|
||||||
|
case "Tank":
|
||||||
|
self.drawTank(ctx, compartmentWidth, compartmentHeight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
//setup clip area of container
|
||||||
|
ctx.clip();
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
//set fill style for water to gradient
|
||||||
|
ctx.fillStyle = grad;
|
||||||
|
//move grid for animation
|
||||||
|
if (self.fluidLevelPercent > 1) {
|
||||||
|
ctx.translate(0, compartmentHeight - (compartmentHeight * 0.95 - compartmentHeight * 0.05) * 1 - compartmentHeight * 0.1);
|
||||||
|
} else {
|
||||||
|
ctx.translate(0, compartmentHeight - (compartmentHeight * 0.95 - compartmentHeight * 0.05) * self.fluidLevelPercent - compartmentHeight * 0.1);
|
||||||
|
}
|
||||||
|
ctx.fillRect(0, compartmentHeight * 0.05, compartmentWidth, compartmentHeight * 0.95);
|
||||||
|
ctx.restore();
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
self.drawTicks(ctx, compartmentWidth, compartmentHeight);
|
||||||
|
self.drawText(ctx, compartmentWidth, compartmentHeight);
|
||||||
|
|
||||||
|
if (i % cols === 0) {
|
||||||
|
ctx.translate(-(cols - 1) * compartmentWidth, compartmentHeight);
|
||||||
|
} else {
|
||||||
|
ctx.translate(compartmentWidth, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error("Not enough space for Vessels");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.drawText = function (ctx, compartmentWidth, compartmentHeight) {
|
||||||
|
fl = typeof self.fluidLevel === 'number' ? self.fluidLevel.toFixed(2) : "0.00";
|
||||||
|
vl = typeof self.volume === 'number' ? self.volume.toFixed(2) : "0.00";
|
||||||
|
ctx.textAlign = "left";
|
||||||
|
ctx.fillStyle = "rgba(0,0,0,1)";
|
||||||
|
var padding = Math.max(Math.sqrt(compartmentWidth), Math.sqrt(compartmentHeight));
|
||||||
|
ctx.fillText(`${(self.fluidLevelPercent * 100).toFixed(2)} %`, compartmentWidth / 4 - padding, compartmentHeight / 2);
|
||||||
|
ctx.fillText(`${fl} Ft`, compartmentWidth / 4 - padding, compartmentHeight / 2 + padding);
|
||||||
|
ctx.fillText(`${vl} BBLs`, compartmentWidth / 4 - padding, compartmentHeight / 2 + 2 * padding);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.drawTicks = function (ctx, compartmentWidth, compartmentHeight, guageAlignment) {
|
||||||
|
ctx.fillStyle = "rgba(0,0,0,1)";
|
||||||
|
ctx.textBaseline = "middle";
|
||||||
|
var widthOffset;
|
||||||
|
switch (guageAlignment) {
|
||||||
|
case "center":
|
||||||
|
widthOffset = compartmentWidth * 0.5;
|
||||||
|
break;
|
||||||
|
case "left":
|
||||||
|
widthOffset = compartmentWidth * 0.05;
|
||||||
|
break;
|
||||||
|
case "right":
|
||||||
|
widthOffset = compartmentWidth * 0.95;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
widthOffset = compartmentWidth * 0.5;
|
||||||
|
}
|
||||||
|
var heightOffset = compartmentHeight * 0.05;
|
||||||
|
var heightRange = compartmentHeight * 0.9;
|
||||||
|
var numTicks = Math.min(Math.round(compartmentHeight / 40), 10);
|
||||||
|
ctx.moveTo(widthOffset, compartmentHeight - heightOffset);
|
||||||
|
ctx.lineTo(widthOffset, heightOffset);
|
||||||
|
|
||||||
|
for (let i = 0; i < numTicks; i++) {
|
||||||
|
if (i % 2) {
|
||||||
|
ctx.moveTo(widthOffset - ctx.lineWidth / 2, heightOffset + (i * heightRange) / numTicks);
|
||||||
|
ctx.lineTo(widthOffset + 10 + ctx.lineWidth / 2, heightOffset + (i * heightRange) / numTicks);
|
||||||
|
ctx.textAlign = "left";
|
||||||
|
ctx.fillText((self.maxHeight * ((numTicks - i) / numTicks)).toFixed(2), widthOffset + 15, heightOffset + (i * heightRange) / numTicks);
|
||||||
|
} else {
|
||||||
|
ctx.moveTo(widthOffset + ctx.lineWidth / 2, heightOffset + (i * heightRange) / numTicks);
|
||||||
|
ctx.lineTo(widthOffset - (10 + ctx.lineWidth / 2), heightOffset + (i * heightRange) / numTicks);
|
||||||
|
ctx.textAlign = "right";
|
||||||
|
ctx.fillText((self.maxHeight * ((numTicks - i) / numTicks)).toFixed(2), widthOffset - 15, heightOffset + (i * heightRange) / numTicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.draw = function () {
|
||||||
|
//self.fluidLevel = typeof self.ctx.defaultSubscription.data[0].data[0] !== "undefined" ? self.ctx.defaultSubscription.data[0].data[0][1] : 0;
|
||||||
|
var numVessels = typeof self.ctx.settings.vessels !== "undefined" ? self.ctx.settings.vessels.length : 1;
|
||||||
|
var vesselType = typeof self.ctx.settings.vessels[0].vesselType !== "undefined" ? self.ctx.settings.vessels[0].vesselType : "Tank";
|
||||||
|
var fluidColor = typeof self.ctx.settings.vessels[0].color !== "undefined" ? self.ctx.settings.vessels[0].color : "Water";
|
||||||
|
var numCols = typeof self.ctx.settings.numCols !== "undefined" ? self.ctx.settings.numCols : 1;
|
||||||
|
var numRows = typeof self.ctx.settings.numRows !== "undefined" ? self.ctx.settings.numRows : 1;
|
||||||
|
|
||||||
|
const canvas = document.getElementById("vessel" + self.ctx.defaultSubscription.id);
|
||||||
|
if (canvas.getContext) {
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
fitToContainer(canvas);
|
||||||
|
//clear frame
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
//line style
|
||||||
|
ctx.lineWidth = Math.max((canvas.width * 0.005) / numCols, (canvas.height * 0.005) / numRows);
|
||||||
|
ctx.lineJoin = "round";
|
||||||
|
ctx.strokeStyle = "black";
|
||||||
|
//text style
|
||||||
|
ctx.font = `${Math.min(Math.sqrt(canvas.width / numCols), Math.sqrt(canvas.height / numRows))}px Times New Roman`;
|
||||||
|
self.drawVessels(ctx, canvas, numVessels, numCols, numRows);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onDestroy = function () {};
|
||||||
|
|
||||||
BIN
__pycache__/thingsboardAPI.cpython-39.pyc
Normal file
BIN
__pycache__/thingsboardAPI.cpython-39.pyc
Normal file
Binary file not shown.
24
getImage.py
Normal file
24
getImage.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPDigestAuth
|
||||||
|
import json
|
||||||
|
def getImage(res):
|
||||||
|
with open(f'./snapshot{res}.jpg', 'wb') as handle:
|
||||||
|
resp = requests.get(f"http://192.168.1.67:3067/cgi-bin/SnapshotJPEG?Resolution={res}", auth=HTTPDigestAuth("ASS", "amerus@1903"), stream=True)
|
||||||
|
for block in resp.iter_content(1024):
|
||||||
|
if not block:
|
||||||
|
break
|
||||||
|
|
||||||
|
handle.write(block)
|
||||||
|
with open(f'./snapshot{res}.jpg', 'rb') as img:
|
||||||
|
encoded_string = base64.b64encode(img.read())
|
||||||
|
|
||||||
|
return encoded_string.decode("UTF-8")
|
||||||
|
|
||||||
|
|
||||||
|
resolutions = ["640x360","1280x720", "1920x1080"]
|
||||||
|
for res in resolutions:
|
||||||
|
with open(f'./snapshot{res}.json', 'w') as f:
|
||||||
|
json.dump({"snapshot": getImage(res)}, f)
|
||||||
|
|
||||||
|
|
||||||
@@ -2,525 +2,12 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 21,
|
"execution_count": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"import requests\n",
|
"import thingsboardAPI\n",
|
||||||
"import json"
|
"from datetime import datetime as dt"
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 40,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"headers = {\"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}\n",
|
|
||||||
"data = '{\"username\":\"nmelone@henry-pump.com\",\"password\":\"gzU6$26v42mU%3jDzTJf\"}'\n",
|
|
||||||
"url_base = \"https://hp.henrypump.cloud/api/\"\n",
|
|
||||||
"response = requests.post(url_base + 'auth/login', headers=headers,data=data)\n",
|
|
||||||
"token = json.loads(response.content.decode(\"UTF-8\"))\n",
|
|
||||||
"headers[\"X-Authorization\"] = \"Bearer \" + token['token']"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 47,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"#Get Customers\n",
|
|
||||||
"customers = requests.get(url_base + \"customers?page=0&pageSize=10\", headers=headers)\n",
|
|
||||||
"customers = json.loads(customers.content.decode(\"UTF-8\"))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 59,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"{\n",
|
|
||||||
" \"data\": [\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"06b6a450-aadd-11ec-8eb3-41740343dd9f\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1648062681877,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BV-602\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BV-602\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"0731e280-d163-11ec-9d28-f57ea5aee126\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1652298379432,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BZ-201\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BZ-201\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"16af78d0-ccb8-11ec-b0e8-ff45c37940c6\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1651785156829,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BW-72\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BW-72\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"4ac91370-cca3-11ec-9cdb-5b8ff28e4445\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1651776224807,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BX-101\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BX-101\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"9a37c410-d144-11ec-a502-79978f9d7342\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1652285311697,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BW-041\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BW-041\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"c50ec0b0-d150-11ec-9a8d-d3ef2e0c0a7d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1652290537531,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"S-601\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"S-601\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"d8433890-d147-11ec-8e7b-4d9a3bf70f9d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1652286704281,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BY-501\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BY-501\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"e9b87630-aadc-11ec-8eb3-41740343dd9f\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1648062633235,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"BP-601\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"BP-601\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" {\n",
|
|
||||||
" \"id\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE\",\n",
|
|
||||||
" \"id\": \"ed19b7e0-d213-11ec-8c76-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"createdTime\": 1652374356574,\n",
|
|
||||||
" \"additionalInfo\": {\n",
|
|
||||||
" \"gateway\": false,\n",
|
|
||||||
" \"overwriteActivityTime\": false,\n",
|
|
||||||
" \"description\": \"\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"tenantId\": {\n",
|
|
||||||
" \"entityType\": \"TENANT\",\n",
|
|
||||||
" \"id\": \"a610ad00-52e2-11ec-89c2-2f343e6c262d\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"customerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"name\": \"CF-501\",\n",
|
|
||||||
" \"type\": \"advvfdipp\",\n",
|
|
||||||
" \"label\": \"CF-501\",\n",
|
|
||||||
" \"deviceProfileId\": {\n",
|
|
||||||
" \"entityType\": \"DEVICE_PROFILE\",\n",
|
|
||||||
" \"id\": \"4ea52d70-a0b7-11ec-8e7b-f34df8141ace\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"deviceData\": {\n",
|
|
||||||
" \"configuration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" },\n",
|
|
||||||
" \"transportConfiguration\": {\n",
|
|
||||||
" \"type\": \"DEFAULT\"\n",
|
|
||||||
" }\n",
|
|
||||||
" },\n",
|
|
||||||
" \"firmwareId\": null,\n",
|
|
||||||
" \"softwareId\": null,\n",
|
|
||||||
" \"ownerId\": {\n",
|
|
||||||
" \"entityType\": \"CUSTOMER\",\n",
|
|
||||||
" \"id\": \"4b856c50-a0b6-11ec-a588-ad8278896f52\"\n",
|
|
||||||
" }\n",
|
|
||||||
" }\n",
|
|
||||||
" ],\n",
|
|
||||||
" \"totalPages\": 1,\n",
|
|
||||||
" \"totalElements\": 9,\n",
|
|
||||||
" \"hasNext\": false\n",
|
|
||||||
"}\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"#Get Devices\n",
|
|
||||||
"for customer in customers['data']:\n",
|
|
||||||
" if customer[\"name\"] == \"Faskens\":\n",
|
|
||||||
" cid = customer[\"id\"][\"id\"]\n",
|
|
||||||
"devices = requests.get(url_base + f\"customer/{cid}/devices?page=0&pageSize=10\", headers=headers)\n",
|
|
||||||
"devices = json.loads(devices.content.decode(\"UTF-8\"))\n",
|
|
||||||
"print(json.dumps(devices,indent=4))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 60,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"[\n",
|
|
||||||
" \"flowrate\",\n",
|
|
||||||
" \"hartrevtotal\",\n",
|
|
||||||
" \"hartfwdtotal\",\n",
|
|
||||||
" \"hartnettotal\",\n",
|
|
||||||
" \"maxvfdfrequency\",\n",
|
|
||||||
" \"minvfdfrequency\",\n",
|
|
||||||
" \"controllerfault_program\",\n",
|
|
||||||
" \"controllerfault_io\",\n",
|
|
||||||
" \"vfd_fault\",\n",
|
|
||||||
" \"last_vfd_fault_code\",\n",
|
|
||||||
" \"sensorheight\",\n",
|
|
||||||
" \"temperaturestartuplimit\",\n",
|
|
||||||
" \"temperatureshutdownlimit\",\n",
|
|
||||||
" \"pressurestartuplimit\",\n",
|
|
||||||
" \"pressureshutdownlimit\",\n",
|
|
||||||
" \"alarmfluidlevel\",\n",
|
|
||||||
" \"tubingpressuresetpoint\",\n",
|
|
||||||
" \"manualfrequencysetpoint\",\n",
|
|
||||||
" \"fluidlevelsetpoint\",\n",
|
|
||||||
" \"flowsetpoint\",\n",
|
|
||||||
" \"stopcommand\",\n",
|
|
||||||
" \"startcommand\",\n",
|
|
||||||
" \"startpermissive\",\n",
|
|
||||||
" \"runpermissive\",\n",
|
|
||||||
" \"alarmlockout\",\n",
|
|
||||||
" \"alarmvfd\",\n",
|
|
||||||
" \"alarmtubingpressure\",\n",
|
|
||||||
" \"alarmintaketemperature\",\n",
|
|
||||||
" \"alarmintakepressure\",\n",
|
|
||||||
" \"alarmflowrate\",\n",
|
|
||||||
" \"energytotalyesterday\",\n",
|
|
||||||
" \"flowtotalyesterday\",\n",
|
|
||||||
" \"fluidspecificgravity\",\n",
|
|
||||||
" \"downholesensorstatus\",\n",
|
|
||||||
" \"vfdcurrent\",\n",
|
|
||||||
" \"energytotal\",\n",
|
|
||||||
" \"flowtotal\",\n",
|
|
||||||
" \"vfdfrequency\",\n",
|
|
||||||
" \"wellstatus\",\n",
|
|
||||||
" \"pidcontrolmode\",\n",
|
|
||||||
" \"tubingpressure\",\n",
|
|
||||||
" \"intaketemperature\",\n",
|
|
||||||
" \"intakepressure\",\n",
|
|
||||||
" \"fluidlevel\",\n",
|
|
||||||
" \"wellstatus_int\",\n",
|
|
||||||
" \"vfd_fault_int\",\n",
|
|
||||||
" \"last_vfd_fault_code_int\",\n",
|
|
||||||
" \"alarmfluidlevel_int\",\n",
|
|
||||||
" \"startpermissive_int\",\n",
|
|
||||||
" \"runpermissive_int\",\n",
|
|
||||||
" \"alarmlockout_int\",\n",
|
|
||||||
" \"alarmvfd_int\",\n",
|
|
||||||
" \"alarmtubingpressure_int\",\n",
|
|
||||||
" \"alarmintaketemperature_int\",\n",
|
|
||||||
" \"alarmintakepressure_int\",\n",
|
|
||||||
" \"alarmflowrate_int\",\n",
|
|
||||||
" \"downholesensorstatus_int\",\n",
|
|
||||||
" \"pidcontrolmode_int\",\n",
|
|
||||||
" \"resetalarms\",\n",
|
|
||||||
" \"flowrate_gpm\",\n",
|
|
||||||
" \"flowmeter_fault\",\n",
|
|
||||||
" \"flowmeter_fault_int\",\n",
|
|
||||||
" \"RuleNodeState_6e98a3f0-d6b3-11ec-b5bf-ff45c37940c6\",\n",
|
|
||||||
" \"sumFlowRate\"\n",
|
|
||||||
"]\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"#Get Keys\n",
|
|
||||||
"for device in devices['data']:\n",
|
|
||||||
" if device[\"name\"] == \"BV-602\":\n",
|
|
||||||
" did = device['id']['id']\n",
|
|
||||||
" eType = device['id']['entityType']\n",
|
|
||||||
"keys = requests.get(url_base + f\"plugins/telemetry/{eType}/{did}/keys/timeseries\", headers=headers)\n",
|
|
||||||
"keys = json.loads(keys.content.decode(\"UTF-8\"))\n",
|
|
||||||
"\n",
|
|
||||||
"print(json.dumps(keys,indent=4))"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -529,7 +16,41 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"#Get Telemetry"
|
"tb = thingsboardAPI(\"nmelone@henry-pump.com\", \"gzU6$26v42mU%3jDzTJf\", \"hp.henrypump.cloud\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"#tb"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"customers = tb.getCustomers()\n",
|
||||||
|
"devices = tb.getDevices(customers=customers, target_customer=\"Amerus Safety Solutions\")\n",
|
||||||
|
"eType, did, keys = tb.getDeviceKeys(devices=devices, target_device=\"Camera Trailer 106\")\n",
|
||||||
|
"telemetry = tb.getTelemetry(startTs=tb.convertDateTimeToMS(\"26 May 2022, 13:57:00\"), endTs=int(dt.now().timestamp() * 1000), keys=\",\".join(keys), eType=eType, did=did)\n",
|
||||||
|
"#telemetry"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 10,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import base64\n",
|
||||||
|
"for snap in telemetry[\"snapshot\"]:\n",
|
||||||
|
" with open('/Users/nico/Documents/tbTimelapse/'+ str(snap[\"ts\"]) + \".jpg\", 'wb') as img:\n",
|
||||||
|
" img.write(base64.b64decode(snap[\"value\"]))"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
62
thingsboardAPI.py
Normal file
62
thingsboardAPI.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from datetime import datetime as dt
|
||||||
|
|
||||||
|
class ThingsBoardAPI():
|
||||||
|
def __init__(self, username, password,domain):
|
||||||
|
self.headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
||||||
|
self.credentials = json.dumps({"username":f"{username}", "password":f"{password}"})
|
||||||
|
self.url_base = f"https://{domain}/api/"
|
||||||
|
self.getJWT()
|
||||||
|
|
||||||
|
def getJWT(self):
|
||||||
|
response = requests.post(self.url_base + 'auth/login', headers=self.headers,data=self.credentials)
|
||||||
|
self.token = response.json()
|
||||||
|
self.headers["X-Authorization"] = "Bearer " + self.token['token']
|
||||||
|
|
||||||
|
def getCustomers(self, page=0, pageSize=10):
|
||||||
|
customers = requests.get(self.url_base + f"customers?page={page}&pageSize={pageSize}", headers=self.headers)
|
||||||
|
return customers.json()
|
||||||
|
|
||||||
|
def getAssets(self, customers, target_customer, page=0, pageSize=10):
|
||||||
|
for c in customers['data']:
|
||||||
|
if c["name"] == target_customer:
|
||||||
|
cid = c["id"]["id"]
|
||||||
|
assets = requests.get(self.url_base + f"customers/{cid}/assets?page={page}&pageSize={pageSize}")
|
||||||
|
return assets.json()
|
||||||
|
|
||||||
|
def getDevices(self,customers,target_customer, page=0, pageSize=10):
|
||||||
|
for c in customers['data']:
|
||||||
|
if c["name"] == target_customer:
|
||||||
|
cid = c["id"]["id"]
|
||||||
|
devices = requests.get(self.url_base + f"customer/{cid}/devices?page={page}&pageSize={pageSize}", headers=self.headers)
|
||||||
|
return devices.json()
|
||||||
|
|
||||||
|
def getDeviceKeys(self, devices,target_device):
|
||||||
|
for d in devices['data']:
|
||||||
|
if d["name"] == target_device:
|
||||||
|
did = d['id']['id']
|
||||||
|
eType = d['id']['entityType']
|
||||||
|
keys = requests.get(self.url_base + f"plugins/telemetry/{eType}/{did}/keys/timeseries", headers=self.headers)
|
||||||
|
return eType, did, keys.json()
|
||||||
|
|
||||||
|
def getTelemetry(self, startTs, endTs, keys, eType, did):
|
||||||
|
telemetry = requests.get(self.url_base + f"plugins/telemetry/{eType}/{did}/values/timeseries?startTs={startTs}&endTs={endTs}&keys={keys}", headers=self.headers)
|
||||||
|
return telemetry.json()
|
||||||
|
|
||||||
|
def deleteTimeSeriesAll(self, keys, eType, did):
|
||||||
|
resp = requests.delete(self.url_base + f"plugins/telemetry/{eType}/{did}/timeseries/delete?deleteAllDataForKeys=true&keys={keys}", headers=self.headers)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
def deleteTimeSeriesScoped(self, startTs, endTs, keys, eType, did):
|
||||||
|
resp = requests.delete(self.url_base + f"plugins/telemetry/{eType}/{did}/timeseries/delete?startTs={startTs}&endTs={endTs}&keys={keys}", headers=self.headers)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
def convertDateTimeToMS(self,datestring):
|
||||||
|
date = dt.strptime(datestring,"%d %b %Y, %H:%M:%S")
|
||||||
|
return int(date.timestamp() * 1000)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
print(f"Base URL: {self.url_base}")
|
||||||
|
print(f"Token: {self.token['token']}")
|
||||||
|
return ""
|
||||||
90
timelapse.ipynb
Normal file
90
timelapse.ipynb
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from tb_rest_client.rest_client_pe import *\n",
|
||||||
|
"from tb_rest_client.rest import ApiException\n",
|
||||||
|
"import base64\n",
|
||||||
|
"from datetime import datetime as dt"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def convertDateTimeToMS(datestring):\n",
|
||||||
|
" date = dt.strptime(datestring,\"%d %b %Y, %H:%M:%S\")\n",
|
||||||
|
" return int(date.timestamp() * 1000)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"url = \"https://hp.henrypump.cloud\"\n",
|
||||||
|
"username = \"nmelone@henry-pump.com\"\n",
|
||||||
|
"password = \"gzU6$26v42mU%3jDzTJf\"\n",
|
||||||
|
"with RestClientPE(base_url=url) as rest_client:\n",
|
||||||
|
" try:\n",
|
||||||
|
" rest_client.login(username=username, password=password)\n",
|
||||||
|
" customer = rest_client.get_customers(page_size=10,page=0,text_search=\"Amerus Safety Solutions\")\n",
|
||||||
|
" #print(customer)\n",
|
||||||
|
" cid = customer.data[0].id.id\n",
|
||||||
|
" device = rest_client.get_customer_devices(customer_id=cid, page=0, page_size=10,text_search=\"Camera Trailer 104\")\n",
|
||||||
|
" #print(device)\n",
|
||||||
|
" eType = device.data[0].id.entity_type\n",
|
||||||
|
" eid = device.data[0].id.id\n",
|
||||||
|
" start = convertDateTimeToMS(\"28 Jun 2022, 00:00:00\")\n",
|
||||||
|
" end = int(dt.now().timestamp() * 1000)\n",
|
||||||
|
" telemetry = rest_client.get_timeseries(entity_type=eType, entity_id=eid , keys=\"snapshot\", start_ts=start, end_ts=end, limit=1000)\n",
|
||||||
|
" #print(telemetry)\n",
|
||||||
|
" except ApiException as e:\n",
|
||||||
|
" print(e)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 9,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for snap in telemetry[\"snapshot\"]:\n",
|
||||||
|
" with open('/Users/nico/Documents/tbTimelapse/'+ str(snap[\"ts\"]) + \".jpg\", 'wb') as img:\n",
|
||||||
|
" img.write(base64.b64decode(snap[\"value\"]))"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"interpreter": {
|
||||||
|
"hash": "32b1684233d9748bd1bb5a29a1b19459c9564d6488d1324e633b9c48826c5d03"
|
||||||
|
},
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3.10.4 ('thingsboard')",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.10.4"
|
||||||
|
},
|
||||||
|
"orig_nbformat": 4
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user