diff --git a/.DS_Store b/.DS_Store index 7a5db0b..eaaefa9 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Widgets/.DS_Store b/Widgets/.DS_Store index c6404ea..8e8a643 100644 Binary files a/Widgets/.DS_Store and b/Widgets/.DS_Store differ diff --git a/Widgets/notes/addNote.html b/Widgets/notes/addNote.html new file mode 100644 index 0000000..3538012 --- /dev/null +++ b/Widgets/notes/addNote.html @@ -0,0 +1,31 @@ +
+ +

New Note

+ + +
+ +
+
+
+ +
+
+
+ + +
+ +
+ \ No newline at end of file diff --git a/Widgets/notes/addNote.js b/Widgets/notes/addNote.js new file mode 100644 index 0000000..8860ad7 --- /dev/null +++ b/Widgets/notes/addNote.js @@ -0,0 +1,90 @@ +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); +let entityService = $injector.get(widgetContext.servicesMap.get('entityService')); +console.log(widgetContext); +openAddEntityDialog(); + +function openAddEntityDialog() { + customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe(() => {}); +} + +function AddEntityDialogController(instance) { + let vm = instance; + + vm.entityName = entityName; + + vm.attributes = {}; + vm.timeseries = {}; + + vm.editEntity = vm.fb.group({ + attributes: vm.fb.group({ + note: "" + }) + }); + + getEntityInfo(); + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.save = function() { + vm.loading = true; + saveAttributes(entityId).subscribe( + () => { + vm.dialogRef.close(null); + }, () =>{ + vm.loading = false; + } + ); + }; + + function getEntityAttributes(attributes) { + for (var i = 0; i < attributes.length; i++) { + vm.attributes[attributes[i].key] = attributes[i].value; + } + } + + function getEntityInfo() { + vm.loading = true; + attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE').subscribe( + function (data) { + console.log(data); + getEntityAttributes(data); + + vm.editEntity.patchValue({ + attributes: vm.attributes + }, {emitEvent: false}); + vm.loading = false; + } + ); + /*attributeService.getEntityTimeseries(entityId, ["LOGS"],Date.now() - 24*60*60*1000, Date.now() ).subscribe( + function (data) { + console.log(data); + //getEntityTimeseries(data); + + vm.editEntity.patchValue({ + timeseries: vm.timeseries + }, {emitEvent: false}); + vm.loading = false; + } + );*/ + } + + function saveAttributes(entityId) { + let attributes = vm.editEntity.get('attributes').value; + let attributesArray = []; + for (let key in attributes) { + if (attributes[key] !== vm.attributes[key]) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + /*if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + }*/ + return attributeService.saveEntityTimeseries(entityId,"ANY", [{"lastUpdateTs": Date.now(), "key": widgetContext.datasources[0].dataKeys[0].name, "value": attributes.note}] ); + //return widgetContext.rxjs.of([]); + } +} diff --git a/Widgets/notes/editNote.html b/Widgets/notes/editNote.html new file mode 100644 index 0000000..1818c92 --- /dev/null +++ b/Widgets/notes/editNote.html @@ -0,0 +1,187 @@ +
+ +

Edit {{entityType.toLowerCase()}} {{entityName}}

+ + +
+ + +
+
+
+ + Entity Name + + + + Entity Label + + +
+
+ + Entity Type + + + + Type + + +
+
+
+ + Latitude + + + + Longitude + + +
+
+ + Address + + + + Owner + + +
+
+ + Integer Value + + + Invalid integer value. + + +
+ + + {{ (editEntityFormGroup.get('attributes.booleanValue').value ? "value.true" : "value.false") | translate }} + +
+
+
+
+
Relations
+
+
+
+
+
+ + Direction + + + {{ ("relation.search-direction." + direction.value) | translate}} + + + + Relation direction is required. + + + + +
+
+ + +
+
+
+ +
+
+
+
+
+
+
New Relations
+
+
+
+
+
+ + Direction + + + {{ ("relation.search-direction." + direction.value) | translate}} + + + + Relation direction is required. + + + + +
+
+ + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+ + +
+
diff --git a/Widgets/notes/editNote.js b/Widgets/notes/editNote.js new file mode 100644 index 0000000..b2a2d89 --- /dev/null +++ b/Widgets/notes/editNote.js @@ -0,0 +1,216 @@ +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let entityService = $injector.get(widgetContext.servicesMap.get('entityService')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); +let entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService')); + +openEditEntityDialog(); + +function openEditEntityDialog() { + customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe(); +} + +function EditEntityDialogController(instance) { + let vm = instance; + + vm.entityName = entityName; + vm.entityType = entityId.entityType; + vm.entitySearchDirection = { + from: "FROM", + to: "TO" + }; + vm.attributes = {}; + vm.oldRelationsData = []; + vm.relationsToDelete = []; + vm.entity = {}; + + vm.editEntityFormGroup = vm.fb.group({ + entityName: ['', [vm.validators.required]], + entityType: [null], + entityLabel: [null], + type: ['', [vm.validators.required]], + attributes: vm.fb.group({ + latitude: [null], + longitude: [null], + address: [null], + owner: [null], + number: [null, [vm.validators.pattern(/^-?[0-9]+$/)]], + booleanValue: [false] + }), + oldRelations: vm.fb.array([]), + relations: vm.fb.array([]) + }); + + getEntityInfo(); + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.relations = function() { + return vm.editEntityFormGroup.get('relations'); + }; + + vm.oldRelations = function() { + return vm.editEntityFormGroup.get('oldRelations'); + }; + + vm.addRelation = function() { + vm.relations().push(vm.fb.group({ + relatedEntity: [null, [vm.validators.required]], + relationType: [null, [vm.validators.required]], + direction: [null, [vm.validators.required]] + })); + }; + + function addOldRelation() { + vm.oldRelations().push(vm.fb.group({ + relatedEntity: [{value: null, disabled: true}, [vm.validators.required]], + relationType: [{value: null, disabled: true}, [vm.validators.required]], + direction: [{value: null, disabled: true}, [vm.validators.required]] + })); + } + + vm.removeRelation = function(index) { + vm.relations().removeAt(index); + vm.relations().markAsDirty(); + }; + + vm.removeOldRelation = function(index) { + vm.oldRelations().removeAt(index); + vm.relationsToDelete.push(vm.oldRelationsData[index]); + vm.oldRelations().markAsDirty(); + }; + + vm.save = function() { + vm.editEntityFormGroup.markAsPristine(); + widgetContext.rxjs.forkJoin([ + saveAttributes(entityId), + saveRelations(entityId), + saveEntity() + ]).subscribe( + function () { + widgetContext.updateAliases(); + vm.dialogRef.close(null); + } + ); + }; + + function getEntityAttributes(attributes) { + for (var i = 0; i < attributes.length; i++) { + vm.attributes[attributes[i].key] = attributes[i].value; + } + } + + function getEntityRelations(relations) { + let relationsFrom = relations[0]; + let relationsTo = relations[1]; + for (let i=0; i < relationsFrom.length; i++) { + let relation = { + direction: 'FROM', + relationType: relationsFrom[i].type, + relatedEntity: relationsFrom[i].to + }; + vm.oldRelationsData.push(relation); + addOldRelation(); + } + for (let i=0; i < relationsTo.length; i++) { + let relation = { + direction: 'TO', + relationType: relationsTo[i].type, + relatedEntity: relationsTo[i].from + }; + vm.oldRelationsData.push(relation); + addOldRelation(); + } + } + + function getEntityInfo() { + widgetContext.rxjs.forkJoin([ + entityRelationService.findInfoByFrom(entityId), + entityRelationService.findInfoByTo(entityId), + attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE'), + entityService.getEntity(entityId.entityType, entityId.id) + ]).subscribe( + function (data) { + getEntityRelations(data.slice(0,2)); + getEntityAttributes(data[2]); + vm.entity = data[3]; + vm.editEntityFormGroup.patchValue({ + entityName: vm.entity.name, + entityType: vm.entityType, + entityLabel: vm.entity.label, + type: vm.entity.type, + attributes: vm.attributes, + oldRelations: vm.oldRelationsData + }, {emitEvent: false}); + } + ); + } + + function saveEntity() { + const formValues = vm.editEntityFormGroup.value; + if (vm.entity.label !== formValues.entityLabel){ + vm.entity.label = formValues.entityLabel; + if (formValues.entityType == 'ASSET') { + return assetService.saveAsset(vm.entity); + } else if (formValues.entityType == 'DEVICE') { + return deviceService.saveDevice(vm.entity); + } + } + return widgetContext.rxjs.of([]); + } + + function saveAttributes(entityId) { + let attributes = vm.editEntityFormGroup.get('attributes').value; + let attributesArray = []; + for (let key in attributes) { + if (attributes[key] !== vm.attributes[key]) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + } + return widgetContext.rxjs.of([]); + } + + function saveRelations(entityId) { + let relations = vm.editEntityFormGroup.get('relations').value; + let tasks = []; + for(let i=0; i < relations.length; i++) { + let relation = { + type: relations[i].relationType, + typeGroup: 'COMMON' + }; + if (relations[i].direction == 'FROM') { + relation.to = relations[i].relatedEntity; + relation.from = entityId; + } else { + relation.to = entityId; + relation.from = relations[i].relatedEntity; + } + tasks.push(entityRelationService.saveRelation(relation)); + } + for (let i=0; i < vm.relationsToDelete.length; i++) { + let relation = { + type: vm.relationsToDelete[i].relationType + }; + if (vm.relationsToDelete[i].direction == 'FROM') { + relation.to = vm.relationsToDelete[i].relatedEntity; + relation.from = entityId; + } else { + relation.to = entityId; + relation.from = vm.relationsToDelete[i].relatedEntity; + } + tasks.push(entityRelationService.deleteRelation(relation.from, relation.type, relation.to)); + } + if (tasks.length > 0) { + return widgetContext.rxjs.forkJoin(tasks); + } + return widgetContext.rxjs.of([]); + } +} + diff --git a/meshifyDrivers/.DS_Store b/meshifyDrivers/.DS_Store index ff2a3e1..5fc03d6 100644 Binary files a/meshifyDrivers/.DS_Store and b/meshifyDrivers/.DS_Store differ diff --git a/meshifyDrivers/mainHPRPI/main.py b/meshifyDrivers/mainHPRPI/main.py index 9e1da06..dbd484e 100644 --- a/meshifyDrivers/mainHPRPI/main.py +++ b/meshifyDrivers/mainHPRPI/main.py @@ -339,8 +339,8 @@ class meshifyMain(): clientData = json.load(creds) except: clientData = {"clientId": mac, "username": "admin", "password": "columbus"} - with open("mqtt.json", "w+") as creds: - json.dump(clientData, creds) + #with open("mqtt.json", "w+") as creds: + #json.dump(clientData, creds) self.mqtt = paho.Client(client_id=clientData["clientId"], clean_session=True) # change to false for mqtt.meshify.com diff --git a/uplink_converter.js b/uplink_converter.js new file mode 100644 index 0000000..da674ba --- /dev/null +++ b/uplink_converter.js @@ -0,0 +1,74 @@ +// Decode an uplink message from a buffer +// payload - array of bytes +// metadata - key/value object + +/** Decoder **/ + +// decode payload to string +//var payloadStr = decodeToString(payload); + +// decode payload to JSON +var mapping = { + "b8:27:eb:26:55:c0:01:99": { + "deviceName": "Fee BM", + "customer": "Faskens", + "latitude": 32.1418251, + "longitude": -102.2530966 + }, + "b8:27:eb:3d:e9:11:01:99": { + "deviceName": "AW Battery", + "customer": "Faskens", + "latitude": 32.090579, + "longitude": -102.244011 + } +}; +var data = decodeToJson(payload); +var channel = metadata.topic.split("/").slice(-1)[0]; +var devicetype = metadata.topic.split("/").slice(4)[0]; +var mac = metadata.topic.split("/").slice(5)[0]; +var deviceName = mapping[mac].deviceName; +var deviceType = devicetype; +var customerName = mapping[mac].customer; +//var groupName = 'All'; + +// use assetName and assetType instead of deviceName and deviceType +// to automatically create assets instead of devices. +// var assetName = 'Asset A'; +// var assetType = 'building'; + +// Result object with device/asset attributes/telemetry data +var result = { + // Use deviceName and deviceType or assetName and assetType, but not both. + deviceName: deviceName, + deviceType: deviceType, + // assetName: assetName, + // assetType: assetType, + customerName: customerName, + // groupName: groupName, + attributes: { + latitude: mapping[mac].latitude, + longitude: mapping[mac].longitude, + Type: "colorpin" + }, + telemetry: { + + } +}; +result.telemetry[channel] = data[0].value; + +/** Helper functions **/ + +function decodeToString(payload) { + return String.fromCharCode.apply(String, payload); +} + +function decodeToJson(payload) { + // covert payload to string. + var str = decodeToString(payload); + + // parse string to JSON + var data = JSON.parse(str); + return data; +} + +return result; \ No newline at end of file