HTTPMOD: Unterschied zwischen den Versionen

Aus FHEMWiki
K (added more examples for defining set options)
K (→‎Further replacements of URL, header or post data: Corrected a typo and extended text for better understanding)
Zeile 421: Zeile 421:
To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes  
To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes  


* replacement[0-9]*Regex
* <code>replacement[0-9]*Regex</code>
* replacement[0-9]*Mode
* <code>replacement[0-9]*Mode</code>
* replacement[0-9]*Value
* <code>replacement[0-9]*Value</code>
* [gs]et[0-9]*Replacement[0-9]*Value
* <code>[gs]et[0-9]*Replacement[0-9]*Value</code>


a replacement always replaces a match of a regular expression.  
a replacement always replaces a match of a regular expression.  


The way the replacement value is defined can be specified with the replacement mode. If the mode is reading, then the value is interpreted as the name of a reading of the same device or as device:reading to refer to another device.
'''replacement[0-9]*Mode:'''
If the mode is internal, then the value is interpreted as the name of an internal of the same device or as device:internal to refer to another device.
The way the replacement value is defined can be specified with the replacement mode.
The mode text will use the value as a static text and the mode expression will evaluate the value as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.
* If the <code>replacement[0-9]*Mode</code> is <code>reading</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of a ''reading'' of the same device or as ''device:reading'' to refer to another device.
* If the <code>replacement[0-9]*Mode</code> is <code>internal</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of an ''internal'' of the same device or as ''device:internal'' to refer to another device.
* If the <code>replacement[0-9]*Mode</code> is <code>text</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as a static text
* If the <code>replacement[0-9]*Mode</code> is <code>expression</code> , then the corresponding <code>replacement[0-9]*Value</code> is evaluated as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.


Example:
Example:


<pre>
<source lang="perl">
attr mydevice getData {"get" :["%%value%%.value"]}
attr mydevice getData {"get" :["%%value%%.value"]}
attr mydevice replacement01Mode text
attr mydevice replacement01Mode text
Zeile 444: Zeile 447:
attr mydevice get02Name Something
attr mydevice get02Name Something
attr mydevice get02Replacement01Value 31.4024
attr mydevice get02Replacement01Value 31.4024
</pre>         
</source>         


defines that %%value%% will be replaced by a static text.
defines that <code>%%value%%</code> will be replaced by a static text.


All Get commands will be HTTP post requests of a similar form. Only the %%value%% will be different from get to get.
All Get commands will be HTTP post requests of a similar form. Only the <code>%%value%%</code> will be different from get to get.
The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008.
The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008.
A second get will look the same except a different name and replacement value.
A second get will look the same except a different name and replacement value.


The mode expression allows you to define your own replacement syntax:
The mode expression allows you to define your own replacement syntax:
<pre>        
<source lang="perl">      
attr mydevice replacement01Mode expression
attr mydevice replacement01Mode expression
attr mydevice replacement01Regex {{([^}]+)}}
attr mydevice replacement01Regex {{([^}]+)}}
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")
attr mydevice getData {"get" :["{{temp}}.value"]}
attr mydevice getData {"get" :["{{temp}}.value"]}
</pre>      
</source>    


In this example any {{name}} in a URL, header or post data will be passed on to the perl function ReadingsVal  
In this example any <code><nowiki>{{name}}</nowiki></code> in a URL, header or post data will be passed on to the perl function ReadingsVal  
which uses the string between {{}} as second parameter. This way one defined replacement can be used for many different
which uses the string between <code><nowiki>{{}}</nowiki></code> as second parameter. This way one defined replacement can be used for many different
readings.
readings.



Version vom 5. Januar 2016, 16:32 Uhr

HTTPMOD
Zweck / Funktion
Extract information from devices with an HTTP interface (or, more generic, from any URL) or send information to such devices
Allgemein
Typ Gerätemodul
Details
Dokumentation EN / DE
Support (Forum) Sonstiges
Modulname 98_HTTPMOD.pm
Ersteller StefanStrobel (Forum / Wiki)
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!


HTTPMOD provides a generic way to retrieve information from devices with an HTTP Interface and store them in Readings or send information to such devices. It queries a given URL with Headers and data defined by attributes.

From the HTTP response it extracts readings named in attributes using Regexes, JSON or XPath parsing also defined by attributes.

In an advanced configuration the module can also send information to devices. To do this, a generic set option can be configured using attributes.

Availability

