custom widget: send command to node

  • hi,

    i have read the "widget - sensor custom buttons", "rgb controller", "custom widget" and "custom widget - dynamic images on dashboard" topics but did only get a hint on what to do.

    what i have:
    a custom widget with a nice, touch enabled color picker, which is working. which means:

    • can be displayed on the dashboard
    • and is usable
    • and javascript events are fired (currently logs a rgb hex value to browser console)
    • using: iro.js

    what i want:

    • send the selected rgb hex value to a node

    i saw a mention to create a custom angular controller and plug that into Utilities > HTML additional headers > AngularJS custom controllers.
    can anyone provide an example of a angularjs controller to put there?

    i tried to use Utilities > Scripts like in the example "Custom widget" but the variables defined there do not seem to be accessible in the Templates. at least i was unable to use it to send a value to the node.

    so... i am currently stuck.
    is there any documentation (other than plowing through mycontrollers code) which describes how to add a custom widget which can send a value to a node generated in js? i know its possible to send a value using the Utilities > Scripts but this is rather static, as the script only runs during widget creation. which means it only runs on opening the dashboard and if i change the color-picker by touching/clicking it, i can not push the value to a node.

  • @elgarfo Yes, It is possible to add your custom controller in Utilities > HTML additional headers > AngularJS custom controllers. can you share your current work, I can extend from there?

  • @jkandasa, thanks for helping me out.

    currently i have this as template:

    <style type="text/css">
    .wrap {
      color: #fff;
      background: #171F30;
      margin: 0 auto;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
    <div class="wrap">
      <div class="colorPicker"></div>
    var colorPicker = new iro.ColorPicker(".colorPicker", {
      width: 320,
      height: 320,
      color: {r: 255, g: 0, b: 0},
      anticlockwise: true,
      borderWidth: 1,
      borderColor: "#fff",
    colorPicker.on("color:change", function(color) {
      console.log("hex: " + color.hexString);

    and this for the script:

    var colorSensor = mcApi.uidTag().getByUid("hi-wz-rgb-1").getResource();
    var uuid = mcApi.utils().getUUID();

    i tried to copy the "Sensors" controller from github modify it to make for a "Sensors2" controller an pasted that into the "AngularJS custom controllers":

    'use strict';
    angular.module('adf.widget.myc-sen-vars2', [])
          .widget('mycSenVars2', {
            title: 'Sensors2',
            description: 'Monitor and change sensors state',
            templateUrl: 'controllers/adf-widgets/adf-myc-sen-vars/view.html?mcv=${mc.gui.version}',
            controller: 'mycSenVarsController2',
            controllerAs: 'mycSenVars2',
            config: {
              showIcon: true,
            edit: {
              templateUrl: 'controllers/adf-widgets/adf-myc-sen-vars/edit.html?mcv=${mc.gui.version}',
              controller: 'mycSenVarsEditController2',
              controllerAs: 'mycSenVarsEdit2',
      .controller('mycSenVarsController2', function($scope, $interval, config, mchelper, $filter, SensorsFactory, TypesFactory, CommonServices){
        var mycSenVars2 = this;
        mycSenVars2.showLoading = true;
        mycSenVars2.isSyncing = true;
        mycSenVars2.variables = {};
        $scope.tooltipEnabled = false;
        $scope.hideVariableName= !config.showIcon;
        $scope.cs = CommonServices;
        //HVAC heater options - HVAC flow state
        $scope.hvacOptionsFlowState = TypesFactory.getHvacOptionsFlowState();
        //HVAC heater options - HVAC flow mode
        $scope.hvacOptionsFlowMode = TypesFactory.getHvacOptionsFlowMode();
        //HVAC heater options - HVAC fan speed
        $scope.hvacOptionsFanSpeed = TypesFactory.getHvacOptionsFanSpeed();
        //Defined variable types list
        $scope.definedVariableTypes = CommonServices.getSensorVariablesKnownList();
      //update rgba color
      $scope.updateRgba = function(variable){
        variable.value = CommonServices.rgba2hex(variable.rgba);
        function loadVariables(){
          mycSenVars2.isSyncing = true;
          SensorsFactory.getVariables({'ids':config.variableIds}, function(response){
              mycSenVars2.variables = response;
              mycSenVars2.isSyncing = false;
                mycSenVars2.showLoading = false;
        function updateVariables(){
          }else if(config.variableIds.length > 0){
        //load variables initially
        //Update Variable / Send Payload
        $scope.updateVariable = function(variable){
          SensorsFactory.updateVariable(variable, function(){
            //update Success
        // refresh every second
        var promise = $interval(updateVariables, config.refreshTime*1000);
        // cancel interval on scope destroy
        $scope.$on('$destroy', function(){
      }).controller('mycSenVarsEditController2', function($scope, $interval, config, mchelper, $filter, TypesFactory, CommonServices){
        var mycSenVarsEdit2 = this;
        mycSenVarsEdit2.cs = CommonServices;
        mycSenVarsEdit2.variables = TypesFactory.getSensorVariables();

    but this does not show up at all in the dashboard.

    that's why i am asking for a simple example for a custom angular controller as i am not too familiar with angular yet.

  • @elgarfo Thanks for the script. Looks like iro.js do not have angular support 😞
    For two way binding, we need angularJS support.

  • @jkandasa ok thats a little sad. but this will not stop me from trying 🙂

    lets say i wanted to write a custom widget (lets also assume something simple like an html5 slider/range input)


    <input id="slider1" type="range" min="0" max="100" />
    <script type="text/javascript">
      $('#slider1').on('change', function(e) {
        console.log('slider1 value: '  + $(this).val());


    var stepperMotor = mcApi.uidTag().getByUid("hi-wz-blinds-1").getResource();
    var uuid = mcApi.utils().getUUID();

    as far as i can tell, this is a pretty basic example which does not rely on incompatible external libs. what do i need to add to which section to make this a widget with two-way binding?

    all i am looking for is an example for a custom 2 way widget.

  • @elgarfo I do not know how to do with HTML 5. however I made a two-way widget with the angular slider.


    • create HTML template with sensor variable id
    • create dummy javascript to supply buildings
    • add custom css and js files.
    • add custom controller
    • add dependency module in angular (workaround, I do not find a way to include new modules into the controller creation)

    HTML template:

    <div ng-controller="myCustomWidgetController" ng-init="${sId};loadVariable();">
      <rzslider rz-slider-model="sVariable.value" rz-slider-options="slider.options"></rzslider>

    Dummy JavaScript:

    // dummy script


    CSS and JS file:


    Custom controller:

    myControllerModule.controller('myCustomWidgetController', function($scope, SensorsFactory){
        $scope.sVariable = {
          id: null,
        $scope.loadVariable = function(){
          SensorsFactory.getVariable({id:$}, function(response){
            if(response.value != undefined){
              $scope.sVariable.value = parseInt(response.value);
        $scope.slider = {
          options: {
            floor: 0,
            ceil: 100,
            step: 1,
            minLimit: 0,
            maxLimit: 90,
            onEnd: function() {
        // send payload
        $scope.sendPayload = function(sVariable){
          SensorsFactory.updateVariable(sVariable, function(){
            //update Success

    Workaround, add a module on the app level

    File: mycontroller/www/app.js



    Widget in dashboard



  • @jkandasa your support is outstanding 👍
    your example works good and i can use it to build a dashboard to my needs. thank you very very much.

    the reason it took me so long to respond is, that i needed to trace a startup error on my end:
    [$injector:nomod] Module 'rzModule' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.


    • dashboard not loading correctly ({{ variable }} everywhere, nothing works)
    • angular throwing error about undefined module
    • testing with dev-console on firefox angular.module('rzModule'); yielded no error.
    • rzslider.js was actually loaded


    • firefox does not support <link rel="import">
    • the polyfill i pushed to github fb3d0d96 is working but:
    • too late.

    so the polyfill for the import-feature is working, as i am able to load the rzModule after the dashboard html loaded completely and angular tried to load.
    but it is not working fast enough.

    i am currently trying to find a way to either delay angular startup until all imports are handled or to find a better way to include the /_configurations/additional-headers.html

    current workaround: put <script src=""></script> directly into index.html for firefox 😕

    html imports are also deprecated in chrome since v70 and will be removed with v73 which is only two versions from now (v71 as of this writing). see: chrome platform status

  • @elgarfo If we change anything in our current implementation, can fix the issue in both firefox and chrome? Any idea?

  • How can I download the latest SNAPSHOT with this PR?
    Is this it? Https: //

  • @wanvo Compiled and uploaded in SNAPSHOT location.

  • @jkandasa Thanx!
    I checked this widget in Chrome and Firefox, it works great.

Log in to reply

Suggested Topics