Skip to content

Commit

Permalink
Merge pull request #4 from JuliusH4/feature
Browse files Browse the repository at this point in the history
Feature
  • Loading branch information
JuliusH4 committed Oct 12, 2022
2 parents 07fa1e4 + 3abf1ed commit 18cf0cd
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 112 deletions.
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# StreamDeck-NetatmoCO2
Unofficial Plugin for an Elgato StreamDeck plugin to display CO2-value form Netatmo weather station.
Unofficial Plugin for an Elgato StreamDeck to display CO2-value form Netatmo weather stations.

The value will be refreshed every 15 minutes or by pressing the key. (Pay attention, this just updates the value provided by Netatmo, which will not be refreshed every time)

>**This plugin is currently under development**
Client ID, Client Secret and a refresh token have to be created manually (e.g. using [Postman](https://www.postman.com/)). Take a look at the [Netatmo documentation](https://dev.netatmo.com/apidocumentation/oauth) for further information. This process will be improved in future!

## Build
[Distribution Tool](https://developer.elgato.com/documentation/stream-deck/sdk/packaging/) for Windows can be downloaded [here](https://developer.elgato.com/documentation/stream-deck/distributiontool/DistributionToolWindows.zip).
The plugin can be build with the official
[Distribution Tool](https://developer.elgato.com/documentation/stream-deck/sdk/packaging/) for Windows, which can be downloaded [here](https://developer.elgato.com/documentation/stream-deck/distributiontool/DistributionToolWindows.zip).
To build the plugin, use the following command: `./DistributionTool.exe -b -i com.juliushenle.netatmo-co2.sdPlugin -o dist`.

## Open Features
- Support of multiple wether stations
- Easy creation of credentials (client_id, client_secret, refresh_token)
- Individual co2 thresholds
- Individual auto-refresh interval
184 changes: 74 additions & 110 deletions com.juliushenle.netatmo-co2.sdPlugin/src/streamdeck.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
/* global $CC, Utils, $SD */

/**
* Here are a couple of wrappers we created to help you quickly setup
* your plugin and subscribe to events sent by Stream Deck to your plugin.
*/

/**
* The 'connected' event is sent to your plugin, after the plugin's instance
* is registered with Stream Deck software. It carries the current websocket
* and other information about the current environmet in a JSON object
* You can use it to subscribe to events you want to use in your plugin.
*/

$SD.on("connected", (jsonObj) => connected(jsonObj));

let access_token = null;
Expand All @@ -33,26 +21,6 @@ function connected(jsn) {
"com.juliushenle.netatmo-co2.displayco2.didReceiveSettings",
(jsonObj) => action.onDidReceiveSettings(jsonObj)
);
$SD.on(
"com.juliushenle.netatmo-co2.displayco2.propertyInspectorDidAppear",
(jsonObj) => {
console.log(
"%c%s",
"color: white; background: black; font-size: 13px;",
"[app.js]propertyInspectorDidAppear:"
);
}
);
$SD.on(
"com.juliushenle.netatmo-co2.displayco2.propertyInspectorDidDisappear",
(jsonObj) => {
console.log(
"%c%s",
"color: white; background: red; font-size: 13px;",
"[app.js]propertyInspectorDidDisappear:"
);
}
);
}

// ACTIONS
Expand All @@ -65,105 +33,40 @@ const action = {
* input-field it get's saved to Stream Deck persistently and the plugin
* will receive the updated 'didReceiveSettings' event.
*/

console.log("didReciveSettings")
this.settings = Utils.getProp(jsn, 'payload.settings', {});

this.settings = Utils.getProp(jsn, "payload.settings", {});
},

/**
* The 'willAppear' event is the first event a key will receive, right before it gets
* shown on your Stream Deck and/or in Stream Deck software.
* This event is a good place to setup your plugin and look at current settings (if any),
* which are embedded in the events payload.
*/

onWillAppear: function (jsn) {
/**
* The willAppear event carries your saved settings (if any). You can use these settings
* to setup your plugin or save the settings for later use.
* If you want to request settings at a later time, you can do so using the
* 'getSettings' event, which will tell Stream Deck to send your data
* (in the 'didReceiveSettings above)
*
*/

console.log("onWillAppear")
this.settings = jsn.payload.settings;
console.log("settings", this.settings)

setInterval(() => {
console.info("Auto update");
this.updateKey(jsn);
}, 15 * 60 * 1000); // every 15 minutes
},

onKeyUp: function (jsn) {
console.log("settings", this.settings)
const headers = new Headers();
headers.append("Authorization", `Bearer ${access_token}`);

const requestOptions = {
method: "GET",
headers,
redirect: "follow",
};

fetch("https://api.netatmo.com/api/getstationsdata", requestOptions)
.then((response) => {
resultStatus = response.status;
return response.json();
})
.then((result) => {
console.log(result);
switch (resultStatus) {
case 200:
const co2_value = result.body.devices[0].dashboard_data.CO2;
console.log("CO2 Value", co2_value);
$SD.api.setTitle(jsn.context, co2_value);
console.log("title set");

const imagePath =
co2_value < 1000
? "images/assets/key_green.png"
: co2_value < 2000
? "images/assets/key_orange.png"
: "images/assets/key_red.png";
console.log("LoadImage:", imagePath);
this.setImage(jsn, imagePath);
console.log("Image succesful updated");
break;
case 403:
const isError = result.error.code != undefined;
if (isError && (result.error.code == 3 || result.error.code == 2)) {
console.log("Refresh");
if (this.settings.refresh_token != null) {
newToken(this.settings.client_id, this.settings.client_secret, this.settings.refresh_token);
}
break;
}
default:
console.error("unknown response", resultStatus, result);
}
})
.catch((error) => console.log("error", error));
this.updateKey(jsn);
},

onSendToPlugin: function (jsn) {
/**
* This is a message sent directly from the Property Inspector
* (e.g. some value, which is not saved to settings)
* You can send this event from Property Inspector (see there for an example)
*/

const sdpi_collection = Utils.getProp(jsn, "payload.sdpi_collection", {});
console.log("onSentToPlugin", sdpi_collection)

if (sdpi_collection.key === "btnReset") {
console.log("reset access token")
access_token = null
console.log("reset access token");
access_token = null;
}
},

/**
* This snippet shows how you could save settings persistantly to Stream Deck software.
* It is not used in this example plugin.
*/

setImage: function (jsn, image) {
loadImageAsDataUri(image, (imgUrl) => {
$SD.api.setImage(
Expand All @@ -185,6 +88,66 @@ const action = {
}
},

updateKey: function (jsn) {
console.log("run try");
this.getco2value().catch((error) => {
console.log("run catch", this.settings.refresh_token);
if (this.settings.refresh_token != null) {
newToken(
this.settings.client_id,
this.settings.client_secret,
this.settings.refresh_token
);
this.getco2value(jsn);
}
});
},

getco2value: async function (jsn) {
const headers = new Headers();
headers.append("Authorization", `Bearer ${access_token}`);

const requestOptions = {
method: "GET",
headers,
redirect: "follow",
};

await fetch("https://api.netatmo.com/api/getstationsdata", requestOptions)
.then((response) => {
resultStatus = response.status;
return response.json();
})
.then((result) => {
console.info("Response getStationsData", result);
switch (resultStatus) {
case 200:
co2_value = result.body.devices[0].dashboard_data.CO2;
console.log("set Title", co2_value);
$SD.api.setTitle(jsn.context, co2_value);
const imagePath =
co2_value < 1000
? "images/assets/key_green.png"
: co2_value < 2000
? "images/assets/key_orange.png"
: "images/assets/key_red.png";
this.setImage(jsn, imagePath);
break;
case 403:
const isError = result.error != undefined;
if (isError && result.error.code == 3) {
console.info("Refresh required");
throw "Refresh required";
}
if (isError && result.error.code == 2) {
console.info("Invalid access token");
throw "New access token required";
}
default:
console.error("unknown response", resultStatus, result);
}
});
},
};

const newToken = (client_id, client_secret, refresh_token) => {
Expand All @@ -210,6 +173,7 @@ const newToken = (client_id, client_secret, refresh_token) => {
})
.then((result) => {
if (isresultOk) {
console.info("Set new access token", access_token);
access_token = result.access_token;
} else {
console.error("unknown resopnse while refresh", result);
Expand All @@ -219,15 +183,15 @@ const newToken = (client_id, client_secret, refresh_token) => {
};

function loadImageAsDataUri(url, callback) {
var image = new Image();
let image = new Image();

image.onload = function () {
var canvas = document.createElement("canvas");
let canvas = document.createElement("canvas");

canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;

var ctx = canvas.getContext("2d");
let ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
callback(canvas.toDataURL("image/png"));
};
Expand Down

0 comments on commit 18cf0cd

Please sign in to comment.