@sugram
Das Script läuft inzwischen ganz gut bei Mike0185 und mir mit der 7.22. Ich muss da allerdings noch ein wenig aufräumen und dann wohl auch mal ins Github packen.
Installation:
- Der Javascript-Adapter muss installiert sein und unter „Zusätzliche NPM-Module“ die iconv-lite und crypto Module eingetragen sein.
- In der Fritzbox einen weiteren Benutzer „ioBroker“ anlegen und mit einem Passwort versehen. Das muss im Script (siehe unten) angegeben werden.
- Dann das unten stehende Script anlegen und dauerhaft laufen lassen. Die Variablen werden automatisch angelegt und jede Minute gefüllt.
var logging = true;
const iconv = require('iconv-lite');
const crypto = require('crypto');
var DOCSIS30DSChannels = 0;
var DOCSIS31DSChannels = 0;
var DOCSIS30USChannels = 0;
var DOCSIS31USChannels = 0;
var sid;
var fritzBenutzer = 'ioBroker';
var fritzPasswort = 'passwort';
var loginURL = 'http://fritz.box/login_sid.lua?username=';
var docsisURL = 'http://fritz.box/data.lua';
// Downstream DOCSIS 3.0
for (var i = 1; i <= 31; i++){
var Channel = 'C' + (i < 10 ? '0' + i.toString() : i.toString());
createState('Internet.Docsis.DS.' + Channel + '.Frequency', 0, false, {name: 'Frequency', unit: 'MHz', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.Modulation', 0, false, {name: 'Modulation', unit: 'QAM', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.PowerLevel', 0, false, {name: 'PowerLevel', unit: 'dBmV', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.MSE', 0, false, {name: 'MSE', unit: 'dB', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.Latency', 0, false, {name: 'Latency', unit: 'ms', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.CorrectableErrors', 0, false, {name: 'CorrectableErrors', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.CorrectableErrorsPerMinute', 0, false, {name: 'CorrectableErrorsPerMinute', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.UncorrectableErrors', 0, false, {name: 'UncorrectableErrors', type: 'mixed', role: 'state'});
createState('Internet.Docsis.DS.' + Channel + '.UncorrectableErrorsPerMinute', 0, false, {name: 'UncorrectableErrorsPerMinute', type: 'mixed', role: 'state'});
}
// Upstream DOCSIS 3.0
for (var i = 0; i <= 5; i++){
var Channel = 'C0' + i.toString();
createState('Internet.Docsis.US.' + Channel + '.Frequency', 0, false, {name: 'Frequency', unit: 'MHz', type: 'mixed', role: 'state'});
createState('Internet.Docsis.US.' + Channel + '.Modulation', 0, false, {name: 'Modulation', unit: 'QAM', type: 'mixed', role: 'state'});
createState('Internet.Docsis.US.' + Channel + '.MultiplexMethod', 0, false, {name: 'MultiplexMethod', type: 'mixed', role: 'state'});
createState('Internet.Docsis.US.' + Channel + '.PowerLevel', 0, false, {name: 'PowerLevel', unit: 'dBmV', type: 'mixed', role: 'state'});
}
// Downstream DOCSIS 3.1
createState('Internet.Docsis31.DS.C01.Frequency', 0, false, {name: 'Frequency', unit: 'MHz', type: 'mixed', role: 'state'});
createState('Internet.Docsis31.DS.C01.Type', 0, false, {name: 'Modulation', unit: 'K', type: 'mixed', role: 'state'});
createState('Internet.Docsis31.DS.C01.PowerLevel', 0, false, {name: 'PowerLevel', unit: 'dBmV', type: 'mixed', role: 'state'});
// Upstream DOCSIS 3.1
createState('Internet.Docsis31.US.C00.Frequency', 0, false, {name: 'Frequency', unit: 'MHz', type: 'mixed', role: 'state'});
createState('Internet.Docsis31.US.C00.Type', 0, false, {name: 'Modulation', unit: 'K', type: 'mixed', role: 'state'});
createState('Internet.Docsis31.US.C00.MultiplexMethod',0, false, {name: 'MultiplexMethod', type: 'mixed', role: 'state'});
createState('Internet.Docsis31.US.C00.PowerLevel', 0, false, {name: 'PowerLevel', unit: 'dBmV', type: 'mixed', role: 'state'});
/**
* Simple XML parser
* @param {String} xml
* @return {Object}
*/
function parseXML(xml) {
var beg = -1;
var end = 0;
var tmp = 0;
var current = [];
var obj = {};
var from = -1;
while (true) {
beg = xml.indexOf('<', beg + 1);
if (beg === -1)
break;
end = xml.indexOf('>', beg + 1);
if (end === -1)
break;
var el = xml.substring(beg, end + 1);
var c = el[1];
if (c === '?' || c === '/') {
var o = current.pop();
if (from === -1 || o !== el.substring(2, el.length - 1))
continue;
var path = current.join('.') + '.' + o;
var value = xml.substring(from, beg);
if (typeof(obj[path]) === 'undefined')
obj[path] = value;
else if (obj[path] instanceof Array)
obj[path].push(value);
else
obj[path] = [obj[path], value];
from = -1;
continue;
}
tmp = el.indexOf(' ');
var hasAttributes = true;
if (tmp === -1) {
tmp = el.length - 1;
hasAttributes = false;
}
from = beg + el.length;
var isSingle = el[el.length - 2] === '/';
var name = el.substring(1, tmp);
if (!isSingle)
current.push(name);
if (!hasAttributes)
continue;
var match = el.match(/\w+\=\".*?\"/g);
if (match === null)
continue;
var attr = {};
var length = match.length;
for (var i = 0; i < length; i++) {
var index = match[i].indexOf('"');
attr[match[i].substring(0, index - 1)] = match[i].substring(index + 1, match[i].length - 1);
}
obj[current.join('.') + (isSingle ? '.' + name : '') + '[]'] = attr;
}
return obj;
};
function loginAndGetSID(){
sid = null;
// Challenge holen
var options = {
url: loginURL + fritzBenutzer,
method: 'GET'
};
request(options, function(error, response, body) {
if (!error && response.statusCode == 200) {
//if (logging) log('error: ' + error + ', response: ' + JSON.stringify(response) + ', body: ' + body, 'info');
var result = parseXML(body);
var challenge = result['SessionInfo.Challenge'];
// Einloggen und SID holen
var utf16le_encoded = iconv.encode(challenge + '-' + fritzPasswort, 'UTF-16LE', {addBOM: false});
var challengeResponse = crypto.createHash('md5').update(utf16le_encoded).digest('hex');
options = {
url: loginURL + '/login_sid.lua?username=' + fritzBenutzer + '&response=' + challenge + '-' + challengeResponse,
method: 'GET'
};
request(options, function(error, response, body) {
if (!error && response.statusCode == 200) {
var result = parseXML(body);
sid = result['SessionInfo.SID'];
if (logging) log('Logged in. SID = ' + sid, 'info');
}
else {
log('error: ' + error + ', response: ' + response.statusCode.toString(), 'info');
}
});
}
else {
log('error: ' + error + ', response: ' + response.statusCode.toString(), 'info');
}
});
}
// Wenn keine Daten abgerufen werden konnten, werden die States auf NULL gesetzt
function setStates2NullValues(){
var NullValue = null;
// DOCSIS 3.0 Downstream Channels
for (i = 0; i < DOCSIS30DSChannels; i++) {
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.Frequency', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.Modulation', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.PowerLevel', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.MSE', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.Latency', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.CorrectableErrors', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.CorrectableErrorsPerMinute', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.UncorrectableErrors', NullValue, true);
setState('Internet.Docsis.DS.C' + (i < 10 ? '0' : '') + i.toString() + '.UncorrectableErrorsPerMinute', NullValue, true);
}
// DOCSIS 3.1 Downstream Channel
setState('Internet.Docsis31.DS.C01.PowerLevel', NullValue, true);
setState('Internet.Docsis31.DS.C01.Type', NullValue, true);
setState('Internet.Docsis31.DS.C01.Frequency', NullValue, true);
// DOCSIS 3.0 Upstream Channels
for (i = 0; i < DOCSIS30USChannels; i++) {
setState('Internet.Docsis.US.C' + (i < 10 ? '0' : '') + i.toString() + '.Frequency', NullValue, true);
setState('Internet.Docsis.US.C' + (i < 10 ? '0' : '') + i.toString() + '.Modulation', NullValue, true);
setState('Internet.Docsis.US.C' + (i < 10 ? '0' : '') + i.toString() + '.MultiplexMethod', NullValue, true);
setState('Internet.Docsis.US.C' + (i < 10 ? '0' : '') + i.toString() + '.PowerLevel', NullValue, true);
}
// DOCSIS 3.1 Upstream Channel
setState('Internet.Docsis31.US.C00.PowerLevel', NullValue, true);
setState('Internet.Docsis31.US.C00.Type', NullValue, true);
setState('Internet.Docsis31.US.C00.MultiplexMethod', NullValue, true);
setState('Internet.Docsis31.US.C00.Frequency', NullValue, true);
}
// Holt die Informationen von der Fritzbox Benutzeroberfläche. Ab fritz.OS Version 7.2x werden die Informationen als JSON-String übermittelt (getCableModemChannelInfos Version 2)
function getCableModemChannelInfosV2(){
var NullValue = null;
var tableData;
var options = {
url: docsisURL,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'xhr=1&sid=' + sid + '&lang=de&page=docInfo&xhrId=all&no_sidrenew='
};
request(options, function(error, response, body) {
if (!error && response.statusCode == 200) {
tableData = JSON.parse(body);
if(tableData){
//log(JSON.stringify(tableData), 'info');
// DOCSIS 3.0 Downstream Channels
DOCSIS30DSChannels = Object.entries(tableData.data.channelDs.docsis30).length;
for (i = 0; i < DOCSIS30DSChannels; i++) {
var channelID = parseInt(tableData.data.channelDs.docsis30[i].channelID);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.Frequency', parseInt(tableData.data.channelDs.docsis30[i].frequency), true);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.Modulation', parseInt(tableData.data.channelDs.docsis30[i].type.replace('QAM', '')), true);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.PowerLevel', parseFloat(tableData.data.channelDs.docsis30[i].powerLevel), true);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.MSE', parseFloat(tableData.data.channelDs.docsis30[i].mse), true);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.Latency', parseFloat(tableData.data.channelDs.docsis30[i].latency), true);
var correctableErrors = getState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.CorrectableErrors');
var lastValue = correctableErrors.val;
var ts_diff = new Date().getTime() - correctableErrors.ts;
var newValue = parseInt(tableData.data.channelDs.docsis30[i].corrErrors);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.CorrectableErrors', newValue, true);
// Die Differenz zum letzten Wert nur dann speichern, wenn dieser ca. 1 Min. alt ist
if (ts_diff > 50000 && ts_diff < 70000){
if (newValue > lastValue){
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.CorrectableErrorsPerMinute', newValue - lastValue, true);
}
}
else {
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.CorrectableErrorsPerMinute', NullValue, true);
}
var uncorrectableErrors = getState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.UncorrectableErrors');
var lastValue = uncorrectableErrors.val;
var ts_diff = new Date().getTime() - uncorrectableErrors.ts;
var newValue = parseInt(tableData.data.channelDs.docsis30[i].nonCorrErrors);
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.UncorrectableErrors', newValue, true);
// Die Differenz zum letzten Wert nur dann speichern, wenn dieser ca. 1 Min. alt ist
if (ts_diff > 50000 && ts_diff < 70000){
if (newValue > lastValue){
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.UncorrectableErrorsPerMinute', newValue - lastValue, true);
}
}
else {
setState('Internet.Docsis.DS.C' + (channelID < 10 ? '0' : '') + tableData.data.channelDs.docsis30[i].channelID + '.UncorrectableErrorsPerMinute', NullValue, true);
}
}
// DOCSIS 3.1 Downstream Channel
if (tableData.data.channelDs.docsis31 != null){
DOCSIS31DSChannels = 1;
setState('Internet.Docsis31.DS.C01.PowerLevel', parseFloat(tableData.data.channelDs.docsis31[0].powerLevel), true);
setState('Internet.Docsis31.DS.C01.Type', parseInt(tableData.data.channelDs.docsis31[0].type.replace('K', '')), true);
setState('Internet.Docsis31.DS.C01.Frequency', tableData.data.channelDs.docsis31[0].frequency, true);
}
// DOCSIS 3.0 Upstream Channels
DOCSIS30USChannels = Object.entries(tableData.data.channelUs.docsis30).length;
for (i = 0; i < DOCSIS30USChannels; i++) {
var channelID = parseInt(tableData.data.channelUs.docsis30[i].channelID);
setState('Internet.Docsis.US.C' + (channelID < 10 ? '0' : '') + tableData.data.channelUs.docsis30[i].channelID + '.Frequency', parseInt(tableData.data.channelUs.docsis30[i].frequency), true);
setState('Internet.Docsis.US.C' + (channelID < 10 ? '0' : '') + tableData.data.channelUs.docsis30[i].channelID + '.Modulation', parseInt(tableData.data.channelUs.docsis30[i].type.replace('QAM', '')), true);
setState('Internet.Docsis.US.C' + (channelID < 10 ? '0' : '') + tableData.data.channelUs.docsis30[i].channelID + '.MultiplexMethod', tableData.data.channelUs.docsis30[i].multiplex, true);
setState('Internet.Docsis.US.C' + (channelID < 10 ? '0' : '') + tableData.data.channelUs.docsis30[i].channelID + '.PowerLevel', parseFloat(tableData.data.channelUs.docsis30[i].powerLevel), true);
}
// DOCSIS 3.1 Upstream Channel
if (tableData.data.channelUs.docsis31 != null){
DOCSIS31USChannels = 1;
setState('Internet.Docsis31.US.C00.PowerLevel', parseFloat(tableData.data.channelUs.docsis31[0].powerLevel), true);
setState('Internet.Docsis31.US.C00.Type', parseInt(tableData.data.channelUs.docsis31[0].type.replace('K', '')), true);
setState('Internet.Docsis31.US.C00.MultiplexMethod', tableData.data.channelUs.docsis31[0].multiplex, true);
setState('Internet.Docsis31.US.C00.Frequency', parseInt(tableData.data.channelUs.docsis31[0].frequency), true);
}
}
else{
log('Empty response', 'error');
setStates2NullValues();
loginAndGetSID();
}
}
else {
log('error: ' + error + ', response: ' + response.statusCode.toString(), 'error');
setStates2NullValues();
loginAndGetSID();
}
});
}
if (logging) log('DocsisInfo starting', 'info');
// SID holen und merken (User Token)
loginAndGetSID();
var getSIDinterval = setInterval(loginAndGetSID, 900000); // Alle 15 Minuten neue SID holen
schedule("* * * * *", function() { // Zu jeder vollen Minute die Fritzbox DOCSIS-Daten abfragen
getCableModemChannelInfosV2();
});