• Recent
    • Tags
    • Popular
    • Register
    • Login

    Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

    Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website Mango 5 Documentation Website

    maJsonStore (JSON store)

    Scripting general Discussion
    4
    35
    14.6k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • richard.mortimerR
      richard.mortimer
      last edited by richard.mortimer

      Hi,

      With the dashboards I'm designing, I've managed to store my data points I want to look at in an array, which is geat for the one overview page, but now I'm looking at making detail page(s), which uses some of the same datapoints.

      I'm wondering if the ma-json-store is a better place to save the details of the datapoints - it's actually an array of arrays which is formatted thus:

          DataPoints=[
              {ID:'001',Location:'Lot 17',URL:'/ui/lot17',CustomerLoad:'001DP_POD-827990', PV:'001DP-8212690',PVMax:'DP_008082',GenRun:'DP_812',BattCharge:'684160',BattTemp:'4275',FuelLevel:'9842',GenOutput: '37690'}
             ,{ID:'002',Location:'Lot 860',URL:'/ui/lot860',CustomerLoad:'7990',PV:'2690',PVMax:'008082',GenRun:'2852',BattCharge:'44800',BattTemp:'444275',FuelLevel:'999842',GenOutput: '767690'}
      (etc, for another 10 or so points)
      ]
      

      Where the second value is the XID of the datapoint I'm addressing (I've snipped a lot down so it doesn't look so messy!)

      Before I plunge in and move everything around - I was curious if the JSON store could save the information in this state, or whether I'd need to change it's format somewhat - and also how I (or someone else) could administer these points when new MangoES are added. I've seen some rudimentary documentation on the component, but was also curious if there was some more detailed/advanced examples beyond the http://localhost:8080/ui/docs/ng-mango/ma-json-store ?

      Thanks

      Richard

      1 Reply Last reply Reply Quote 0
      • Jared WiltshireJ
        Jared Wiltshire
        last edited by Jared Wiltshire

        I would highly recommend leveraging a dynamic watchlist based on data point tags to gather a list of data points for a displaying on a dashboard/page. See https://help.infiniteautomation.com/dynamic-dashboard-workflow.

        Do not use data point XIDs to store information about a datapoint, use tags for this!
        See here for how to add tags - https://forum.infiniteautomation.com/topic/4153/using-ma-state-params/10
        Example naming schema
        Site 1, voltage: name: 'Voltage', tags: {location: 'Site 1'}
        Site 1, current: name: 'Current', tags: {location: 'Site 1'}
        Site 2, voltage: name: 'Voltage', tags: {location: 'Site 2'}
        Site 2, current: name: 'Current', tags: {location: 'Site 2'}
        and so on
        Your page basically uses the Watchlist to retrieve all data points belonging to a selected location, then you bind components on your page to a particular point in this array by filtering on the data point name.

        You can still store auxillary data about a site in the JSON store, e.g. set points, limits etc. There is another example located at http://localhost:8080/ui/examples/utilities/json-store

        I would store the JSON data in an object where each key is the location string (same as what you store as the location tag value). e.g.

        {
          "Site 1": {
            limitA: 200,
            setPointB: -20.5
          },
          "Site 2": {
            limitA: 250,
            setPointB: -32.4
          }
        }
        

        Developer at Radix IoT

        1 Reply Last reply Reply Quote 1
        • richard.mortimerR
          richard.mortimer
          last edited by

          Thank you so much; that looks like exactly what I want for my individual pages, so I'm off to have a play with watchlists and see what I can do there. I'm sure I'll have a heap of questions in the near future, so I'll try to add them to this thread to make it a resource for those reading in the future.

          One question comes to mind for my "overview" page - can I cycle through the watchlist to plot all those points on a single page; I've got the page looking reasonable with the XID data at this stage:

          0_1556091729266_Display_of_sun-anon.png

          Cheers

          Richard

          1 Reply Last reply Reply Quote 0
          • CraigWebC
            CraigWeb
            last edited by

            Hi Richard

            The best way to cycle through the array that the watchlist gives you is to use the angular filter pipe. You can filter by any point attribute. such as deviceName, name or tag.

            richard.mortimerR 1 Reply Last reply Reply Quote 0
            • richard.mortimerR
              richard.mortimer @CraigWeb
              last edited by

              @craigweb said in maJsonStore (JSON store):

              Hi Richard

              The best way to cycle through the array that the watchlist gives you is to use the angular filter pipe. You can filter by any point attribute. such as deviceName, name or tag.

              Thanks - is it possible to see some sample/example code (or if you have a site which outlines it) to use the filter?

              Cheers

              Richard

              1 Reply Last reply Reply Quote 0
              • CraigWebC
                CraigWeb
                last edited by CraigWeb

                <div flex="100" flex-gt-md="33" layout="column" ng-if="designer.points | filter:{name:'Level'}:true | maFirst" ng-repeat="res in designer.points | filter:{name:'Level'}:false">  
                                <md-card>
                                        <md-toolbar class="md-whiteframe-1dp md-hue-3">
                                            <div class="md-toolbar-tools">
                                                <h2 flex="">
                                                    <span>{{ res.deviceName }} </span>
                        
                                                </h2>
                                            </div>
                                        </md-toolbar>
                                        <md-card-content> 
                                            <div flex="100" layout="row">
                                                <div layout="column" flex="50"> 
                        
                                                    <h2> Level:</h2>
                                                    <ma-point-value style=" width: 25%; font-weight: bolder; font-size: 25px;" enable-popup="right" point="res"></ma-point-value>
                                                </div>
                                                <div class="flex">
                                                    <img ng-src="/rest/v2/file-stores/default/img/Reservoir.svg" style="z-index:-2 width: 200px; height: 150px;">
                                            
                                            </div>
                                                </div>
                                    </md-card-content>
                                    </md-card> 
                        </div>
                

                My watchlist is a dynamic watchlist the queries all points where the "site" tag matches.

                I then filter down to only have the points with name = "Level" then use ng-repeat to display them all in a md-card.

                Your table might get a little complicated with nested ng-repeats. You might want to read up on the angular docs on how to use ng-repeat-end. https://docs.angularjs.org/api/ng/directive/ngRepeat

                richard.mortimerR 1 Reply Last reply Reply Quote 0
                • richard.mortimerR
                  richard.mortimer
                  last edited by

                  Thanks - these are working quite well, and I've been making some good progress - I was curious if tags can be set on the edge devices, or if they can only be set on the server?

                  Cheers

                  Richard

                  1 Reply Last reply Reply Quote 0
                  • CraigWebC
                    CraigWeb
                    last edited by

                    The edge device and the server runs the same software The ES just has limited hardware capacity. So yes they can be set there and the publisher/data source can be set to update any point properties on the server if they are changed on the ES.

                    1 Reply Last reply Reply Quote 0
                    • richard.mortimerR
                      richard.mortimer @CraigWeb
                      last edited by

                      @craigweb said in maJsonStore (JSON store):

                      <div flex="100" flex-gt-md="33" layout="column" ng-if="designer.points | filter:{name:'Level'}:true | maFirst" ng-repeat="res in designer.points | filter:{name:'Level'}:false">  
                      

                      My watchlist is a dynamic watchlist the queries all points where the "site" tag matches.

                      I then filter down to only have the points with name = "Level" then use ng-repeat to display them all in a md-card.

                      Your table might get a little complicated with nested ng-repeats. You might want to read up on the angular docs on how to use ng-repeat-end. https://docs.angularjs.org/api/ng/directive/ngRepeat

                      Does the designer.points map to all points, that then need to be filtered? Or, after adding the tags, do I also need to create a dynamic watchlist (as is kinda eluded to here: https://forum.infiniteautomation.com/topic/4153/using-ma-state-params/15#) to address?

                      Thanks

                      Richard

                      1 Reply Last reply Reply Quote 0
                      • CraigWebC
                        CraigWeb
                        last edited by

                        This post is deleted!
                        1 Reply Last reply Reply Quote 0
                        • CraigWebC
                          CraigWeb
                          last edited by

                          Designer.points has all the points that are in the watchlist that I created, the watchlist points get brought into the page with a <ma-watch-list-get>

                          So yes you will need to make a watchlist.

                          The other option is to use a

                          <ma-point-query query="{name:query.filter, deviceName:query.filter}" limit="query.limit"
                          start="(query.page-1)*query.limit" sort="query.order" points="points" promise="promise"></ma-point-query>
                          

                          in your page, use {{points}} so show youthe object it returns.

                          1 Reply Last reply Reply Quote 0
                          • richard.mortimerR
                            richard.mortimer
                            last edited by

                            So, just trying to tie together Craig's example and Jared's example above, I'm getting confused how to filter by the tags; so far I have:

                            <ma-point-query query="{deviceName:'SPS001'}" points="points" promise="promise"></ma-point-query>
                            <!-- show me everything -->
                            <!--div style="color: white;background-color:black; border: 1px solid red;" ng-if="points" ><pre>{{points}}</pre></div-->
                                
                            <div md-progress="promise" style="border: 1px solid blue; background-color: white; color: black;" ng-repeat="point in points">
                                <span>{{point.xid}}</span>
                                <span style="background-color: yellow;">{{point.tags.Display}}</span>
                            </div>
                            

                            Which successfully shows me everything that matches the device name in the commented out (first) div, or the secondary DIV, which shows me the same points, but just the XID for the point and the tag for "Display" - but how do I get a specific point from the array if I want the "Display" equal to, say, "Battery Capacity" for this one site? I don't know if I need to put this filter within the ma-point-query section, or if I load the whole array into points and then filter in the ng-repeat section ... nor the syntax, as the tags seem to be at a secondary level of the initial query (as per the two spans, where one is point.xid and the tags are point.tag.Display).

                            BTW: there is a typo on the page: /ui/docs/ng-mango/ma-point-query in the 'limit' description: "no limit by defualt"

                            Thanks

                            Richard

                            1 Reply Last reply Reply Quote 0
                            • MattFoxM
                              MattFox
                              last edited by

                              I can help you with the point query.
                              You can either be specific at what you want at the beginning, or take a multitude of points then filter them accordingly with a filter or using ng-if="point.tags.Display=='displayType'"

                              For your point query, you can work from the watchlist builder to generate an RQL query.
                              You'll get something like:

                              <ma-point-query query="'eq(deviceName,SPS001)&in(tags.Display,Battery Capacity)'" points="points" promise="promise"></ma-point-query>
                              

                              Hope that's of some help

                              Fox

                              Do not follow where the path may lead; go instead where there is no path.
                              And leave a trail - Muriel Strode

                              1 Reply Last reply Reply Quote 0
                              • CraigWebC
                                CraigWeb
                                last edited by CraigWeb

                                Using the query builder as MattFox suggested is definitely a pro tip!

                                Your question seems to be around where best to do the filtering. IMO you will be better off doing one simple query to the backend and then doing all your filtering on the front end. That is if your page is going to have a lot of different components using those points. If the page is focused on only certain points then you could query for only those points. The choice is yours

                                The point query gives you an object with an array of points and all the points attributes, it is not live updating. So now you know that in your page you only have points from SPS001, you can now filter down to the specific point you want in sps001 as such. The syntax is like this because of the nested structure.

                                <ma-point-value point="points | filter:{tags:{Display: 'Battery Capacity'} }"></ma-point-value>
                                

                                You can have multiple filters like such

                                <ma-point-value point="points | filter:{deviceName:'myDevice',tags:{Site: 'myTag'} }"></ma-point-value>
                                

                                If you want to use an ng-repeat then you make your filter less precise that it gives multiple points that match the criteria. You have a couple of options for the order that the ng-repeat will use.

                                1 Reply Last reply Reply Quote 0
                                • richard.mortimerR
                                  richard.mortimer
                                  last edited by

                                  Unfortunately I'm still not getting the results I require; if I put the point query as:

                                  <ma-point-query query="'eq(tags.SiteName,SPS001)&&(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                  

                                  I'm getting nothing back, but if I put:

                                  <ma-point-query query="'eq(tags.SiteName,SPS001)'" points="points" ></ma-point-query>
                                  

                                  It only returns the tag SiteName and knocks out the tag Display, so I can't further filter on it...

                                  Also, when I did get this working (in a different capacity, using the SIteName tag to filter a specific site), the data populated in my DIV, but was destroyed almost instantaneously:

                                  <tr ng-repeat="site in sites.sites">
                                      <td>
                                          <ma-point-query query="'&in(tags.SiteName,{{site.name}})'" points="points" ></ma-point-query>
                                          <div style="color: white;background-color:black; border: 1px solid red;" ng-if="points | filter:{tags:'Display'}" ><pre>{{points}}</pre></div>
                                      </td>
                                  

                                  Is this where the promise keyword becomes important?

                                  Cheers

                                  Richard

                                  1 Reply Last reply Reply Quote 0
                                  • CraigWebC
                                    CraigWeb
                                    last edited by Jared Wiltshire

                                    Hi Richard

                                    The promise variable will have 3 states fulfilled, rejected and pending. It gives you the status of the query. So no is the answer to your question about the promise.

                                    <ma-point-query query="'eq(tags.SiteName,SPS001)&&(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                    

                                    There is no operatore for your second criteria. This should work

                                    <ma-point-query query="'eq(tags.SiteName,SPS001)&eq(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                    

                                    As Mattfox sugested useing the watchlist builder to make your RQL queries. Let me show you how. The nice thing about using this method is there is you can see the results immediately on the query preview tab.
                                    0_1557821191387_untitled (25).png

                                    As for what you are doing in the table. I think you might be running into scoping issues with using points. Hopefully, @Jared-Wiltshire can comment on that.

                                    ng-if="points | filter:{tags:'Display'}" Will not work and I'm sure there are plenty of errors in your browser's console when you use this. tags is an object, what you are doing there is filtering the points array for any object that has a tag with a value of string 'Display'

                                    As in my previous post if you want to filter with tags you need to supply a nested object the filter ie:

                                    point="points | filter:{tags:{Display: 'Battery Capacity'} }"
                                    

                                    If you want to use it in a ng-if you need to use maFirst

                                    point="points | filter:{tags:{Display: 'Battery Capacity'} | maFirst}"
                                    

                                    Lastly, I think that your pages are getting quite complex and you would be better off creating a user module where you have a controller to do all your logic and mapping of arrays,

                                    richard.mortimerR 1 Reply Last reply Reply Quote 0
                                    • richard.mortimerR
                                      richard.mortimer @CraigWeb
                                      last edited by

                                      @craigweb said in maJsonStore (JSON store):

                                      Hi Richard

                                      There is no operatore for your second criteria. This should work

                                      <ma-point-query query="'eq(tags.SiteName,SPS001)&eq(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                      

                                      Thanks - that was the syntax I was after; I couldn't see anything like i in the RQL syntax: https://cubicweb.readthedocs.io/en/3.26/book/annexes/rql/language/#rql

                                      Is there somewhere that I can read about this??

                                      Also I note that in my nested repeats, this will work, and display all the relevant info for a single point:

                                      <ma-json-store xid="sitesDataXID" value="sites"></ma-json-store>
                                      <div style="border:2px solid blue;" ng-repeat="site in sites.sites">
                                          <ma-point-query query="'eq(tags.SiteName,SPS001)&eq(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                          <!-- show me everything -->
                                          <div style="color: white;background-color:black; border: 1px solid red;">--{{ site.name }}--<pre>{{ points }}</pre>--</div>
                                      </div>
                                      

                                      0_1557900229406_cycle1.png

                                      Yet if I change the tag.SiteName to {{site.name}} thus:

                                      <ma-json-store xid="sitesDataXID" value="sites"></ma-json-store>
                                      <div style="border:2px solid blue;" ng-repeat="site in sites.sites">
                                          <ma-point-query query="'eq(tags.SiteName,{{site.name}})&eq(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                          <!-- show me everything -->
                                          <div style="color: white;background-color:black; border: 1px solid red;">--{{ site.name }}--<pre>{{ points }}</pre>--</div>
                                      </div>
                                      

                                      I'm getting this:

                                      0_1557900459270_cycle2.png

                                      Although the browsers (Firefox) code inspector displays the code as it should:

                                      0_1557901439677_cycle3.png

                                      So - should that work as I have it, or does Angular not allow variable substitution in this manner? I al;so tried to do it with ' + {{site.name}} + ' and a few variations (but clearly not the right one!)

                                      ng-if="points | filter:{tags:'Display'}" Will not work and I'm sure there are plenty of errors

                                      My apologies - I left this in with changing the page so much ...

                                      As Mattfox sugested useing the watchlist builder to make your RQL queries. Let me show you how. The nice thing about using this method is there is you can see the results immediately on the query preview tab.

                                      Thanks for that - I'm looking into how that all works ...

                                      Cheers

                                      Richard

                                      1 Reply Last reply Reply Quote 0
                                      • MattFoxM
                                        MattFox
                                        last edited by MattFox

                                        @richard-mortimer said in maJsonStore (JSON store):

                                        <div style="border:2px solid blue;" ng-repeat="site in sites.sites">
                                        <ma-point-query query="'eq(tags.SiteName,SPS001)&eq(tags.Display,Customer Load)'" points="points" ></ma-point-query>
                                        <!-- show me everything -->
                                        <div style="color: white;background-color:black; border: 1px solid red;">--{{ site.name }}--<pre>{{ points }}</pre>--</div>
                                        </div>

                                        Yikes, you're repeating your queries multiple times and calling the same data. We may need to start moving you into angularJS component territory.
                                        However, if you're after that site name, you need to do this:

                                        <ma-json-store xid="sitesDataXID" value="sites"></ma-json-store>
                                        <div style="border:2px solid blue;" ng-repeat="site in sites.sites">
                                            <ma-point-query query="'eq(tags.SiteName,'+site.name+')&eq(tags.Display,Customer Load)'" points="points[site.name]" ></ma-point-query>
                                            <!-- show me everything in this point! -->
                                            <div style="color: white;background-color:black; border: 1px solid red;">--{{ site.name }}--<pre>{{ points[site.name] }}</pre>--</div>
                                        </div>
                                        

                                        if you have points="points" being used every time for each of your ma-point-query items, they'll continue to be updated and overwrite one another as they all share the same scope.
                                        Storing them in an object using the site name as the key makes it a bit easier.
                                        or alternatively!

                                        <ma-json-store xid="sitesDataXID" value="sites"></ma-json-store>
                                        <div style="border:2px solid blue;" ng-repeat="(index,site) in sites.sites">
                                            <ma-point-query query="'eq(tags.SiteName,'+site.name+')&eq(tags.Display,Customer Load)'" points="points[index]" ></ma-point-query>
                                            <!-- show me everything in this point! -->
                                            <div style="color: white;background-color:black; border: 1px solid red;">--{{ site.name }}--<pre>{{ points[index] }}</pre>--</div>
                                        </div>
                                        

                                        This will map everything by the index in your JSON store.
                                        Let me know how you go.

                                        Fox

                                        Do not follow where the path may lead; go instead where there is no path.
                                        And leave a trail - Muriel Strode

                                        1 Reply Last reply Reply Quote 0
                                        • CraigWebC
                                          CraigWeb
                                          last edited by

                                          I agree with Mattfox and I think Richard will be more familiar since you can code pure javascript functions in the component controller to manipulate your data. instead of pseudo angular/javascript

                                          I believe you are safe to use points="points" unless points is initiated somewhere else in the ng-repeats parent scope. As ng-repeat creates a scope for each iteration but will first look in the parent scope for points

                                          1 Reply Last reply Reply Quote 0
                                          • richard.mortimerR
                                            richard.mortimer
                                            last edited by richard.mortimer

                                            Sorry to drag up an old subject, but I've got a curious thing happening within my repeats - and I'm not sure if it's an Angular issue, or I've done something to upset it ...

                                            My code used two ng-if statements to determine if the value is output value is in watts or kilowatts, thus:

                                            <span ng-repeat="point in points[site.name]"><!-- Load -->
                                                <ma-get-point-value point-xid="{{ point.xid }}" point="output"></ma-get-point-value>
                                                <div ng-if="output.value > 1000">{{ (output.value / 1000) | number:1 }}kW</div>
                                                <div ng-if="output.value <= 1000">{{ output.value | number:0 }}W</div>
                                            </span><!-- end Load -->
                                            

                                            The problem is - I'm sometimes getting two values returned, (for example 984W and 1kW) - if I directyly print the value on the screen via {{ output.value }} I'm seeing what I would expect to see (mostly integers, a couple of float types for some points).

                                            Am I doing something wrong here, or is there a better way to do this?

                                            [edit] Here's one I managed to catch as it happened:0_1559714978372_output_error.jpg

                                            Thanks

                                            Richard

                                            CraigWebC 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post