Read the statement by Michael Teeuw here.
ShellyPV mit Shelly 2.5
-
Den einzigen Unterschied sehe ich hier:
Beide Lampen aus:
“relays”:[{“ison”:false,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”},{“ison”:false,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”}]
Kanal 0 an:
“relays”:[{“ison”:true,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”},{“ison”:false,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”}]
Kanal 1 an:
“relays”:[{“ison”:false,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”},{“ison”:true,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”}]
Beide Kanäle an:
“relays”:[{“ison”:true,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”},{“ison”:true,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”}]Ich sehe zwar, das sich bei ison: true / false was ändert, aber da steht nichts von Kanäle.
-
@visionmaster
Also ich sehe im Vergleich zu einem anderen Shelly mit nur einem Kanal, daß im Block “relays” nur 1 “Block” existiert, während es beim Shelly 2.5 > 2 Blöcke sind.
Einfacher shelly:
“relays”:[{“ison”:false,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“source”:“cloud”}]
Shelly mit 2 Ausgängen:
“relays”:[{“ison”:false,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”},{“ison”:true,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“overpower”:false,“overtemperature”:false,“is_valid”:true,“source”:“http”}]Vielleicht muss man die Abfrage “erweitern”
-
Vielleicht kann ja die Config erweitert werden:
shellys: [
{ name: “Küche Hauptlicht”, id: “#####”,Kanal:“0” },
{ name: “Küche Unterschrank”, id: “####” ,Kanal:“1”},
],
Und natürlich das Script :) -
Und hier noch eine Info:
Bei einem shellyrgbw2 heißt das Zauberwort “lights”
Vielleicht könnte man da ja auch den OnOff Status abfragen“lights”:[{“ison”:false,“source”:“http”,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“mode”:“color”,“red”:0,“green”:0,“blue”:255,“white”:0,“gain”:79,“effect”:0,“transition”:0,“power”:0,“overpower”:false,“brightness”:79}]
Komplett:
{“isok”:true,“data”:{“online”:true,“device_status”:{“ram_free”:39280,“serial”:27538,“_updated”:“2024-11-26 19:42:59”,“inputs”:[{“input”:0,“event”:“”,“event_cnt”:0}],“unixtime”:1732650104,“cloud”:{“enabled”:true,“connected”:true},“time”:“20:42”,“meters”:[{“power”:0,“is_valid”:true,“overpower”:false,“timestamp”:1732653779,“counters”:[0.893,0,0],“total”:1341}],“ram_total”:51672,“mode”:“color”,“wifi_sta”:{“connected”:true,“ssid”:“#####”,“ip”:“192.168.178.27”,“rssi”:-73},“fs_free”:151353,“has_update”:false,“cfg_changed_cnt”:1,“actions_stats”:{“skipped”:0},“uptime”:7212089,“mac”:“#####”,“fs_size”:233681,“getinfo”:{“fw_info”:{“device”:“shellyrgbw2-#####”,“fw”:“20230913-113259/v1.14.0-gcb84623”,“mode”:“color”}},“mqtt”:{“connected”:false},“update”:{“status”:“idle”,“has_update”:false,“new_version”:“20230913-113259/v1.14.0-gcb84623”,“old_version”:“20230913-113259/v1.14.0-gcb84623”,“beta_version”:“20231107-164040/v1.14.1-rc1-g0617c15”},“input”:0,“lights”:[{“ison”:false,“source”:“http”,“has_timer”:false,“timer_started”:0,“timer_duration”:0,“timer_remaining”:0,“mode”:“color”,“red”:0,“green”:0,“blue”:255,“white”:0,“gain”:79,“effect”:0,“transition”:0,“power”:0,“overpower”:false,“brightness”:79}] -
@visionmaster both, please try to use code blocks around data like this and config and logs
paste the text into the message editor
select the text
hit the </> button in the editor bar -
@visionmaster Hi, werde es mir morgen anschauen. Danke für die Infos.
-
Hi,
please replace the node_helper.js in the module MMM-ShellyPV with the following code. If you receive an error, please describe what you see or what error messages you get. Since I do not have such a device yet it is not possible for me to test it.
At first I start with the Shelly 2.5 device. The “shellyrgbw2” is then the next step!
The config must be like this for these specific 2.5 devices:
shellysPV: [ { name: "Kueche 1", id: "dcda0cb93bb8", ch: "1" }, // Channel 1 (relay[0]) { name: "Kueche 2", id: "dcda0cb93bb8", ch: "2" } // Channel 2 (relay[1]) ]
I’ve used 1 and 2 instead of 0 and 1. It is easier for my head :-)
And next the updated node_helper.js file:
const NodeHelper = require("node_helper"); const axios = require("axios"); module.exports = NodeHelper.create({ start: function () { this.config = {}; setTimeout(() => { console.log("MagicMirror is ready. Fetching ShellyPV status..."); this.fetchShellyPVStatus(); }, 15000); // Delay to ensure MagicMirror is fully loaded }, socketNotificationReceived: function (notification, payload) { if (notification === "CONFIG") { this.config = payload; if (this.config.shellysPV && Array.isArray(this.config.shellysPV)) { console.log("Configuration received, fetching ShellyPV status..."); this.fetchShellyPVStatus(); } } else if (notification === "GET_SHELLYPV_STATUS") { this.fetchShellyPVStatus(); } }, fetchShellyPVStatus: async function () { const results = []; if (!this.config.shellysPV || !Array.isArray(this.config.shellysPV)) { console.error("No valid shellysPV configuration found or 'shellysPV' is not an array."); return; } for (const shellyPV of this.config.shellysPV) { try { const response = await axios.post( `${this.config.serverUri}/device/status`, `id=${shellyPV.id}&auth_key=${this.config.authKey}` ); const data = response.data?.data?.device_status; if (data) { let isOn = false; let power = null; // Handle multi-channel devices if (data.relays && shellyPV.ch) { const channelIndex = parseInt(shellyPV.ch, 10) - 1; // Convert to zero-based index if (channelIndex >= 0 && channelIndex < data.relays.length) { const relay = data.relays[channelIndex]; const meter = data.meters?.[channelIndex]; isOn = relay.ison; power = meter?.power || 0; } else { console.error(`Invalid channel index for ${shellyPV.name}: ${shellyPV.ch}`); } } // Handle single-channel devices (or default behavior for Gen 1/2) else if (data.relays) { isOn = data.relays[0].ison; power = data.meters ? data.meters[0].power : null; } // Handle Gen 3 devices (pm1:0 structure) else if (data["pm1:0"]) { isOn = true; // Assume true if data exists power = data["pm1:0"].apower; } // Handle switch:0 structure else if (data["switch:0"]) { isOn = data["switch:0"].output; power = data["switch:0"].apower; } results.push({ name: shellyPV.name, isOn: isOn, power: power !== undefined ? power : null, statusClass: isOn ? 'on' : 'off', // Dynamically set status class }); } else { results.push({ name: shellyPV.name, isOn: false, power: null, statusClass: 'off', // Default to off if no data found }); } } catch (error) { console.error(`Error fetching status for ${shellyPV.name}:`, error); results.push({ name: shellyPV.name, isOn: false, power: null, statusClass: 'off', // Default to off on error }); } } this.sendSocketNotification("SHELLYPV_STATUS_UPDATE", results); }, });
For devices without a ch parameter, the logic defaults to using the first relay and meter (relays[0], meters[0]), ensuring compatibility with single-channel or older devices.
If a ch parameter is specified in the config, the code now accesses the corresponding relays and meters arrays for the specific channel. -
@chrisfr1976
Hi und Danke !!!
Das neue Script funktioniert einwandfrei.
Ich hatte allerdings vergessen zu erwähnen, daß ich das ShellyStatusTable benutze und nicht das ShellyPV.
Daher ging es erst nicht. Nachdem ich aber alle PV entfernt habe, ging es sofort. Tausend Dank… Über die Abfrage der ShellyRGBW würde ich mich aber auch sehr freuen :) -
@visionmaster
Perfekt. Freut mich! Morgen probiere mich an der RGB Shelly. Kann es aber noch nicht versprechen. Wenn das läuft aktualisiere ich die Module für Table und PV bei Github. -
@visionmaster
Vielleicht einfacher als gedacht. Wieder als node_helper.js übernehmen:const NodeHelper = require("node_helper"); const axios = require("axios"); module.exports = NodeHelper.create({ start: function () { this.config = {}; setTimeout(() => { console.log("MagicMirror is ready. Fetching ShellyPV status..."); this.fetchShellyPVStatus(); }, 15000); // Delay to ensure MagicMirror is fully loaded }, socketNotificationReceived: function (notification, payload) { if (notification === "CONFIG") { this.config = payload; if (this.config.shellysPV && Array.isArray(this.config.shellysPV)) { console.log("Configuration received, fetching ShellyPV status..."); this.fetchShellyPVStatus(); } } else if (notification === "GET_SHELLYPV_STATUS") { this.fetchShellyPVStatus(); } }, fetchShellyPVStatus: async function () { const results = []; if (!this.config.shellysPV || !Array.isArray(this.config.shellysPV)) { console.error("No valid shellysPV configuration found or 'shellysPV' is not an array."); return; } for (const shellyPV of this.config.shellysPV) { try { const response = await axios.post( `${this.config.serverUri}/device/status`, `id=${shellyPV.id}&auth_key=${this.config.authKey}` ); const data = response.data?.data?.device_status; if (data) { let isOn = false; let power = null; // Check for Gen 1/2 structure (relay-based devices) if (data.relays) { const channel = parseInt(shellyPV.ch || 0, 10); isOn = data.relays[channel]?.ison || false; power = data.meters?.[channel]?.power || null; } // Check for Gen 3 structure (pm1:0 devices) else if (data["pm1:0"]) { isOn = true; // Assume true if data exists for the device power = data["pm1:0"].apower; // Use 'apower' from pm1:0 } // Check for "switch:0" structure else if (data["switch:0"]) { isOn = data["switch:0"].output; // Use 'output' for on/off status power = data["switch:0"].apower; // Use 'apower' for power } // Check for RGB Shelly structure (lights array) else if (data.lights) { const light = data.lights[0]; // Assume single channel for RGB device isOn = light?.ison || false; power = light?.power || null; } results.push({ name: shellyPV.name, isOn: isOn, power: power !== undefined ? power : null, statusClass: isOn ? 'on' : 'off', // Dynamically set status class }); } else { results.push({ name: shellyPV.name, isOn: false, power: null, statusClass: 'off', // Default to off if no data found }); } } catch (error) { console.error(`Error fetching status for ${shellyPV.name}:`, error); results.push({ name: shellyPV.name, isOn: false, power: null, statusClass: 'off', // Default to off on error }); } } this.sendSocketNotification("SHELLYPV_STATUS_UPDATE", results); }, });
In der config wieder wie üblich einrichten.