Info green.pngAn extended / modified version of this module that among other features adds XPath and JSON support is currently under development.

If you want to participate in early tests, please follow this discussion thread in FHEM forum. This page has already been updated to describe most of the new features. So if you need one of the new features described here and yout HTTPMOD is still the old version, load the new module

from the forum and help testing

The module is part of the regular FHEM distribution.

Prerequisites

This module uses the non blocking HTTP function HttpUtils_NonblockingGet provided by FHEM's HttpUtils in a new version published in December 2013. If not already installed in your environment, please update FHEM or install it manually using appropriate commands from your environment.

Define

define <name> HTTPMOD <URL> <Interval>

The module connects to the given URL every Interval seconds, sends optional headers and data and then parses the response with regular expressions, xpath or json to set readings.

URL can be "none" and Interval can be 0 if you prefer to only query data with a get command and not in a defined interval.

Example:

define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60

Set-Commands

can be defined using attributes, see advanced configuration

If you set the attribute enableControlSet to 1, the following additional built in set commands are available:

interval
set new interval time in seconds and restart the timer
reread
request the defined URL and try to parse it just like the automatic update would do it every Interval seconds without modifying the running timer.
stop
stop interval timer.
start
restart interval timer to call GetUpdate after interval seconds

Get-Commands

can be defined using attributes, see advanced configuration

simple Attributes

do_not_notify
readingFnAttributes
requestHeader.*
Define an additional HTTP Header to set in the HTTP request
requestData
POST Data to be sent in the request. If not defined, it will be a GET request as defined in HttpUtils used by this module
reading[0-9]+(-[0-9]+)?Name
the name of a reading to extract with the corresponding readingRegex
reading[0-9]*(-[0-9]+)?Expr
defines an expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.
reading[0-9]*(-[0-9]+)?Map
defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb". If specified as readingMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Map.
reading[0-9]*(-[0-9]+)?Format
Defines a format string that will be used in sprintf to format a reading value. If specified as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.
reading[0-9]*(-[0-9]+)?Decode
defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 instead of utf8.
reading[0-9]*(-[0-9]+)?Encode
defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.
reading[0-9]+Regex
defines the regex to be used for extracting the reading. The value to extract should be in a sub expression e.g. ([\d\.]+) in the above example
reading[0-9]+Regex
defines the regex to be used for extracting the reading. The value to extract should be in a capture group / sub expression
e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)
reading[0-9]+XPath
defines an xpath to one or more readings when parsing HTML data (see examples below)
reading[0-9]+XPath-Strict
defines an xpath to one or more readings when parsing XML data (see examples below)
reading[0-9]+JSON
defines a path to the JSON object wanted by concatenating the object names with an underscore as delimiter (see the example below)


noShutdown
pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)
disable
stop doing automatic HTTP requests while this attribute is set to 1
timeout
time in seconds to wait for an answer. Default value is 2
enableControlSet
enables the built in set commands interval, stop, start, reread
(get|reading)[0-9]*RecombineExpr
defines an expression that is used in an eval to compute one reading value out of the list of matches.
This is supposed to be used for regexes or xpath specifications that produce multiple results if only one result that combines them is wanted.
The list of matches will be in the variable @matchlist.


simple Configuration of HTTP Devices

