Extending Machineface with HAL Remote to control Smart-Plugs

This blog post explains how to extend the Machineface 3D printer UI with a custom UI element that interacts with HAL. For this purpose, this article explains the core concepts of HAL remote.

The blog post is a continuation of Controlling TP-Link HS100/110 Smart Plugs with Machinekit.

HAL Remote

HAL remote is a remote API for the Machinekit HAL (Hardware Abstraction Layer). HAL bases on reusable assets called components. These components can either be real-time or userland components.

HAL remote extends this concept by adding HAL remote components. HAL remote components do not have an instance handled by HAL. Instead, they are instantiated via a remote API.

remote_component

This concept allows mapping HAL remote components into the UI. For example, a HAL pin is represented by a button UI element. When pressing the button in the UI the pin value automatically changes in HAL.

The API or middleware behind HAL remote is called Machinetalk. It uses following de-facto standard technologies:

The remote UI for Machinekit Machineface uses QtQuickVcp library. QtQuickVcp is the Qt/QML language binding for Machinetalk.

For now, I will not go into more details about Machinetalk.

Development setup

To extend Machineface, you need a local copy of the Git repository. I recommend you to start by forking the Machineface repository on GitHub.

Then check out your forked repository locally.

git clone https://github.com/yourusername/Machineface.git

For editing the Machineface user interface I prefer using Qt Creator. Qt Creator comes with the Qt SDK.

You do not necessarily need to install the Qt SDK and to build QtQuickVcp. However, it helps when developing QtQuickVcp UIs. For install instructions, please take a look at the README.

Additionally, I prefer working with qmllive. A live coding environment for QML. This tool automatically reloads the UI source code whenever the file system is modified.

If you plan to use any other text editor you need to edit the Machineface source code on the Machinekit target device. Furthermore, you need to use configserver to remotely deploy the files to the Machinekit Client

Adding a remote component to HAL

Once we have a working development setup, it is time to modify the HAL configuration. For this purpose, we need to extend the setup_smartplugs function created in the last blog post.

Remember that we used a Python HAL configuration. The code that creates the HAL remote component for controlling the smart-plugs looks as follows.

rcomp = hal.RemoteComponent('smartplug-control', timer=100)
rcomp.newpin('power-enable', hal.HAL_BIT, hal.HAL_IO)
rcomp.newpin('fan-enable', hal.HAL_BIT, hal.HAL_IO)
rcomp.newpin('power', hal.HAL_FLOAT, hal.HAL_IN)
rcomp.newpin('energy', hal.HAL_FLOAT, hal.HAL_IN)
rcomp.ready()

The first line creates a new HAL remote component and assigns it the rcomp variable.

The first argument 'smartplug-control' of the Python class initializer is the name of the component.

The timer argument specifies how often the remote component values are sent to the remote clients.

In the following lines, we add new HAL pins to the component.

  • power-enable – to toggle the power plug
  • fan-enable – to toggle the fan plug
  • power – for monitoring the power consumption
  • energy – for monitoring the energy consumption

The ready function call tells the haltalk HAL remote service provider, to release the remote component.

Once created, it is possible to use the HAL remote component like any other HAL component.
For more details, please take a look at the complete source code on GitHub.

Adding a HAL remote component to Machineface

Next, it is time to add new UI elements and a new HAL remote component to Machineface.

The ./Machineface directory inside the Machineface repository contains all UI components of the Machineface UI.

machineface_source_tree

QML is organized into .qml files. Each file contains one root component with the name of the file. For example, LightControl.qml contains the LightControl QML component.

The DisplayPanel component contains the display panel on the right side of Machineface. An ideal place to add a new control element.

Moreover, the DisplayPanel already contains some HAL remote component based controls, namely:

  • FanControl
  • TemperatureControl
  • LightControl

These components are a perfect starting point for adding new control elements to Machineface. I encourage you to take a look at these components if you interested in learning how to add new controls to Machineface.

Based on these components I added a new QML file called SmartplugControl.qml. I will now go over the most important parts of the code. I recommend you to take a look at the complete source code on GitHub.

First of all, we need a HAL remote component.

import Machinekit.HalRemote 1.0

...

HalRemoteComponent {
    id: halRemoteComponent
    halrcmdUri: halrcmdService.uri
    halrcompUri: halrcompService.uri
    ready: (halrcmdService.ready && halrcompService.ready) || connected
    name: root.componentName
    containerItem: container
    create: false
    onErrorStringChanged: console.log(componentName + " " + errorString)
    onConnectedChanged: root.wasConnected = true
}

The first line imports the HalRemote QtQuick module.

The HalRemoteComponent represents the HAL remote component in QtQuickVcp. The halrcmdUri and halrcompUri properties specify the ZeroMQ service URIs. In this case, the component references to properties in a parent object.

When both services are ready the ready property is set to true. The component tried to connect to a remote Machinekit instance.

Also important is the name property, since it has to match the name of the remote component in HAL.

The create property tells QtQuickVcp to throw an error if no remote instance of the component exists.

You may wonder how the HalRemoteComponent matches pins to UI controls such as buttons. The QML item passed to the containerItem property is searched for HalRemote.Controls when the component becomes ready.

In the container item we can find following controls:

HalSwitch {
    name: "power-enable"
    halPin.direction: HalPin.IO
}

and

TextField {
    Layout.preferredWidth: root.width * 0.4
    readOnly: true
    text: energyPin.value.toFixed(2) + "kWh"

    HalPin {
        id: energyPin
        name: "energy"
        type: HalPin.Float
        direction: HalPin.In
    }
}

The HalPin item is a non-visible QML item representing a single HAL pin. name, type and direction have the same meaning as for regular HAL pins. Note that direction In means that a signal can drive this HAL pin.

The value property of the energyPin is then used as a source for the text property of the TextField.

The HalSwitch component is a combination of the Switch UI element and a HalPin. The checked property of the switch binds automatically to the HAL pin with the name power-enable.

The resulting control element looks as follows:

machineface_smartplug1

I cannot go into full details of how to implement a QtQuick/QML component here. If you are interested in this topic, I recommend you starting with the QML tutorial.

Summary

Concluding, this blog article explains how to extend Machineface with a new UI control. Furthermore, it explains some concepts of HAL remote and QtQuickVcp.

The full source code of the modified Machineface and UNI-PRINT-3D configuration is available in the home branch of the repositories.

I hope this blog post has been useful for you. If you have questions about HAL remote or want to give feedback, please comment on this post.

Your,
Machine Koder

3 thoughts on “Extending Machineface with HAL Remote to control Smart-Plugs”

Leave a Reply

Your email address will not be published. Required fields are marked *