custom widget: send command to node



  • @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;
    }
    </style>
    <div class="wrap">
      <div class="colorPicker"></div>
    </div>
    <script>
    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);
    });
    </script>
    

    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', [])
      .config(function(dashboardProvider){
        dashboardProvider
          .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: {
              variableIds:[],
              showIcon: true,
              itemsPerRow:"2",
              refreshTime:30,
            },
            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);
        $scope.updateVariable(variable);
      };
    
        function loadVariables(){
          mycSenVars2.isSyncing = true;
          SensorsFactory.getVariables({'ids':config.variableIds}, function(response){
              mycSenVars2.variables = response;
              mycSenVars2.isSyncing = false;
              if(mycSenVars2.showLoading){
                mycSenVars2.showLoading = false;
              }
          });
        };
    
        function updateVariables(){
          if(mycSenVars2.isSyncing){
            return;
          }else if(config.variableIds.length > 0){
            loadVariables();
          }
        }
    
        //load variables initially
        loadVariables();
        //updateVariables();
    
        //Update Variable / Send Payload
        $scope.updateVariable = function(variable){
          SensorsFactory.updateVariable(variable, function(){
            //update Success
          },function(error){
            displayRestError.display(error);
          });
        };
    
        // refresh every second
        var promise = $interval(updateVariables, config.refreshTime*1000);
    
        // cancel interval on scope destroy
        $scope.$on('$destroy', function(){
          $interval.cancel(promise);
        });
      }).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)

    template:

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

    script:

    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.

    Steps:

    • 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="sVariable.id=${sId};loadVariable();">
      <rzslider rz-slider-model="sVariable.value" rz-slider-options="slider.options"></rzslider>
    </div>
    

    Dummy JavaScript:

    // dummy script
    

    9de831a0-816c-4f94-8285-6e427c01b480-image.png

    CSS and JS file:

    https://cdnjs.cloudflare.com/ajax/libs/angularjs-slider/6.6.0/rzslider.min.css
    https://cdnjs.cloudflare.com/ajax/libs/angularjs-slider/6.6.0/rzslider.min.js
    

    52843ff4-392c-4de7-8132-887af7ae6b13-image.png

    Custom controller:

    myControllerModule.controller('myCustomWidgetController', function($scope, SensorsFactory){
        $scope.sVariable = {
          id: null,
          value:null
        };
      
        $scope.loadVariable = function(){
          SensorsFactory.getVariable({id:$scope.sVariable.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() {
                $scope.sendPayload($scope.sVariable);
            },
          }
      };
    
        // send payload
        $scope.sendPayload = function(sVariable){
          SensorsFactory.updateVariable(sVariable, function(){
            //update Success
          },function(error){
            displayRestError.display(error);
          });
        };
      });
    

    Workaround, add a module on the app level

    File: mycontroller/www/app.js

    rzModule
    

    f53f954f-e081-49d1-a8de-f127ec382950-image.png

    Widget in dashboard

    d933f59c-b34b-4b55-9800-2bfabfbe07a6-image.png

    d67fa588-62c3-415b-ad8b-b3984d9b882b-image.png



  • @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.

    symptoms:

    • 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

    cause:

    • 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="https://cdnjs.cloudflare.com/ajax/libs/angularjs-slider/6.6.1/rzslider.js"></script> directly into index.html for firefox 😕

    EDIT:
    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: //travis-ci.org/mycontroller-org/mycontroller/builds/472109919



  • @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

3
Online

475
Users

407
Topics

2.5k
Posts