If your device expects special HTTP-headers then specify them as attr requestHeader1 to attr requestHeaderX. If your Device expects an HTTP POST instead of HTTP GET then the POST-data can be specified as attr requestData. To get the readings, specify pairs of attr readingXName and attr readingXRegex, attr readingXXPath, attr readingXXPath-Strict or attr readingXJSON to define which readings you want to extract from the HTTP response and how to extract them. (The old syntax attr readingsNameX and attr readingsRegexX is still supported but the new one with attr readingXName and attr readingXRegex should be preferred. The actual values to be extracted have to be sub expressions within () in the regex (see example below)

Example for a PoolManager 5:

The PoolManager Web GUI can be queried with HTTP POST Requests like this one:

POST /cgi-bin/webgui.fcgi HTTP/1.1
Host: 192.168.70.90
Accept: */*
Content-Type: application/json;charset=UTF-8
Content-Length: 60

{"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value"]}

The resulting HTTP Response would look like this:

HTTP/1.1 200 OK
Content-type: application/json; charset=UTF-8
Expires: 0
Cache-Control: no-cache
Date: Sun, 12 Jan 2014 12:23:11 GMT
Server: lighttpd/1.4.26
Content-Length: 179

{
	"data":	{
		"34.4001.value":	"7.00",
		"34.4008.value":	"0.52",
		"34.4033.value":	"24.8"
	},
	"status":	{
		"code":	0
	},
	"event":	{
		"type":	1,
		"data":	"48.30000.0"
	}
}

To configure HTTPMOD for a PoolManager one would first define a PoolManager device with e.g. the name PM, the URL and an interval of e.g. 60 seconds.

Then the data to be sent in the request needs to be defined because in this example the device expects a POST request so the query is not contained in the URL but in the request data.

Also as seen above the device expects special HTTP headers in the request so these headers also need to be defined as attr PM requestHeader1 and attr PM requestHeader2

Then the names of the readings to be extracted would be set with attributes

Then for each reading value to be extracted a regular expression needs to be set that will match the value in question within ().

Example:

define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60
attr PM reading01Name PH
attr PM reading01Regex 34.4001.value":[ \t]+"([\d\.]+)"

attr PM reading02Name CL
attr PM reading02Regex 34.4008.value":[ \t]+"([\d\.]+)"

attr PM reading03Name3TEMP
attr PM reading03Regex 34.4033.value":[ \t]+"([\d\.]+)"

attr PM requestData {"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value", "14.16601.value", "14.16602.value"]}
attr PM requestHeader1 Content-Type: application/json
attr PM requestHeader2 Accept: */*
attr PM stateFormat {sprintf("%.1f Grad, PH %.1f, %.1f mg/l Chlor", ReadingsVal($name,"TEMP",0), ReadingsVal($name,"PH",0), ReadingsVal($name,"CL",0))}


Example for AmbientMonitor

AmbientMonitor is a webbased visualisation for sensors connected to an Arduino device. Its web interface can also be queried with HTTMOD to grab the data into readings.

This example was provided by locutus. The hardware configuration is an Arduino + Ethercard with ENC28J60 Controller + DHT22 Sensor and software can be downloaded from https://github.com/lucadentella/AmbientMonitor

In this example an HTTP GET is sufficent, so no requestData is needed. The device provides temperature and humidity readings in an HTTP response that looks like:

HTTP/1.0 200 OK 
Content-Type: text/html 

myCB({'temperature':22.00,'humidity':46.00})

the definition could be:

define AmbientMonitor HTTPMOD http://192.168.1.221/?callback=? 300
attr AmbientMonitor requestHeader Content-Type: application/json
attr AmbientMonitor reading1Name Temperatur
attr AmbientMonitor reading1Regex temperature':([\d\.]+)
attr AmbientMonitor reading2Name Feuchtigkeit
attr AmbientMonitor reading2Regex humidity':([\d\.]+)
attr AmbientMonitor stateFormat {sprintf("Temperatur %.1f C, Feuchtigkeit %.1f %", ReadingsVal($name,"Temperatur",0), ReadingsVal($name,"Feuchtigkeit",0))}


formating and manipulating values / readings

Values that are parsed from an HTTP response can be further treated or formatted with the following attributes:

  • (reading|get)[0-9]*(-[0-9]+)?Expr
  • (reading|get)[0-9]*(-[0-9]+)?Map
  • (reading|get)[0-9]*(-[0-9]+)?Format
  • (reading|get)[0-9]*(-[0-9]+)?Decode
  • (reading|get)[0-9]*(-[0-9]+)?Encode

They can all be specified for an individual reading, for all readings in one match (e.g. if a regular expression has several capture groups)or for all readings in a get command (defined by getXX) or for all readings in the main reading list (defined by readingXX):

reading01Format %.1f

will format the reading with the name specified by the attribute reading01Name to be numerical with one digit after the decimal point. If the attribute reading01Regex is used and contains several capture groups then the format will be applied to all readings thet are parsed by this regex unless these readings have their own format specified by reading01-1Format, reading01-2Format and so on.

reading01-2Format %.1f

Can be used in cases where a regular expression specified as reading1regex contains several capture groups or an xpath specified as reading01XPath creates several readings. In this case reading01-2Format specifies the format to be applied to the second match.

readingFormat %.1f

applies to all readings defined by a reading-Attribute that have no more specific format.

If you need to do some calculation on a raw value before it is used as a reading, you can define the attribute readingExpr. It defines a Perl expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.

Example:

attr PM reading03Expr $val * 10

Just like in the above example of the readingFormat attributes, readingExpr and the other following attributes can be applied on several levels.

To map a numerical value to a name, you can use the readingMap attribute. It defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".

Example:

attr PM reading02-3Map 0:kalt, 1:warm, 2:sehr warm

To convert character sets, the module can first decode a string read from the device and then encode it again. For example:

attr PM getDecode UTF-8

This applies to all readings defined for Get-Commands.


Some help with Regular Expressions

If HTTPMOD seems not to work and the FHEM Logfile contains a message like

HTTPMOD: Response didn't match Reading ...

then you should check if the value you want to extract is read into the internal with the name buf. Internals are visible when you click on the defined HTTPMOD Device. buf is an internal variable that contains the HTTP Response read. If the value is there and you get the mentioned message then probably something is wrong with your regular expression. If you are new to regular expressions then the introduction at http://perldoc.perl.org/perlretut.html might be helpful.

For a typical HTTPMOD use case where you want to extract a number out of a HTTP-Response you can use something like [\d\.]+ to match the number itself. The expression matches the number characters (\d) or a . if one of these characters occurs at least once.

To tell HTTPMOD that the number is what you want to use for the reading, you have to put the expression in between (). A ([\d\.]+) alone would match the longest number in the HTTP Response which is very likely not the number you are looking for so you need to add something to the expression to give it a context and define how to find the number that you are looking for. if there is a title text before the number or a special text after the number you can put this in the regex. In one of the examples above humidity':([\d\.]+) is looking for the number that immediately follows the text humidity': without any blanks in between.

Regular Expressions with multiple capture Groups

The regular expressions used in the above example for a Poolmanager will take the value that matches one capture group. This is the part of the regular expression inside (). In the above example "([\d\.]+)" refers to numerical digits or points between double quotation marks. Only the string consiting of digits and points will match inside (). This piece is assigned to the reading.

You can also use regular expressions that have several capture groups which might be helpful when parsing tables. In this case an attribute like

reading02Regex something[ \t]+([\d\.]+)[ \t]+([\d\.]+)

could match two numbers. When you specify only one reading02Name like

reading02Name Temp

the name Temp will be used with the extension -1 and -2 thus giving a reading Temp-1 for the first number and Temp-2 for the second. You can also specify individual names for several readings that get parsed from one regular expression with several capture groups by defining attributes

reading02-1Name
reading02-2Name
...

The same notation can be used for formatting attributes like readingXMap, readingXFormat and so on.

The usual way to define readings is however to have an individual regular expression with just one capture group per reading as shown in the above example.


Parsing JSON

If a webservice delivers data in JSON format, HTTPMOD can directly parse JSON which might be easier in this case than definig regular expressions. The next example shows the data that can be requested from a Poolmanager with the following partial configuration:

define test2 HTTPMOD none 0
attr test2 get01Name Chlor
attr test2 getURL http://192.168.70.90/cgi-bin/webgui.fcgi
attr test2 getHeader1 Content-Type: application/json
attr test2 getHeader2 Accept: */*
attr test2 getData {"get" :["34.4008.value"]}

The data in the HTTP response looks like this:

{
	"data": {
			"34.4008.value": "0.25"
	},
	"status":       {
			"code": 0
	},
	"event":        {
			"type": 1,
			"data": "48.30000.0"
	}
}

the classic way to extract the value 0.25 into a reading with the name Chlor with a regex would have been

attr test2 get01Regex 34.4008.value":[ \t]+"([\d\.]+)"

with JSON you can write

attr test2 get01JSON data_34.4008.value 

or if you don't care about the naming of your readings, you can simply extract all JSON data with

attr test2 extractAllJSON

which would apply to all data read from this device and create the following readings out of the HTTP response shown above:

data_34.4008.value 0.25
event_data 48.30000.0
event_type 1
status_code 0

or you can specify

attr test2 get01ExtractAllJSON

which would only apply to all data read as response to the get command defined as get01.

Parsing http / XML using xpath

Another alternative to regex parsing is the use of XPath to extract values from HTTP responses. The following example shows how XML data can be parsed with XPath-Strict or HTML Data can be parsed with XPath. Both work similar and the example uses XML Data parsed with the XPath-Strict option:

If The XML data in the HTTP response looks like this:

<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
<actors>
<actor id="1">Peter X</actor>
<actor id="2">Charles Y</actor>
<actor id="3">John Doe</actor>
</actors>
</root>

with XPath you can write

attr htest reading01Name Actor
attr htest reading01XPath-Strict //actor[2]/text()

This will create a reading with the Name "Actor" and the value "Charles Y".

Since XPath specifications can define several values / matches, HTTPMOD can also interpret these and store them in multiple readings:

attr htest reading01Name Actor
attr htest reading01XPath-Strict //actor/text()

will create the readings

Peter X
Charles Y
John Doe

Further replacements of URL, header or post data

sometimes it might be helpful to dynamically change parts of a URL, HTTP header or post data depending on existing readings, internals or perl expressions at runtime. This might be needed to pass further variables to a server, a current date or other things.

To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes

  • replacement[0-9]*Regex
  • replacement[0-9]*Mode
  • replacement[0-9]*Value
  • [gs]et[0-9]*Replacement[0-9]*Value

a replacement always replaces a match of a regular expression.

replacement[0-9]*Mode: The way the replacement value is defined can be specified with the replacement mode.

  • If the replacement[0-9]*Mode is reading, then the corresponding replacement[0-9]*Value is interpreted as the name of a reading of the same device or as device:reading to refer to another device.
  • If the replacement[0-9]*Mode is internal, then the corresponding replacement[0-9]*Value is interpreted as the name of an internal of the same device or as device:internal to refer to another device.
  • If the replacement[0-9]*Mode is text, then the corresponding replacement[0-9]*Value is interpreted as a static text
  • If the replacement[0-9]*Mode is expression , then the corresponding replacement[0-9]*Value is evaluated as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.

Example:

attr mydevice getData {"get" :["%%value%%.value"]}
attr mydevice replacement01Mode text
attr mydevice replacement01Regex %%value%%

attr mydevice get01Name Chlor
attr mydevice get01Replacement01Value 34.4008

attr mydevice get02Name Something
attr mydevice get02Replacement01Value 31.4024

defines that %%value%% will be replaced by a static text.

All Get commands will be HTTP post requests of a similar form. Only the %%value%% will be different from get to get. The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008. A second get will look the same except a different name and replacement value.

The mode expression allows you to define your own replacement syntax:

        
attr mydevice replacement01Mode expression
attr mydevice replacement01Regex {{([^}]+)}}
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")
attr mydevice getData {"get" :["{{temp}}.value"]}

In this example any {{name}} in a URL, header or post data will be passed on to the perl function ReadingsVal which uses the string between {{}} as second parameter. This way one defined replacement can be used for many different readings.

replacing reading values when they have not been updated / the device did not respond

If a device does not respond then the values stored in readings will keep the same and only their timestamp shows that they are outdated. If you want to modify reading values that have not been updated for a number of seconds, you can use the attributes

  • (reading|get)[0-9]*(-[0-9]+)?MaxAge
  • (reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacementMode
  • (reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacement

Every time the module tries to read from a device, it will also check if readings have not been updated for longer than the MaxAge attributes allow. If readings are outdated, the MaxAgeReplacementMode defines how the affected reading values should be replaced. MaxAgeReplacementMode can be text or expression.

MaxAge specifies the number of seconds that a reading should remain untouched before it is replaced.

MaxAgeReplacement contains either a static text that is used as replacement value or a Perl expression that is evaluated to give the replacement value. This can be used for example to replace a temperature that has not bee updated for more than 5 minutes with the string "outdated - was 12":

attr PM readingMaxAge 300
attr PM readingMaxAgeReplacement "outdated - was " . $val
attr PM readingMaxAgeReplacementMode expression

The variable $val contains the value of the reading before it became outdated.


Additional notes

If you don't know which URLs, headers or POST data your web GUI uses, you might try a local proxy like BurpSuite BurpSuite to track requests and responses

Advanced configuration to define a set and send data to a device

When a set option is defined by attributes, the module will use the value given to the set command and integrate it into an HTTP-Request that sends the value to the device. The definitions for URL, headers and post data can contain the placeholder $val which will be replaced by the value given to the set command.

This can be as simple as:

# No cyclic requests and no main URL needed in this example
define MyDevice none 0

attr MyDevice set01Name Licht
attr MyDevice set01URL http://192.168.1.22/switch=$val

A user command

set MyDevice Licht 1

will be translated into the http GET request

http://192.168.1.22/switch=1

In this example a map would also be helpful, that translates on / off to 0 or 1 and allows the user to select on/of in fhemweb:

attr MyDevive set01Map 0:off, 1:on

This also provides input validation to make sure that only on and off can be used with the set command.

In more complex Scenarios you might need to login before sending a command and the Login might create a session id that has to be part of further requests either in the URL, in headers or in the post data.

Extension to the above example for a PoolManager 5 where a set needs a session id in the URL and the values have to be passed in JSON strings as post data:

attr PM set01Name HeizungSoll
attr PM set01URL http://MyPoolManager/cgi-bin/webgui.fcgi?sid=$sid
attr PM set01Hint 6,10,20,30
attr PM set01Min 6
attr PM set01Max 30
attr PM setHeader1 Content-Type: application/json
attr PM set01Data {"set" :{"34.3118.value" :"$val" }}

This example defines a set option with the name HeizungSoll. By issuing set PM HeizungSoll 10 in FHEM, the value 10 will be sent in the defined HTTP Post to URL http://MyPoolManager/cgi-bin/webgui.fcgi in the Post Data as

{"set" :{"34.3118.value" :"10" }}

The optional attributes set01Min and set01Max define input validations that will be checked in the set function. The optional attribute set01Hint will define a selection list for the Fhemweb GUI.

If a parameter to a set command is not numeric but should be passed on to the device as text, then you can specify the attribute setTextArg. For example:

attr PM set01TextArg

If a set command should not require a parameter at all, then you can specify the attribute NoArg. For example:

attr PM set03Name On
attr PM set03NoArg


Advanced configuration to create a valid session id that might be necessary in set options

In simple cases logging in works with basic authentication. In the case HTTPMOD accepts a username and password as part of the URL in the form

http://User:Password@192.168.1.18/something

However basic auth is seldom used. If you need to fill in a username and password in a HTML form and the session is then managed by a session id, here is how to configure this:

when sending data to an HTTP-Device in a set, HTTPMOD will replace any $sid in the URL, Headers and Post data with the internal $hash->{sid}. To authenticate towards the device and give this internal a value, you can use an optional multi step login procedure defined by the following attributes:

sid[0-9]*URL
sid[0-9]*IDRegex
sid[0-9]*Data.*
sid[0-9]*Header.*
sid[0-9]*IgnoreRedirects

Each step can have a URL, Headers, Post Data pieces and a Regex to extract a resulting Session ID into $hash->{sid}. HTTPMOD will create a sorted list of steps (the numbers between sid and URL / Data / Header) and the loop through these steps and send the corresponding requests to the device. For each step a $sid in a Header or Post Data will be replaced with the current content of $hash->{sid}.

Using this feature, HTTPMOD can perform a forms based authentication and send user name, password or other necessary data to the device and save the session id for further requests.

To determine when this login procedure is necessary, HTTPMOD will first try to do a set without doing the login procedure. If the Attribute ReAuthRegex is defined, it will then compare the HTTP Response to the set request with the regular expression from ReAuthRegex. If it matches, then a login is performed. The ReAuthRegex is meant to match the error page a device returns if authentication or reauthentication is required e.g. because a session timeout has expired.

If for one step not all of the URL, Data or Header Attributes are set, then HTTPMOD tries to use a sidURL, sidData.* or sidHeader.* Attribue (without the step number after sid). This way parts that are the same for all steps don't need to be defined redundantly.

Example for a multi step login procedure:

attr PM reAuthRegex /html/dummy_login.htm 
attr PM sidURL http://192.168.70.90/cgi-bin/webgui.fcgi?sid=$sid
attr PM sidHeader1 Content-Type: application/json
attr PM sid1IDRegex wui.init\('([^']+)'
attr PM sid2Data {"set" :{"9.17401.user" :"fhem" ,"9.17401.pass" :"password" }}
attr PM sid3Data {"set" :{"35.5062.value" :"128" }}
attr PM sid4Data {"set" :{"42.8026.code" :"pincode" }}

In this case HTTPMOD detects that a login is necessary by looking for the pattern /html/dummy_login.htm in the HTTP response. If it matches, it starts a login sequence. In the above example all steps request the same URL. In step 1 only the defined Header is sent in an HTTP get request. The response will contain a session id that is extraced with the regex wui.init\('([^']+)'.

In the next step this session id is sent in a post request to the same URL where tha post data contains a username and password. The a third and a fourth request follow that set a value and a code. The result will be a valid and authorized session id that can be used in other requests where $sid is part of a URL, header or post data and will be replaced with the session id extracted above.

Advanced configuration to define a get and request additional data with its own request from a device

The normal automatic HTTP request that is done repeatedly after the defined interval has elapsed works well in cases where all required readings can be requested in one common HTTP request. If however a device needs individual requests with different URLs or different POST data for each value, then another method is necessary. For such cases a get option can be defined and the user can either issue Fhem get commands each time he needs the reading or the user can set an attribute to request the reading automatically together with the normal iteration. For each get option attributes define an individual URL, optional headers, and post data as well as individual regular expressions and formatting options.

Example for a Siemens webserver provided by Lanhydrock:

define ozw672 HTTPMOD https://192.168.178.8/api/auth/login.json?user=test&pwd=test 300

attr ozw672 get1Name tempAussen
attr ozw672 get1URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1960
attr ozw672 get1Poll 1
attr ozw672 get1PollDelay 1800

attr ozw672 get2Name tempAussenGemischt
attr ozw672 get2URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1964
attr ozw672 get2Poll 1
attr ozw672 get2PollDelay 1800

attr ozw672 get3Name tempTWW
attr ozw672 get3URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1996
attr ozw672 get3Poll 1

attr ozw672 get4Name tempKesselSoll
attr ozw672 get4URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1910
attr ozw672 get4Poll 1

attr ozw672 get5Name tempKesselRuecklauf
attr ozw672 get5URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1915
attr ozw672 get5Poll 1

attr ozw672 get6Name tempKesselRuecklaufSoll
attr ozw672 get6URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1916
attr ozw672 get6Poll 1

attr ozw672 get7Name anzahlStartsBrenner
attr ozw672 get7URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1927
attr ozw672 get7PollDelay 1800
attr ozw672 get7Poll 1

attr ozw672 get8Name statusKessel
attr ozw672 get8URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1898
attr ozw672 get8Poll 1
attr ozw672 get8Regex Value": "([a-zA-Zü ]*)"
attr ozw672 get8Map Aus:0, Nachlauf aktiv:5, Freigegeben für TWW:10, Freigegeben für HK:20, In Teillastbetrieb für TWW:40, In Teillastbetrieb für HK:50, In Betrieb für Trinkwasser:90, In Betrieb für Heizkreis:100

attr ozw672 getRegex Value": "[ ]*([-.0-9]*)"

attr ozw672 reAuthRegex .*session not valid.*
attr ozw672 sid1IDRegex .*"(.*-.*-.*-[0-9a-z]*).*
attr ozw672 sid1URL https://192.168.178.8/api/auth/login.json?user=test&pwd=test


Advanced attributes

ReAuthRegex
regular Expression to match an error page indicating that a session has expired and a new authentication for read access needs to be done.
This attribute only makes sense if you need a forms based authentication for reading data and if you specify a multi step login procedure based on the sid.. attributes.
This attribute is used for all requests. For set and get operations you can however specify individual reAuthRegexes with the [gs]et[0-9]*ReAuthRegex attributes.
sid[0-9]*URL
different URLs or one common URL to be used for each step of an optional login procedure.
sid[0-9]*IDRegex
different Regexes per login procedure step or one common Regex for all steps to extract the session ID from the HTTP response
sid[0-9]*Data.*
data part for each step to be sent as POST data to the corresponding URL
sid[0-9]*Header.*
HTTP Headers to be sent to the URL for the corresponding step
sid[0-9]*IgnoreRedirects
Tells the HttpUtils to not follow HTTP Redirects for this Request. Might be needed for some devices that set a session cookie within a 303 Redirect.


set[0-9]+Name
Name of a set option
set[0-9]*URL
URL to be requested for the set option
set[0-9]*Data
Data to be sent to the device as POST data when the set is executed
set[0-9]*Header
HTTP Headers to be sent to the device when the set is executed
set[0-9]+Min
Minimum value for input validation.
set[0-9]+Max
Maximum value for input validation.
set[0-9]+Expr
Perl Expression to compute the raw value to be sent to the device from the input value passed to the set.
set[0-9]+Map
Map that defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb". This attribute atomatically creates a hint for FhemWEB so the user can choose one of the visible values or select a value with a slider.
set[0-9]+Hint
Explicit hint for fhemWEB that will be returned when set ? is seen. Can be used to get a slider or a list of values to choose from.
set[0-9]*ReAuthRegex
Regex that will detect when a session has expired an a new login needs to be performed.
get[0-9]+Name
Name of a get option and Reading to be retrieved / extracted
get[0-9]*URL
URL to be requested for the get option. If this option is missing, the URL specified during define will be used.
get[0-9]*Data
optional data to be sent to the device as POST data when the get is executed. if this attribute is not specified, an HTTP GET method will be used instead of an HTTP POST
get[0-9]*NoData
can be used to override a more generic attribute that specifies POST data for all get commands. With NoData no data is sent and therefor the request will be an HTTP GET.
get[0-9]*Header
optional HTTP Headers to be sent to the device when the get is executed
get[0-9]+Poll
if set to 1 the get is executed automatically during the normal update cycle (after the interval provided in the define command has elapsed)
get[0-9]+PollDelay
if the value should not be read in each iteration (after the interval given to the define command), then a minimum delay can be specified with this attribute. This has only an effect if the above Poll attribute has also been set. Every time the update function is called, it checks if since this get has been read the last time, the defined delay has elapsed. If not, then it is skipped this time.
PollDelay can be specified as seconds or as x[0-9]+ which means a multiple of the interval in the define command.
get[0-9]*Regex
If this attribute is specified, the Regex defined here is used to extract the value from the HTTP Response and assign it to a Reading with the name defined in the get[0-9]+Name attribute.
If this attribute is not specified for an individual Reading but as getRegex, then it applies to all get options where no specific Regex is defined.
If neither a generic getRegex attribute nor a specific get[0-9]+Regex attribute is specified, then HTTPMOD tries all Regex / Reading pairs defined in Reading[0-9]+Name and Reading[0-9]+Regex attributes and assigns the Readings that match.
get[0-9]*Expr
this attribute behaves just like Reading[0-9]*Expr but is applied to a get value.
get[0-9]*Map
this attribute behaves just like Reading[0-9]*Map but is applied to a get value.
get[0-9]*Format
this attribute behaves just like Reading[0-9]*Format but is applied to a get value.
get[0-9]*CheckAllReadings
this attribute modifies the behavior of HTTPMOD when the HTTP Response of a get command is parsed.
If this attribute is set to 1, then additionally to any matching of get specific regexes (get[0-9]*Regex), also all the Regex / Reading pairs defined in Reading[0-9]+Name and Reading[0-9]+Regex attributes are checked and if they match, the coresponding Readings are assigned as well.
replacement[0-9]*Regex
Defines a replacement to be applied to an HTTP request header, data or URL before it is sent. This allows any part of the request to be modified based on a reading, an internal or an expression.
The regex defines which part of a header, data or URL should be replaced. The replacement is defined with the following attributes:
replacement[0-9]*Mode
Defines how the replacement should be done and what replacementValue means. Valid options are text, reading, interbal and expression.
replacement[0-9]*Value
Defines the replacement. If the corresponding replacementMode is text, then value is a static text that is used as the replacement.
If replacementMode is reading then Value can be the name of a reading of this device or it can be a reading of a different device referred to by devicename:reading.
If replacementMode is internal the Value can be the name of an internal of this device or it can be an internal of a different device referred to by devicename:internal.
If replacementMode is expression the the Value is treated as a Perl expression that computes the replacement value. The expression can use $1, $2 and so on to refer to capture groups of the corresponding regex that is matched against the original URL, header or post data.
[gs]et[0-9]*Replacement[0-9]*Value
This attribute can be used to override the replacement value for a specific get or set.
get|reading[0-9]*MaxAge
Defines how long a reading is valid before it is automatically overwritten with a replacement when the read function is called the next time.
get|reading[0-9]*MaxAgeReplacement
specifies the replacement for MaxAge - either as a static text or as a perl expression.
get|reading[0-9]*MaxAgeReplacementMode
specifies how the replacement is interpreted: can be text and expression.


showMatched
if set to 1 then HTTPMOD will create a reading with the name MATCHED_READINGS
that contains the names of all readings that could be matched in the last request.
showError
if set to 1 then HTTPMOD will create a reading and event with the Name LAST_ERROR
that contains the error message of the last error returned from HttpUtils.
queueDelay
HTTP Requests will be sent from a queue in order to avoid blocking when several Requests have to be sent in sequence. This attribute defines the delay between calls to the function that handles the send queue. It defaults to one second.
queueMax
Defines the maximum size of the send queue. If it is reached then further HTTP Requests will be dropped and not be added to the queue
minSendDelay
Defines the minimum time between two HTTP Requests.

Links