Hallo,
Ich möchte gerne ein scripted device erstellen um in der Fritz Box das WLAN ein-/auszuschalten und den Status abzufragen.
Beim Versuch eine Anfrage an die Fritz Box zu senden scheitere ich leider schon. Ich bekommen den http Fehler 401. Denselben Fehler sehe ich in Postman wenn ich als Authorization zB Basic Auth wähle. Die Fritz Box verlangt digest authentication (WWW-Authenticate: Digest realm="HTTPS Access",nonce="76780F4E964C0B97",algorithm=MD5,qop="auth").
In anderen Threads habe ich gelesen dass digest authentication unterstützt ist. Was habe ich falsch gemacht?
Mein Test-Code:

// FritzBox connection information
var baseurl = "!https://fritz.box"
var port = 49443
var user = "user"
var password = "passwort"
// action to execute
var location = "/upnp/control/wlanconfig1"
var uri = "urn:dslforum-org:service:WLANConfiguration:1"
var action = 'GetInfo'
// build request
var request = {
  'url' : '',
  'method' : 'POST',
  'headers' : {
    'Content-Type' : 'text/xml; charset="utf-8"',
    'SoapAction' :  '',
  },
  'user' : "",
  'password' : "",
  }
request.url = baseurl + ':' + port + location
request.headers.SoapAction = '"' + uri + '#' + action + '"'
request.data = "<?xml version='1.0' encoding='utf-8'?><s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><u:" + action + " xmlns:u='" + uri + "'></u:" + action + "></s:Body></s:Envelope>"
// execute request
httprequest(request)

Das sieht soweit gut aus, ausser dass user und passwort im Beispielcode nicht gesetzt werden. Oben hat es zwar entsprechende Variablen, aber diese müssten noch den Feldern im request drin zugewiesen werden:

request.user = user
request.password = password

Damit sollte digest-auth funktionieren.

Oh - das war wohl zu spät für mich... Danke für die Hilfe! Leider kriege ich aber immer noch 401... Habe jetzt user und passwort in die URL genommen, damit klappt es 🙂
PS: wirklich toll, die P44-DSB-E2! Ich weiss gar nicht wie ich Digitalstrom so lange ohne sie benutzen konnte 😉

// FritzBox connection information
var protocol = 'https'
var boxip = 'fritz.box'
var user = "user"
var password = "passwort"
// build baseurl
var port
if (protocol=='https') port = 49443 else port = 49000
var baseurl = '!' + protocol + '://' + user + ':' + password + '@' + boxip + ':' + port
// action to execute
var location = "/upnp/control/wlanconfig1"
var uri = "urn:dslforum-org:service:WLANConfiguration:1"
var action = 'GetInfo'
// build request
var request = {
  'url' : '',
  'method' : 'POST',
  'headers' : {
	'Content-Type' : 'text/xml; charset="utf-8"',
	'SoapAction' :  '',
  },
  'withmeta': true,
  }
