• header.categories
    • header.recent
    • header.tags
    • header.popular
    • register
    • login

    custom widget: send command to node

    scheduled pinned locked moved Dashboard
    21 posts 4 posters 6.7k views 2 watching
    loading-more-posts
    • oldest-to-newest
    • newest-to-oldest
    • most-votes
    reply
    • reply-as-topic
    guest-login-reply
    deleted-message
    • E offline
      elgarfo
      global:last-edited-by,

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

      jkandasaJ one-reply-to-this-post last-reply-time reply quote 0
      • jkandasaJ offline
        jkandasa @elgarfo
        global:last-edited-by,

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

        one-reply-to-this-post last-reply-time reply quote 0
        • E offline
          elgarfo
          global:last-edited-by,

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

          jkandasaJ one-reply-to-this-post last-reply-time reply quote 0
          • jkandasaJ offline
            jkandasa @elgarfo
            global:last-edited-by, jkandasa

            @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

            one-reply-to-this-post last-reply-time reply quote 1
            • E offline
              elgarfo
              global:last-edited-by, elgarfo

              @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

              jkandasaJ topic:replies-to-this-post, 2 last-reply-time reply quote 1
              • jkandasaJ offline
                jkandasa @elgarfo
                global:last-edited-by,

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

                one-reply-to-this-post last-reply-time reply quote 0
                • jkandasaJ offline
                  jkandasa @elgarfo
                  global:last-edited-by,

                  @elgarfo Thank you for the PR https://github.com/mycontroller-org/mycontroller/pull/486

                  one-reply-to-this-post last-reply-time reply quote 0
                  • W offline
                    wanvo
                    global:last-edited-by,

                    How can I download the latest SNAPSHOT with this PR?
                    Is this it? Https: //travis-ci.org/mycontroller-org/mycontroller/builds/472109919

                    jkandasaJ one-reply-to-this-post last-reply-time reply quote 0
                    • jkandasaJ offline
                      jkandasa @wanvo
                      global:last-edited-by,

                      @wanvo Compiled and uploaded in SNAPSHOT location.

                      one-reply-to-this-post last-reply-time reply quote 1
                      • W offline
                        wanvo
                        global:last-edited-by, wanvo

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

                        one-reply-to-this-post last-reply-time reply quote 1
                        • R offline
                          RMF69
                          global:last-edited-by, RMF69

                          I'm just testing out various examples to understand how things work, I'm getting

                          Failed at: ${sId}  [in template "unknown" at line 1, column 69]
                          
                          

                          which I assume is from the first line of the html template, its not finding the angularjs custom controller ? I did modify app.js.

                          I'm pretty sure I've done all of the above to get the slider to appear on dashboard, but I must of missed something. I pasted the angularjs custom controller into the text field in HTML additional headers.

                          Any help 🙂 thanks

                          R one-reply-to-this-post last-reply-time reply quote 0
                          • R offline
                            RMF69 @RMF69
                            global:last-edited-by, RMF69

                            @RMF69 To myself... the script binding id mistyped {sId:2}... got the camel case wrong. Slider is now visible but I get 400 error... as I don't have the variable set up correctly which will get updated ? I've created a global variable "sVariable" but I don't think this is right. How do I get the value out of the slider when its value changes ?

                            R one-reply-to-this-post last-reply-time reply quote 0
                            • R offline
                              RMF69 @RMF69
                              global:last-edited-by,

                              @RMF69 Ok looking through code, I understand that its updating a sensor.variabel and that this id is passed in via the script binding {sId:31}... 31 is the id of a sensor S_LIGHT_LEVEL![alt text](Screenshot from 2019-12-28 13-05-08.png
                              I still get 400 bad requests... and

                              ERROR [Acme.Utils.ThreadPool(0)-PooledThread: Acme.Serve.Serve$ServeConnection@1415568e] [org.mycontroller.standalone.api.jaxrs.exception.mappers.ApplicationExceptionMapper:42] ApplicationException,
                              org.jboss.resteasy.spi.ApplicationException: java.lang.NullPointerException
                              

                              I'd love to understand what I've done wrong:)

                              jkandasaJ one-reply-to-this-post last-reply-time reply quote 0
                              • jkandasaJ offline
                                jkandasa @RMF69
                                global:last-edited-by,

                                @RMF69 Can you report your MyController version? and if you modified the script please report your script.

                                R one-reply-to-this-post last-reply-time reply quote 0
                                • R offline
                                  RMF69 @jkandasa
                                  global:last-edited-by,

                                  @jkandasa

                                  Thanks, I've got the latest, Version 1.5.0. And I've not changed anything, just the script binding {sId:31} where 31 is the id of a light dimmer virtual sensor... see picture. I took the ID from the url of that page in the picture below.Screenshot_2020-01-02_18-31-18.png

                                  jkandasaJ one-reply-to-this-post last-reply-time reply quote 0
                                  • jkandasaJ offline
                                    jkandasa @RMF69
                                    global:last-edited-by, jkandasa

                                    @RMF69 Click on the Edit icon on the Level variable and use the id from the URL.

                                    in version 1.5, you no need to hardcode rzModule on mycontroller/www/app.js. We have an option on UI to update angular modules.
                                    3482e3a0-d2f2-4189-9f3f-2f4ae7750d72-image.png

                                    R one-reply-to-this-post last-reply-time reply quote 0
                                    • R offline
                                      RMF69 @jkandasa
                                      global:last-edited-by,

                                      @jkandasa Thanks for confirming that in 1.5, the hardcoding of rzModule in mycontroller/www/app.js isn't required. However if I remove rzModule then the slider widget isn't displayed.

                                      Still I can't get the example to work...I've got the id from the place you mention, mine is still 31... I've also noticed that the intial value of the sensor->variable isn't populated. I created simple script to update the value

                                      var myImports = new JavaImporter(java.lang, java.util, org.mycontroller.standalone.utils.McUtils);
                                      
                                      with(myImports) {
                                          dimSensor = mcApi.uidTag().getByUid("dimSensor").getResource();
                                          var v = dimSensor.value; //value2/3 etc
                                          dimSensor.setValue(parseInt(v) + 1);
                                          mcApi.sensor().sendPayload(dimSensor);
                                      }
                                      

                                      I insert the following code into "AngularJs custom controllers"

                                      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);
                                            });
                                          };
                                        });
                                      

                                      Which is just the original example above, no changes... it seems to me that the pointer/reference to the variable I want to have connected to the slider is correct or working, both when the value is initialized on the loadVariable and when updated. But I just can't see what I've done wrong.

                                      jkandasaJ one-reply-to-this-post last-reply-time reply quote 0
                                      • jkandasaJ offline
                                        jkandasa @RMF69
                                        global:last-edited-by,

                                        @RMF69 Do you see any error on the browser console and/or in MyController log file?

                                        R one-reply-to-this-post last-reply-time reply quote 0
                                        • R offline
                                          RMF69 @jkandasa
                                          global:last-edited-by,

                                          @jkandasa Sorry... I thought I'd edited or deleted that reply saying it didn't work. It now works... I'd taken the sensor ID from the summary page and not the edit page as you pointed me to in your last reply.

                                          So its working now... my mistake, thanks for your patience.

                                          one-reply-to-this-post last-reply-time reply quote 1
                                          • first-post
                                            last-post

                                          0

                                          online

                                          644

                                          users

                                          532

                                          topics

                                          3.4k

                                          posts
                                          Copyright © 2015-2025 MyController.org | Contributors | Localization