Examples of custom devices implemented in p44script

An implementation of a custom device always consists of two parts:

  • the so-called init-message, which describes the type of device as it should be visible in the Smarthome system. The init-message must be entered when the device is created and cannot be changed later without deleting it and creating it again (from the point of view of the SmartHome system, it is then a new, different device).

  • The actual implementation in p44script. This can be changed again and again until the function is as desired.

Complete Documentation

For complete documentation please see the Custom Devices page with full specification of the external device API (init message and other device communication)

Create Custom-Device

A new device is created with the "+ Scripted" button:

Custom Devices vDC header line

In the appearing dialog the init-Message can be entered.

Custom Devices Create Dialog

A valid init message must be entered here. A complete documentation of the init message can be found here; for the first experiments it is recommended to take one of the following examples.

Please note

  • The init message is compatible with the init messages used via the external device API via TCP socket for externally implemented devices. However, for devices implemented in p44script it is not necessary to specify a 'uniqueid', and usually not recommended.
  • For p44Script-implemented devices, the init message can be spread over several lines and provided with C-style comments /* ... */ (while the init message via the external device API must always be on a single line).

Edit custom device implementation

The implementation can be customized at any time using the edit button (pencil icon)

Custom Device line

Simple scripts can be entered directly in the appearing dialog, but for longer/more complex scripts it is recommended to use the built-in fullscreen code editor (via the link at the bottom right of the input field)

Custom Device edit dialog

In the following examples the JSON init-Message and the script code of the Implementation are shown in separate text fields, from which the examples can be easily copied and pasted.

For P44-DSB-X on Raspberry Pi: CPU temperature as sensor value

On RaspberryPi devices the CPU temp is available as a number in the file /sys/class/thermal/thermal_zone0/temp. With the following simple Custom Device a sensor device can be created from it:

Init message (details here):

{
  'message':'init',
  'protocol':'simple',
  'group':3, /* blue/climate */
  'name':'RPi CPU temp.', /* initial name */
  'sensors':[
    /* sensortype1 = temperature, updateinterval = 60 = read once per minute */
    {'sensortype':1,'usage':1,'hardwarename':'RPiCPU','min':0,'max':100,'resolution':0.1,'updateinterval':60}
  ]
}

Implementation (details of the content of the message() sent here).

// Every minute:
on(every(0:01)) {
  // read the value from the file, treat it as a number and scale it (file returns 1/1000 degrees)
  var t = number(readfile('/sys/class/thermal/thermal_zone0/temp'))/1000;
  // report as sensor value
  message(format("S0=%.1f",t))
}

// important: signals that it's ok that the script ends here
// Only the handler is running in the background.
// If this "return true" is missing, the implementation will be restarted 20 seconds after
// exit (assuming that an error has occurred)
return true

This creates a sensor device that reads the current CPU temperature from the system every minute, and reports it as a sensor value to the Smarthome system. It does not differ from any other temperature sensor (e.g. EnOcean devices etc.) in the way it works.

RPi CPU temperature Custom Device

!!! warning "userlevel 1 required". Because this example uses readfile() with an absolute path, the device must have at least userlevel 1 for security reasons. Production devices have userlevel 0 by default. Experimental DIY devices and devices with beta versions have userlevel 1. The userlevel is defined in /flash/p44userlevel. Thus, for devices with access to the commandline (e.g. P44-DSB-X) the userlevel can simply be set to 1 with echo 1 >/flash/p44userlevel.

myStrom switching socket: Simple HTTP API

From mystrom.ch there are switching sockets that can be connected via WiFi and switched and programmed via an app. This device is used here as an example because it has a simple API that can be controlled directly from the LAN {:target="_blank"}. Using this API, such an outlet can easily be used as a switchable output for the smarthome system (without depending on an external cloud!):

Init message (details here):

{
  'message':'init',
  'output':'light', /* with output of type "light"... */
  'dimmable':false, /* ...but not dimmable */
  'colorclass':8, /* universally usable, in digitalSTROM: black joker terminal */
}

Implementation (details of the content of the received message() m here): For the example to work, the correct IP address of the socket must be entered, see comment in code:

// the correct IP address of the socket must be entered here
var baseurl = "http://192.168.1.42"

// handle messages from the system (here: change of output value)
on (message()) as m {
  // if the message concerns the channel with index 0 (=brightness)...
  if (m.message=="channel" && m.index==0) {
    // control mySTROM API and switch it on, if brightness > 50%, otherwise off
    geturl(baseurl + format('/relay?state=%d', if(m.value>50, 1, 0)))
  }
}

return true // it's ok that the script ends here

This creates a device whose output can be set directly in the P44-xx web interface (via the gear icon), and behaves in the digitalSTROM Smarthome with all functions (room assignment, scene programming, etc.) like any other on/off switch actuator.

Power Outlet Device

The myStrom sockets can also measure the current drawn, and report back the current switching state (useful if this has been changed with the button on the socket). This can also be used with a slightly more advanced implementation:

Init-Message (new line sensors is added, details see here):

{
  'message':'init',
  'output':'light', /* with output of type "light"... */
  'dimmable':false, /* ...but not dimmable */
  'colorclass':8, /* universally usable, in digitalSTROM: black joker terminal */
  /* definition of a power sensor */
  'sensors':[{"sensortype":14, "usage":0, "hardwarename": "power", "min":0, "max":2300, "resolution":1, "updateinterval":30, "alivesigninterval":300}]
}

Implementation, which now additionally polls the status every 30 seconds, and reports back the effective state of the output (relay) as well as the power consumption (power).

function updatestate()
{
  var t = geturl(baseurl + '/report');
  log (7, "myCurrent reply = %s", t)
  var state = json(t);
  log (6, "myStrom state = %s", state)
  if (isvalid(state.relay)) {
    var msg = { "message": "channel", "index":0 }
    msg.value = if(state.relay, 100, 0);
    message(msg)
  }
  if (isvalid(state.power)) {
    var msg = { "message": "sensor", "index":0 }
    msg.value = state.power;
    message(msg)
  }
}

// the correct IP address of the socket must be entered here
var baseurl = "http://192.168.1.42"

on (message()) as m {
  if (m.message=="channel" && m.index==0) {
    geturl(baseurl + format('/relay?state=%d', if(m.value>50, 1, 0)))
  }
}

// every 30 seconds
on (every(30)) {
  // Read status
  updatestate()
}

// read current state immediately on device startup
updatestate()

return true // it's ok that the script ends here

The new device now has an additional sensor input that shows the current power consumption.

More examples in German part

Note - more examples in German version

Currently, there are some more examples in the German version of this page that are not yet translated to English (which will happen, eventually).