@jared-wiltshire Yes a custom page. I'm using the loginPageTemplate. I don't think using the ma-json-store directive as you wrote it will work because then the filename is still hardcoded. Unless there's a way to pass a variable to the xid attribute? Sorry I'm not experienced with html/javascript. I've tried that exact code, but it doesn't seem to work with a variable passed in. The only other way I can think of doing it is putting all my data in the same row.
Latest posts made by avilla
-
RE: Sql Queries/Sql Datapoint Confusion
-
Sql Queries/Sql Datapoint Confusion
I'm storing test files in the jsondata table in the H2 database. Each test file gets its own row. I need a way, from javascript, to query the table for a specific test (row) so I can extract data from the "Data" Column. I understand that you can input the xid into the ma-json-store directive, but this won't work for me because the filenames can't be hardcoded. I'm not sure how to do this and I've been trying/looking at all of the docs for a few days now. An example of what my jsondata table looks like is:
JSONDATA
I'm able to insert and extract data from the row with the name "filename". For instance I can add to and get filenames from the jsonobject under the "DATA" Column. However, once I retrieve the filename from code, I don't know how to use it to get the corresponding row's data. An sql query to do what I want would be:
select data from jsondata where name='<name of desired file>' . But I can't figure out how to achieve this using sql_datapoints/datasources/the ma-json-store directive. Thanks for your help. -
RE: Atomic File Reads and Writes/Calling Python script from app.js
@joelhaggar I looked at that documentation and i figured out how to do everything except get a list of values for each row under the name column. I can only get info for the first column, whether I'm doing row or column based query.
For example, I want to get a list in my javascript of everything under the "NAME" column so the result should be [play-area-admin, TC Gauges, custom-user-pages, Profile, hello .. etc].
-
RE: Atomic File Reads and Writes/Calling Python script from app.js
Hi thanks for the reply.
I've now decided to use the built in h2 database to save and load my data. To answer your question @JoelHaggar the system is an automated temperature/vacuum chamber that needs to read and save some temperatures and voltages every time it runs a test. It will also need to load data from previous tests. The way I have it set up, each test will get its own row in the jsondata table. I was able to figure out how to insert and modify values into the JSONDATA table so saving files is done, but not how to load.The issue I'm having right now is that I will need to allow the user to load values from previous tests by selecting a file name in a select box that's generated from an sql query. I can't figure out from javascript how to query the "name" column in the jsondata table for all the file names and then once a row based on the "name" column value is selected how to get that rows data (really I only need the "data" column). Is this possible using the sql datapoints? And if so could you possibly provide some quick example code? Sorry, this is all pretty new to me. Thanks for your quick replies!
-
Atomic File Reads and Writes/Calling Python script from app.js
Hi all,
I'm currently trying to find a way to save data to and load data from the local disk atomically so as to avoid corruption in the event of a loss of power. I'm running mango 2.8.6 on Windows. Everything is done on localhost so there's no remote access of any kind, I just need some way to store and retrieve the results of tests. As javascript doesn't have a way of writing files transactionally that I'm aware of, the only solution I can think of is to send the data to a python script, which will do the file writes, but I'm not sure how to call a python script using an ajax request in my mango script. I should also note that these file writes will have to happen fairly regularly (~every minute).Lastly, if this isn't a good way to achieve what I want should I instead use the H2 database? If so, I'm having trouble connecting to it. Do I need to change the blank username and password in env.properties file? The sql console works but the sql datasource isn't working for me. I'd also be interested to know how to query and publish to the sql database from code so that I can save and retrieve files, thanks.
-
Help using MangoAPI to Set Point Values
[0_1509407012389_home.html](Uploading 100%) [0_1509406989995_app.js](Uploading 100%)
Code attached.
I'm trying to use the MangoAPI to set and read points. I looked at the setPointValue tutorial in the mangoAPI docs and essentially copied the javascript and html into my app.js and home.html respectively. Learning JS as I go so there could be an issue with how I included the javascript code, and how I imported the libraries. The resource mango/api is failing to load for instance. The javascript code is now inside my controller so maybe that's the problem.
I want to be able to use MangoAPI.defaultApi.getPoint(xid) and MangoAPI.defaultApi.putValue(xid, pvt) to set points in javascript instead of using the ma-set-point directive. So if anyone has a well detailed way of doing this I'd appreciate it. Also as you may have noticed I'm simply modifying the loginPageTemplate for my own GUI, is there a better way to create an angular app from scratch? I don't actually need the login template.
/** * @copyright 2016 {@link http://infiniteautomation.com|Infinite Automation Systems, Inc.} All rights reserved. * @author Jared Wiltshire */ define([ 'angular', './directives/login/login', // load directives from the directives folder 'mango-3.3/maMaterialDashboards', // load mango-3.3 angular modules 'angular-ui-router', // load external angular modules 'angular-loading-bar', 'mango-2.0/api', ], function(angular, login) { 'use strict'; // create an angular app with our desired dependencies var mySinglePageApp = angular .module('mySinglePageApp', ['ui.router','angular-loading-bar','maMaterialDashboards','ngMessages','ngMaterial']) .controller('MyCtrl', ['$scope', '$timeout', function($scope, $timeout) { $scope.stepTypes = ['soak', 'ramp rate', 'ramp time', 'instant change']; var tabs = [ { title: 'Step 1', content: {}}, ], selected = null, previous = null; $scope.isReady = false; $scope.tabs = tabs; $scope.stepArray = tabs; $scope.selectedIndex = 2; $scope.profile = { cycles: 1, steps: {tabs} }; $scope.$watch('selectedIndex', function(current, old){ previous = selected; selected = tabs[current]; if ( old + 1 && (old != current)) $log.debug('Goodbye ' + previous.title + '!'); if ( current + 1 ) $log.debug('Hello ' + selected.title + '!'); }); $scope.addTab = function () { var titleStr = (tabs.length + 1).toString(); tabs.push({ title: "Step " + titleStr, content: {}, disabled: false}); }; $scope.removeTab = function (tab) { var index = tabs.indexOf(tab); tabs.splice(index, 1); for (var i = 0; i < tabs.length; i++) { tabs*.title = "Step " + (i + 1).toString(); } }; $scope.confirmReady = function() { var r = confirm("Press OK if Gate Valve is Open, Cancel otherwise.\n"); if (r == true) { r = confirm("Press OK if Chamber Door is closed, Cancel otherwise.\n"); if (r == true) { $scope.isReady = true; $timeout(function () { $scope.isReady = false; }, 4000); var points = DataPointQuery.query(); alert(points); submitProfile(profile) } } } $scope.submitProfile = function(profile) { var tabs = profile.steps; var steps = [{}]; for (var i = 0; i < tabs.length; i++){ steps* = tabs*.content.steps; } }; require(['jquery', 'mango/api'], function($, MangoAPI) { $('#updateValue').on('click', function(){ alert("hey"); //We need the data type for the point var xid = $("#xid").val(); MangoAPI.defaultApi.getPoint(xid).then(function(point){ //Check to see if settable if(point.pointLocator.settable === false){ var statusRow = []; statusRow.push(xid + ' not settable.'); statusRow.push(new Date()); //Append a status row $('#status').append(createRow(statusRow)); return; } var pvt = getPointValueTime(point); MangoAPI.defaultApi.putValue(xid, pvt).then(function(response){ var statusRow = []; statusRow.push('Set Value For ' + xid + ' to ' + pvt.value); statusRow.push(new Date()); //Append a status row $('#status').append(createRow(statusRow)); }).fail(MangoAPI.logError); }).fail(MangoAPI.logError); }); function createRow(columns){ var tr = $('<tr>'); for(var i=0; i<columns.length; i++){ var td = $('<td>'); td.text(columns*); tr.append(td); } return tr; } function getPointValueTime(dataPoint){ var value = null; //Set the value depending on the data point type if((dataPoint.pointLocator.dataType == "MULTISTATE")||(dataPoint.pointLocator.dataType == "NUMERIC")){ //Since the input is text type we must convert value = new Number($('#pointValueInput').val()); } else if(dataPoint.pointLocator.dataType == "BINARY"){ //Since the input is text type we must convert pointValue.value = new Boolean(); } else{ //For Alphanumeric value = $('#pointValueInput').val(); } return { value: value, timestamp: new Date().getTime(), annotation: 'Set by custom dashboard', dataType: dataPoint.pointLocator.dataType, }; } }); } ]); // add our directives to the app mySinglePageApp .directive('login', login); mySinglePageApp.config([ '$stateProvider', '$urlRouterProvider', '$compileProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $compileProvider, $locationProvider) { // disable angular debug info to speed up app $compileProvider.debugInfoEnabled(false); // enable html5 mode URLs (i.e. no /#/... urls) $locationProvider.html5Mode(true); // set the default state $urlRouterProvider.otherwise('/home'); $stateProvider.state('dashboard', { templateUrl: 'views/dashboard/main.html', resolve: { auth: ['$rootScope', 'User', function($rootScope, User) { // retrieves the current user when we navigate to a dashboard page // if an error occurs the $stateChangeError listener redirects to the login page $rootScope.user = User.current(); return $rootScope.user.$promise; }] } }).state('dashboard.home', { url: '/home', templateUrl: 'views/dashboard/home.html', }).state('dashboard.page1', { url: '/page1', templateUrl: 'views/dashboard/page1.html', }).state('login', { url: '/login', templateUrl: 'views/login.html', resolve: { loginTranslations: ['Translate', function(Translate) { return Translate.loadNamespaces(['login']); }] } }); }]); mySinglePageApp.run(['$rootScope', '$state', function($rootScope, $state) { // redirect to login page if we can't retrieve the current user when changing state $rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) { if (error && (error.status === 401 || error.status === 403)) { event.preventDefault(); // store the requested state so we can redirect there after login $state.loginRedirect = toState; $state.go('login'); } }); }]); // bootstrap the angular application angular.element(document).ready(function() { angular.bootstrap(document.documentElement, ['mySinglePageApp']); }); }); // define
<h1>Single Page App with Login</h1> <head> <title>Set Point Value</title> <!-- Add the Mango Favicon --> <link rel="icon" href="/images/favicon.ico"> <!-- Page Style --> <style></style> <link href="/resources/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <link href="/modules/dashboards/web/private/css/dashboard.css" rel="stylesheet"> <!-- Base Library --> <script type="text/javascript" src="/resources/loaderConfig.js"></script> <script type="text/javascript" src="/resources/require.js"></script> <script type="text/javascript" src="/resources/main.js"></script> <script type="text/javascript"> </script> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Angular Material Template</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/resources/angular-csp.css"></link> <link rel="stylesheet" href="../vendor/angular-material/angular-material.css"> <link rel="stylesheet" href="../vendor/material-design-icons/iconfont/material-icons.css"> <link rel="stylesheet" href="../vendor/mdPickers/mdPickers.css"> <link rel="stylesheet" href="styles/main.css"> <!-- Scripts from Module Directory --> <script src="/resources/require.js"></script> <script src="/resources/loaderConfig.js"></script> <script src="../../js/loaderConfig.js"></script> <script type='text/javascript' src='/resources/ng-infinite-scroll.min.js'></script> <script type="text/javascript" src="/resources/main.js"></script> <script>require(['dashboards/loginPageTemplate/app']);</script> </head> <div id="main"> <h1>Set Point Values</h1> <div class="row"> <div class="col-md-12"> <label for="xid">Xid: </label><input type="text" id="xid" value="voltage"/> <label id="pointValueLabel" class="formLabel" for="pointValue">Value:</label> <input id="pointValueInput" type="number" value="100.01"></input> <button type="button" id="updateValue">Update</button> </div> </div> <div class="row"> <div class="col-md-12"> <table class="table"> <tr><th>Status</th><th>Time</th></tr> <tbody id="status"></tbody> </table> </div> </div> </div> <div layout="column"> <div ng-if="appLoading" class="app-loading"> <i class="fa fa-cog fa-spin"></i> </div> <div layout="column" flex class="step-card" ng-controller="MyCtrl"> <div flex="grow" layout="column" layout-gt-xs="row"> <md-card flex> <md-card-content> <h1> Profile Creator </h1> <md-p> Add steps to your profile and hit submit when done. Unless you select a time, the profile will start immediately. The program will ask you to confirm that the gate valve is open and the chamber door is closed. <md-p> <div layout="column" layout-padding ng-cloak ng-init="stepTypes = ['soak', 'instant change', 'ramp time', 'ramp rate']; myObj = {Type: '', Hours: 0 ,Minutes: 0, Seconds: 0, SoakEnable: true}"> <br/> <md-content class="md-padding"> <md-tabs md-dynamic-height md-selected="selectedIndex" md-autoselect> <md-tab ng-repeat="tab in tabs" ng-disabled="tab.disabled" label="{{tab.title}}"> <div class="demo-tab tab{{$index%4}}" style="padding: 25px; text-align: center;"> <md-input-container class="md-block" flex-gt-sm> <label>Step Type</label> <md-select ng-model="tabs[$index].content.type"> <md-option ng-value="stepType" ng-repeat="stepType in stepTypes">{{ stepType }}</md-option> </md-select> </md-input-container> <!--Soak Step Input--> <div ng-if="tabs[$index].content.type == 'soak'"> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Hours</label> <input ng-model="tabs[$index].content.parameters.hours" type="number" step="1" min="0"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Minutes</label> <input ng-model="tabs[$index].content.parameters.minutes" type="number" step="1" min="0"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Seconds</label> <input ng-model="tabs[$index].content.parameters.seconds" type="number" step="1" min="0"> </md-input-container> </div> <!--Ramp Rate Step Input--> <div ng-if="tabs[$index].content.type == 'ramp rate'"> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Target Set Point</label> <input ng-model="tabs[$index].content.parameters.targetSetPoint" type="number" step="0.1"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Ramp Rate (Celsius Per Min)</label> <input ng-model="tabs[$index].content.parameters.rampRate" type="number" step="1" min="0"> </md-input-container> </div> <!--Ramp Time Step Input--> <div ng-if="tabs[$index].content.type == 'ramp time'"> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Target Set Point</label> <input ng-model="tabs[$index].content.parameters.targetSetPoint" type="number" step="0.1"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Hours</label> <input ng-model="tabs[$index].content.parameters.hours" type="number" step="1" min="0"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Minutes</label> <input ng-model="tabs[$index].content.parameters.minutes" type="number" step="1" min="0"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Seconds</label> <input ng-model="tabs[$index].content.parameters.seconds" type="number" step="1" min="0"> </md-input-container> </div> <!--Instant Change Input--> <div ng-if="tabs[$index].content.type == 'instant change'"> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Target Set Point</label> <input ng-model="tabs[$index].content.parameters.targetSetPoint" default="0" type="number" step="0.1"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Hours</label> <input ng-model="tabs[$index].content.parameters.hours" type="number" default="0" step="1" min="0"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Minutes</label> <input ng-model="tabs[$index].content.parameters.minutes" type="number" default="0" step="1" min="0"> </md-input-container> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Seconds</label> <input ng-model="tabs[$index].content.parameters.seconds" type="number" step="1" min="0"> </md-input-container> </div> </div> <form ng-submit="addTab()" layout="column" class="md-padding" style="padding-top: 0;"> <div layout="row" layout-sm="column"> <div flex style="position: relative;"> <h2 class="md-subhead" style="position: absolute; bottom: 0; left: 0; margin: 0; font-weight: 500; text-transform: uppercase; line-height: 35px; white-space: nowrap;">Add a new Tab:</h2> </div> <md-button class="md-primary md-raised" ng-disabled="tabs.length <= 1" ng-click="removeTab( tabs[$index] )">Remove Step</md-button> <md-button class="add-tab md-primary md-raised" ng-disabled="!tabs" type="submit" style="margin-right: 0;">Add Step</md-button> </div> </form> </md-tab> </md-tabs> </md-content> <md-input-container class="md-icon-float md-icon-right md-block"> <label>Number of Profile Cycles</label> <input ng-model="profile.cycles" type="number" step="1" min="1"> </md-input-container> <md-input-container> <label>Choose a point</label> <ma-point-list limit="200" ng-model="myPoint"></ma-point-list> </md-input-container> <p>You have chosen point "{{myPoint.name}}". It is {{myPoint.enabled ? 'enabled' : 'disabled'}} and belongs to device {{myPoint.deviceName}}</p> <ma-get-point-value point="myPoint"></ma-get-point-value> <div> <p> {{myPoint.pointLocator.settable}} </p></div> <md-button ng-click="myPoint.setValue(1771)" class="md-raised">Set to 5</md-button> <md-button class="md-primary md-raised" ng-disabled="!tabs" ng-click="confirmReady()">Submit</md-button> <br/> <div ng-show="isReady"> <md-p><br/>Profile Starting</md-p><br/><br/> <md-progress-linear md-mode="indeterminate"></md-progress-linear></div> <pre ng-bind="profile | json"></pre> </div> </md-card-content> </md-card> </div> </div> <md-card flex> <md-card-content> <h1> Set Point Graphs </h1> <div layout="column"> <md-input-container class="md-block"> <label>Choose a point</label> <ma-point-list limit="200" ng-model="point1"></ma-point-list> </md-input-container> <md-input-container class="md-block"> <label>Choose a point</label> <ma-point-list limit="200" ng-model="point2"></ma-point-list> </md-input-container> <md-input-container class="md-block"> <label>Values to display</label> <input type="number" min="1" max="1000" ng-model="count" ng-init="count=25"> </md-input-container> </div> <ma-point-values point="point1" values="point1Values" latest="count"> </ma-point-values> <ma-point-values point="point2" values="point1Values2" latest="count"> </ma-point-values> <ma-serial-chart style="height: 300px; width: 100%" series-1-values="point1Values" series-1-point="point1" series-2-values="point1Values2" series-2-point="point2"> </ma-serial-chart> </md-card-content> </md-card> <md-card flex> <md-card-content> <h1> Temperature Gauges </h1> <div layout="row" ng-controller="MyCtrl"> <div flex> <p>TC 1 module 3</p> <ma-get-point-value point-xid="DP_949013" point="myPoint1"></ma-get-point-value> <ma-gauge-chart point="myPoint1" interval="10" start="-20" end="120" style="width:100%; height:200px"></ma-gauge-chart> </div> <div flex> <p>TC 2 module 3</p> <ma-get-point-value point-xid="DP_809116" point="myPoint2"></ma-get-point-value> <ma-gauge-chart point="myPoint2" interval="10" start="-20" end="120" style="width:100%; height:200px"></ma-gauge-chart> </div> </div> <div layout="row" ng-controller="MyCtrl"> <div flex> <p>TC 3 module 3</p> <ma-get-point-value point-xid="DP_949013" point="myPoint1"></ma-get-point-value> <ma-gauge-chart point="myPoint1" interval="10" start="-20" end="120" style="width:100%; height:200px"></ma-gauge-chart> </div> <div flex> <p>TC 4 module 3</p> <ma-get-point-value point-xid="DP_809116" point="myPoint2"></ma-get-point-value> <ma-gauge-chart point="myPoint2" interval="10" start="-20" end="120" style="width:100%; height:200px"></ma-gauge-chart> </div> </div> <div layout="row" ng-controller="MyCtrl"> <div flex> <p>TC 5 module 3</p> <ma-get-point-value point-xid="DP_949013" point="myPoint1"></ma-get-point-value> <ma-gauge-chart point="myPoint1" interval="10" start="-20" end="120" style="width:100%; height:200px"></ma-gauge-chart> </div> <div flex> <p>TC 6 module 3</p> <ma-get-point-value point-xid="DP_809116" point="myPoint2"></ma-get-point-value> <ma-gauge-chart point="myPoint2" interval="10" start="-20" end="120" style="width:100%; height:200px"></ma-gauge-chart> </div> </div> </md-card-content> </md-card> </div> <p><a ui-sref="dashboard.home">Back to home page</a></p> <p>You have reached the home page! You are logged in as {{user.username}}.</p> <p><a ui-sref="dashboard.page1">Go to page 1.</a></p> <p><a ui-sref="login">Go to the login page.</a></p>