request.url = baseurl + location
request.headers.SoapAction = '"' + uri + '#' + action + '"'
request.data = "<?xml version='1.0' encoding='utf-8'?><s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><u:" + action + " xmlns:u='" + uri + "'></u:" + action + "></s:Body></s:Envelope>"
// execute request
httprequest(request)
  • luz hat auf diesen Beitrag geantwortet.

    chris Oh - das war wohl zu spät für mich... Danke für die Hilfe! Leider kriege ich aber immer noch 401...
    Habe jetzt user und passwort in die URL genommen, damit klappt es 🙂

    Also kein 401 mehr? WiFi geht an und aus wie gewünscht? Sehr schön

    Aber es hätte eigentlich auf dasselbe herauskommen sollen, ob user/password in der URL sind oder separat im JSON als 'user' und 'password'-Felder. Nur, leider hatte es einen Bug an der Stelle, so dass das Passwort nicht richtig übernommen wurde, wie ich jetzt dank Deinem Feedback herausgefunden habe 😢 Wird in der nächsten FW behoben!

    Ja, es funktioniert jetzt 🙂 Ich sehe die Geräte in der dS App nicht, aber das spielt eigentlich keine Rolle, da ich das WLAN über benutzerdefinierte Handlungen steuere. Werde noch benutzerdefinierte Zustände erstellen um den Status anzuzeigen.

    mainscript

    // ***************************************************************************
    // FRITZ!Box Integration Global Code - START
    // ***************************************************************************
    
    global function fritzBoxGet(location, uri, action) {
      fritzBoxSet(location, uri, action, 'nil', 'nil')
    }
    
    global function fritzBoxSet(location, uri, action, tag, value) {
      log(5, format('fritzBoxSet invoked with location: %s, uri: %s, action: %s, tag: %s, value: %s', location, uri, action, tag, value))
      // xml tag string - if value provided
      var xmlTag
      if (tag == 'nil') {
        xmlTag = ''
      } else {
        xmlTag = '<' + tag + '>' + value + '</' + tag + '>'
      }
      // build request
      var request = {
        'headers' : {
        'Content-Type' : 'text/xml; charset="utf-8"',
        'SoapAction' :  '',
        },
        'url' : '',
        'method' : 'POST',
        'withmeta' : true
      }
      request.url = fritzBoxBaseURL + location
      request.headers.SoapAction = '"' + uri + '#' + action + '"'
      request.data = "<?xml version='1.0' encoding='utf-8'?><s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><u:" + action + " xmlns:u='" + uri + "'>" + xmlTag + "</u:" + action + "></s:Body></s:Envelope>"
      log(5, format('fritzBox request for location: %s, uri: %s, action: %s, tag: %s, value: %s = %s', location, uri, action, tag, value, request))
      // execute request
      var fritzBoxResponse = httprequest(request)
      if (fritzBoxResponse.status != 200) {
        log(format('ERROR - FRITZ!Box returned HTTP status %s. Error: %s', fritzBoxResponse.status, fritzBoxResponse.data))
      }
      log (5, format('fritzBox response for location: %s, uri: %s, action: %s, tag: %s, value: %s = %s', location, uri, action, tag, value, fritzBoxResponse))
      fritzBoxResponse
    }
    global function getTagValueFromXml(xml, tag) {
      var tag_start = find(xml, '<' + tag + '>')
      log(5, format('getTagValueFromXml: tag start %s found at %s', tag, tag_start))
      var tag_end = find(xml, '</' + tag + '>', tag_start)
      log(5, format('getTagValueFromXml: tag end %s found at %s', tag, tag_end))
      var substr_from = tag_start + strlen(tag) + 2
      var substr_len  = tag_end - tag_start - strlen(tag) - 2
      log(5, format('getTagValueFromXml: substr_from %s, substr_len %s', substr_from, substr_len))
      substr(xml, substr_from, substr_len)
    }
    
    // FritzBox connection information
    var fritzBox = {
      'protocol': 'https',
      'ip':       'fritz.box',
      'user':     'user',
      'password': 'password'
    }
    // build fritzBoxBaseURL
    var fritzBoxPort
    if (fritzBox.protocol=='https') fritzBoxPort = 49443 else fritzBoxPort = 49000
    global fritzBoxBaseURL
    fritzBoxBaseURL = '!' + fritzBox.protocol + '://' + fritzBox.user + ':' + fritzBox.password + '@' + fritzBox.ip + ':' + fritzBoxPort
    
    var nil = 'nil' // prevent logging of last result (if this is the last line in the global script)
    
    // ***************************************************************************
    // FRITZ!Box Integration Global Code - END
    // ***************************************************************************

    Device für 2.4G WLAN:

    // ***************************************************************************
    // FRITZ!Box Device WLAN2G
    // ***************************************************************************
    
    // init with input 
    {
      'message':    'init',
      'output':     'basic',
      'colorclass': 8, /* dS Joker */
      'group':      8, /* dS Joker */
      'inputs':[ {
        'inputtype':         0,
        'usage':             1,
        'group':             8, /* dS Joker */
        'hardwarename':      'WLAN2G',
        'updateinterval':    300,
        'alivesigninterval': 900,
      }]
    }
    
    // implementation
    
    function updatestate()
    {
      var action = 'GetInfo'
      var fritzBoxResponse = fritzBoxGet(location, uri, action)
      var status = getTagValueFromXml(fritzBoxResponse.data, tag)
      // update state
      var msg = { 'message':'input', 'index':0 }
      msg.value = status;
      log(format("status of WLAN2G is %d", status))
      message(msg)
    }
    
    var location = "/upnp/control/wlanconfig1"
    var uri = "urn:dslforum-org:service:WLANConfiguration:1"
    var action = 'SetEnable'
    var tag = 'NewEnable'
    
    // when the input value changes
    on (message()) as m {
      if (m.message=="channel" && m.index==0) {
        var newValue = if(m.value>50, 1, 0)
        log(format("setting WLAN2G to %d", newValue))
        var fritzBoxResponse = fritzBoxSet(location, uri, action, tag, newValue)
        updatestate()
      }
    }
    
    // every 5 minutes
    on (every(0:05)) {
      // get status
      updatestate()
    }
    
    // get state on startup
    updatestate()
    
    return true // end of script definition

    Device für 5G WLAN:

    // init with input 
    {
      'message':    'init',
      'output':     'basic',
      'colorclass': 8, /* dS Joker */
      'group':      8, /* dS Joker */
      'inputs':[ {
        'inputtype':         0,
        'usage':             1,
        'group':             8, /* dS Joker */
        'hardwarename':      'WLAN5G',
        'updateinterval':    300,
        'alivesigninterval': 900,
      }]
    }
    
    // implementation
    
    function updatestate()
    {
      var action = 'GetInfo'
      var fritzBoxResponse = fritzBoxGet(location, uri, action)
      var status = getTagValueFromXml(fritzBoxResponse.data, tag)
      // update state
      var msg = { 'message':'input', 'index':0 }
      msg.value = status;
      log(format("status of WLAN5G is %d", status))
      message(msg)
    }
    
    var location = "/upnp/control/wlanconfig2"
    var uri = "urn:dslforum-org:service:WLANConfiguration:2"
    var action = 'SetEnable'
    var tag = 'NewEnable'
    
    // when the input value changes
    on (message()) as m {
      if (m.message=="channel" && m.index==0) {
        var newValue = if(m.value>50, 1, 0)
        log(format("setting WLAN5G to %d", newValue))
        var fritzBoxResponse = fritzBoxSet(location, uri, action, tag, newValue)
        updatestate()
      }
    }
    
    // every 5 minutes
    on (every(0:05)) {
      // get status
      updatestate()
    }
    
    // get state on startup
    updatestate()
    
    return true // end of script definition

    Device für Gast WLAN:

    // init with input 
    {
      'message':    'init',
      'output':     'basic',
      'colorclass': 8, /* dS Joker */
      'group':      8, /* dS Joker */
      'inputs':[ {
        'inputtype':         0,
        'usage':             1,
        'group':             8, /* dS Joker */
        'hardwarename':      'WLANGUEST',
        'updateinterval':    300,
        'alivesigninterval': 900,
      }]
    }
    
    // implementation
    
    function updatestate()
    {
      var action = 'GetInfo'
      var fritzBoxResponse = fritzBoxGet(location, uri, action)
      var status = getTagValueFromXml(fritzBoxResponse.data, tag)
      // update state
      var msg = { 'message':'input', 'index':0 }
      msg.value = status;
      log(format("status of WLANGUEST is %d", status))
      message(msg)
    }
    
    var location = "/upnp/control/wlanconfig3"
    var uri = "urn:dslforum-org:service:WLANConfiguration:3"
    var action = 'SetEnable'
    var tag = 'NewEnable'
    
    // when the input value changes
    on (message()) as m {
      if (m.message=="channel" && m.index==0) {
        var newValue = if(m.value>50, 1, 0)
        log(format("setting WLANGUEST to %d", newValue))
        var fritzBoxResponse = fritzBoxSet(location, uri, action, tag, newValue)
        updatestate()
      }
    }
    
    // every 5 minutes
    on (every(0:05)) {
      // get status
      updatestate()
    }
    
    // get state on startup
    updatestate()
    
    return true // end of script definition

    Verbesserungsvorschläge willkommen!

    Besten Dank und Gruss,
    Chris

    • luz gefällt das.