@wendy2702
Dann fang ich mal an.
Hab zwei verschiedene Modi (light/dark)
@wendy2702
Dann fang ich mal an.
Hab zwei verschiedene Modi (light/dark)
@walter-white
Falls Du es brauchen kannst anbei ein Blockly-Script zum Importieren mit dem ich automatisch für alle in der App erstellten Programme Datenpunkte für deren Aktivierung anlege.
vacuum.program.xml
Wenn ein neues Programm dazukommt einfach das Script neu starten.
@myzerat
Vielleicht wäre das hier ein Ansatz
Bei den Funktionen in den Objekten müsstest Du nur bei den einzelnen Datenpunkten "Batteriestatus" hinterlegen.
(nicht verwirren lassen, bei mir steht da 'Batteriestatus_Prozent' weil's eine manuell angelegte Aufzählung ist)
Bei neuen Geräten dann einfach die Funktion mit angeben, der Rest läuft automatisch.
In der Nachricht werden aber nur die Geräte gezählt. Die Gerätenamen werden nicht ausgegeben.
PS
Natürlich müssen die "Batterien" zuerst bei den Aufzählungen hinterlegt werden
Das hintere "+" auswählen
und dann "BATTERIESTATUS"
@pmayer sagte in cod.m ZigBee Coordinator (PoE/non-PoE) - made in Germany:
Nimm dir mal bitte die
.ota.bin
von https://github.com/codm/czc-fw/releases/tag/v2.0.0 und mach das über File Update.
Hatte das gleiche kleine Problem. Mit dem manuellen Upload hat's aber einwandfrei geklappt. Und im Anschluss noch die Zigbee-Firmware auf 20240710 hochgezogen. Das hat ohne Probleme funktioniert.
@kusselin sagte in Was sagt mir mal wieder diese Fehlermeldung?:
Ist das im Link oben von Matthias alles genau beschrieben?
Schau auch mal hier:
https://forum.iobroker.net/post/1144683
Du musst den linken Block gegen den rechten austauschen. Dann sollte wieder alles passen.
Wenn Du mit der manuell angelegten Variable result
gearbeitet hast (für Rückgabewerte) dann diese noch durch die vordefinierte Variable Data
ersetzen.
@basti17683
Was normalerweise funktionieren sollte wäre bei den Influx-Einstellungen unter Alias beim Datenpunkt die alte Bezeichnung des Measurements einzutragen:
Dann sollte eigentlich in der InfluxDB dort weitergeloggt werden.
Kann es sein dass deshalb enpfohglen wird mit Alias zu arbeiten?
Damit wär's eindeutig einfacher. Neuen DP verknüpfen und fertig.
@funkytown
Sollte über die Dateien einbindbar sein
und dann mit der URL
http://<ip_iobroker>:8082/ical.0/entsorgungsdaten2025.ics
@ofbeqnpolkkl6mby5e13 sagte in Hilfe für Javascript Legastheniker und js v8.3.x:
Welches Fazit wollen wir nun ziehen?
Matthias @haus-automatisierung hat hier zwischenzeitlich einen Upgrade-Guide erstellt.
https://forum.iobroker.net/topic/74659/request-package-is-deprecated-please-use-httpget/25
@haus-automatisierung
Funktioniert
Die erste Variante find ich besser falls sich aus unerfindlichen Gründen mal die IP ändern sollte. Dann müssten da ja die Alias-DP nicht mehr geändert werden.
@paul53
Der Ansatz wäre grundsätzlich nicht schlecht. Leider sind aber teilweise die Werte bei label
doppelt vorhanden.
Vielen Dank für Eure Hilfe
So schaut des Code in JS aus
var objID, term, term_old, objID_sum, term_sum, ObjectID, path_pre, search_room, value, txt_original, txt_search, txt_switch, part1, txt_result, function2, datapoint, part2, name2, txt_search_length, position, store, path_sum, list_rooms, list_lights, active_sum_all, i, list_lights_txt, count, j;
// Erstelle DP je Raum
async function create_dp_boolean(objID, term, term_old) {
if (!existsObject(objID)) {
createState(objID, false, {
read: true,
write: true,
name: term_old,
type: "boolean",
def: false
});
await wait(1000);
}
}
// Erstelle DP für aktive Geräte
async function create_dp_number_sum(objID_sum, term_sum) {
if (!existsObject(objID_sum)) {
createState(objID_sum, 0, {
type: 'number',
read: true,
write: true,
name: term_sum
});
await wait(1000);
}
}
// Finde Raumname
async function rooms_extract(ObjectID) {
let room = getObject(ObjectID, 'rooms').enumNames[0]; if(typeof room == 'string') return room; return room.de;
}
// Liefere Ergebnis Zustand je Raum
async function write_datapoint(path_pre, search_room, value) {
// Entferne Sonderzeichen
datapoint = await changeText(String(search_room), 'ä', 'ae');
datapoint = await changeText(String(txt_result), 'ö', 'oe');
datapoint = await changeText(String(txt_result), 'ü', 'ue');
datapoint = await changeText(String(txt_result), 'ß', 'ss');
datapoint = await changeText(String(txt_result), ' ', '_');
objID = [path_pre,'.',datapoint].join('');
await create_dp_boolean(objID, txt_result, search_room);
setStateDelayed(objID, value, true, parseInt(((0) || '').toString(), 10), false);
}
// Entferne Sonderzeichen
async function changeText(txt_original, txt_search, txt_switch) {
part1 = '';
part2 = '';
txt_result = txt_original;
txt_search_length = txt_search.length;
position = txt_result.indexOf(txt_search) + 1;
while (position > 0) {
// Wenn nicht erste Zeichen im Text!
if (position > 1) {
part1 = txt_result.slice(0, position - 1);
}
part2 = txt_result.slice(((position + txt_search_length) - 1), txt_result.length);
txt_result = [part1,txt_switch,part2].join('');
position = txt_result.indexOf(txt_search) + 1;
}
return txt_result;
}
// Script
// >>> Name wählen !!!
function2 = 'Licht';
// >>> Name eintragen!!!
name2 = 'aktive Lichter';
// Erstelle Datenpunkt für aktive Geräte
// >>> Speicherort unter 0_userdata. einstellen
store = '0_userdata.0.Datenpunkte.Widgets';
path_pre = [store,'.',function2].join('');
path_sum = String(path_pre) + '.Active';
await create_dp_number_sum(path_sum, name2);
setStateDelayed(path_sum, 0, true, parseInt(((0) || '').toString(), 10), false);
// Trigger
// >>> functions nach = anpassen !!!
on({ id: [].concat(Array.prototype.slice.apply($('state[id=*](functions=light)'))), change: 'ne' }, async (obj) => {
let value = obj.state.val;
let oldValue = obj.oldState.val;
console.log(name2);
list_rooms = [];
list_lights = [];
active_sum_all = 0;
// >>> functions nach = anpassen !!!
var i_list = Array.prototype.slice.apply($('state[id=*](functions=light)'));
for (var i_index in i_list) {
i = i_list[i_index];
list_rooms.push([await rooms_extract(i)]);
if (getState(i).val) {
list_lights.push([await rooms_extract(i)]);
active_sum_all = (typeof active_sum_all === 'number' ? active_sum_all : 0) + 1;
}
}
console.log(active_sum_all);
list_lights_txt = String(list_lights);
count = 0;
for (var j_index in list_rooms) {
j = list_rooms[j_index];
count = (typeof count === 'number' ? count : 0) + 1;
search_room = String(list_rooms[(count - 1)]);
if (list_lights_txt.indexOf(search_room) + 1 > 0) {
await write_datapoint(path_pre, search_room, true);
} else {
await write_datapoint(path_pre, search_room, false);
}
}
setStateDelayed(path_sum, active_sum_all, true, parseInt(((0) || '').toString(), 10), false);
});
@arteck
Hab bei mir Deinen überarbeiteten Adapter mal mit der neuen evcc-Version v0.200.0
getestet.
Ohne "Status Knoten auflösen" funktioniert der modifizierte Adapter.
Bei meiner 2. Instanz, bei der dieses Feature aktiviert ist, stürzt er aber leider bei mir ab.
Anbei mal zwei Debug-Logs falls Du's Dir genauer anschauen willst:
Alte Datenpunkte nicht gelöscht
debug_log_evcc1.txt
Alte Datenpunkte vor dem Start der Instanz gelöscht
debug_log_evcc1_dp-vorher-geloescht.txt
@sunpower10 sagte in Neuer Adapter für Roborock-Staubsauger:
Ändere mal 200 -> 201 und wieder zurück 201 -> 200, dann hat er bei mir in der App wieder Saugen und der Saugt tatsächlich, ohne zu wischen
Danke für den Tipp.
Hab ich bei mir mal getestet. Funktioniert aber leider bei mir nicht. Da ticken die verschiedenen Modelle vermutlich auch verschieden.
Ist aber kein Problem. Ich hab ja eine passende Lösung für mich.
@copystring sagte in Neuer Adapter für Roborock-Staubsauger:
@wolfi913 def macht nichts anderes außer beim ersten starten des Adapters einen Standardwert auszuwählen. Andernfalls wäre das Feld einfach leer und kein Wert ausgewählt. Hat aber rein gar nichts mit dem Standardwert in der App zu tun.
Dürfte eher @sunpower10 betreffen. Ich hab ja eine passende Lösung für mich.
@sunpower10
Aber (zumindest bei meinem Gerät) leider nicht beim Start über "commands.app_segment_clean" für die Einzelzimmerreinigung. Ich hatte es so aufgefasst, dass Du die Funktion meinst. Zumindest bei mir macht er da immer alles in einem kombinierten Saug&Wisch-Durchgang. Kann aber auch wieder abhängig vom Modell sein. Hab's jetzt gerade spaßeshalber nochmal mit 200/102 nochmal für den Flur ausprobiert. Der wurde aber trotz "commands.set_water_box_custom_mode = 200" wieder feucht gewischt.
@sunpower10
Habe bisher leider auch keine andere Möglichkeit gefunden, bei Steuerung über den Adapter, meinen Staubsauger dazu zu überreden nur zu saugen. Hatte einiges ausprobiert (kann aber leider nicht mehr sagen was alles) bis ich mir die obige Lösung zusammengebastelt habe. Komme damit aber bisher gut klar. Und das Anlegen von einzelnen Programmen in der App für die Anwendungsfälle geht ja auch recht zügig.
Vielleicht hat hier ja jemand anderes eine (bessere) Möglichkeit gefunden.
Aber als zusätzliches Feature im Adapter ist es ja scheinbar nicht geplant bzw. ist auch die Umsetzung gar nicht möglich.
@sunpower10
Zu 1 kann ich Dir leider nichts brauchbares sagen.
Zu 2: Wenn Du Einstellungen in einem Adapter selber setzt sollten die eigentlich immer nicht acknowledged gemacht werden. Bei bspw. Blockly-Scripts somit immer mit dem Steuere-Block, nicht mit dem Aktualisiere
Zu 3: Bei der Reinigung von Räumen läuft das bei mir auch immer mit Saugen&Wischen. Irgendwo hier im Forum hab ich gelesen, dass das (derzeit ???) nicht anders geht.
Habe mir da mit folgendem Workaround beholfen:
Habe in der App für das Zimmer, welches nur gesaugt werden soll, ein "Programm" angelegt mit nur Saugen. Die werden dann (beim Adapter-Neustart) in den Bereich roborock.0.Devices.xxx.programs
geladen.
Das baue ich dann per Blockly-Script vacuum.read_states.xml automatisch in einzeln ansprechbare Datenpunkte für jedes dieser Programme aus der App (sowie zusätzlich ein zusammengefasstes JSON) unter 0_userdata.0.vacuum
um
die ich dann einfach direkt im ioBroker oder über ein DropDown (gefüllt mit den Inhalten des vorher erzeugten JSON) in der Visualisierung ansprechen kann.
Die erzeugten Datenpunkte sollten dann vermutlich auch über simpleAPI ansprechbar sein.
Läuft unterm Strich dann auf die Ansteuerung dieses Datenpunktes hinaus
Ich hab für mich selber noch keine bessere Lösung gefunden. Ist zwar vermutlich nicht zu 100% das was Du suchst aber vielleicht hilft Dir das trotzdem etwas weiter.
@homoran sagte in Blockly - Wenn Wert X zwischen 100 und 200 dann ....:
@wolfi913 wie kommst du jetzt auf **+**1050?
Nur als Beispiel, dass das ganze flexibel erweiterbar ist. Falls also in der Reihenfolge noch was im positiven Bereich berücksichtigt werden muss. Im sonst
würden somit die Werte zwischen -1150 und +1150 erfasst. Wollte nur zeigen, dass das auch möglich ist.
Edit: Aber gebe zu, dass das evtl. nur verwirrt.
@viking85
Was in Deinem Anwendungsfall auch funktioniert wäre mit dem sonst falls
zu arbeiten.
Dabei aber immer die Reihenfolge im Zahlenstrahl
einhalten.
@merlin123
Da bin ich dann auch ratlos. Vielleicht hat ja jemand anderes noch eine Idee dazu.
Das, was Du ohnehin schon probiert hast, wäre nämlich noch mein letzter Vorschlag gewesen. Alles in ein neues Panel ohne vorherige Einstellungen zu packen und mal zu schauen was da rauskommt. Also nur Einstellungen Bar Chart
und die Query. Sollte eigentlich mit einer klappen wenn Du die vom Anfang nimmst und das v.windowPeriod durch 1h ersetzt. Also so:
from(bucket: "iobroker")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "0_userdata.0.PV_Produktion"
or r["_measurement"] == "0_userdata.0.PV_Eigenverbrauch"
or r["_measurement"] == "0_userdata.0.PV_Netzbezug"
or r["_measurement"] == "0_userdata.0.PV_Wallbox"
or r["_measurement"] == "0_userdata.0.PV_Nur_Einspeisung")
|> filter(fn: (r) => r["_field"] == "value")
|> aggregateWindow(every: 1h, fn: mean, createEmpty: false)
oder wie auch bereits versucht aufgeteilt in mehrere Querys.
Warum das bei Deinem Grafana nicht so problemlos klappt und er die Werte einfach in ein Stacking packt und nicht einfach nebeneinander...???
Leider gehen mir die Ideen aus. Sorry
@merlin123 sagte in Bar Chart: Bars nebeneinander?:
In meiner alten Version mit Linie konnte ich den anzuzeigenden Zeitraum in der URL mitgeben und habe nur eine Grafik für 4 verschiedene Zeiträume benötigt. Muss mal schauen, ob ich das hier auch machen kann.
Warum solltest Du den Zeitraum in der URL nicht mitschicken können. Der greift doch auf:
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
Und (wie schon ober geschrieben) den timeShift solltest Du normalerweise nicht brauchen.
Das ist eigentlich nur für spezielle Fälle notwendig.
Ich vermute mal das Du in den Overrides da was eingestellt hast. Die Balken sollten eigentlich standardmäßig nebeneinander liegen wenn da nichts spezielles eingestellt ist.