123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- <html>
- <head>
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
- <meta charset="UTF-8">
- <title>ArozOS IoT Hub</title>
- <link rel="stylesheet" href="../../../script/tocas/tocas.css">
- <link rel="manifest" href="manifest.json">
- <script src="../../../script/tocas/tocas.js"></script>
- <script src="../../../script/jquery.min.js"></script>
- <script src="../../../script/ao_module.js"></script>
- <style>
- .ultrasmall.image{
- height:35px;
- margin:0px !important;
- margin-right:10px !important;
- }
- .selectable{
- cursor:pointer;
- }
- .selectable:hover{
- background-color:#f0f0f0;
-
- }
- .noborder{
- border: 1px solid transparent !important;
- }
- .controlBtn{
- position:absolute;
- right:8px;
- bottom:8px;
- }
- .devIcon{
- border-radius: 10px;
- }
- .primary.button{
- background-color: #4aa9eb !important;
- }
- .bottom.item{
- position:absolute;
- bottom: 0px;
- left:0px;
- width:100%;
- font-size:80%;
- }
- #sideMenu{
- height: calc(100% - 85px);
- }
- .primary.button{
- background-color: #4287f5 !important;
- }
- body{
- height:100%;
- background:rgba(247,247,247,0.95);
- }
- </style>
- </head>
- <body>
- <div class="ts right sidebar overlapped vertical menu">
- <div class="item">
- <div class="ts header">
- ArozOS IoT Hub
- <div class="sub header">Universal IoT Controller</div>
- </div>
- </div>
- <a class="selectable item" onClick="loadDevList();hideSideMenu();">
- <i class="refresh icon"></i> Refresh List
- </a>
- <a class="selectable item" onClick="scanDevices();hideSideMenu();">
- <i class="search icon"></i> Scan Devices
- </a>
- <div class="bottom item">
- CopyRight ArozOS Project 2021
- </div>
- </div>
- <div class="pusher">
- <div class="ts menu">
- <a class="item noborder" href="index.html"><img class="ts ultrasmall circular image" src="img/main_icon.png"> IoT Hub</a>
- <a class="right item" onClick="toggleSideMenu();"><i class="content icon"></i></a>
- </div>
- <div id="devList" class="ts container">
- </div>
- <br><br><br>
- </div>
- <!-- Show more information about thsi device-->
- <div id="moreInfoInterface" class="ts active dimmer" style="display:none;">
- <div style="position:absolute;width:100%;height:100%;left:0px;top:0px;" onClick='$("#moreInfoInterface").fadeOut("fast");'>
- </div>
- <div id="informationItnerface" class="ts segment mainUI" style="height:80%;width:95%;overflow-y:auto;">
- <div class="ts header">
- Device Properties
- </div>
- <br>
- <div class="ts horizontal form">
- <div class="field">
- <label>Device UUID</label>
- <input id="duid" type="text" readonly="true">
- </div>
- <div class="field">
- <label>IP Address</label>
- <input id="ipaddr" type="text" readonly="true">
- </div>
- <div class="field">
- <label>Communication Port</label>
- <input id="comport" type="text" readonly="true">
- </div>
- <div class="field">
- <label>Manufacturer</label>
- <input id="manufacturer" type="text" readonly="true">
- </div>
- <div class="field">
- <label>Version</label>
- <input id="version" type="text" readonly="true">
- </div>
- </div>
- <br>
- <button class="ts primary button" onClick='$("#moreInfoInterface").fadeOut("fast");'>Close</button>
- <br><br>
- </div>
- </div>
- <!-- Action can be done on this device -->
- <div id="actioninterface" class="ts active dimmer" style="display:none;">
- <div style="position:absolute;width:100%;height:100%;left:0px;top:0px;" onClick='$("#actioninterface").fadeOut("fast");'>
- </div>
- <div id="informationItnerface" class="ts segment mainUI" style="height:80%;width:95%;overflow-y:auto;">
- <div class="ts header">
- Device Actions
- </div>
- <br>
- <div class="ts horizontal form" id="statusList">
- <h3>No Status</h3>
- </div>
- <div class="ts divider"></div>
- <div class="ts horizontal form" id="actionForm">
- </div>
- <br>
- <button class="ts primary button" onClick='$("#actioninterface").fadeOut("fast");'>Close</button>
- <br><br>
- </div>
- </div>
- <div id="loadingMask" class="ts active dimmer" style="display:none;">
- <div class="ts text loader">Scanning in Progress</div>
- </div>
- <script>
- var currentlyViewingDevices = "";
- var uselocal = false; //Use Local as command sender or use Host as command sender
- var username = $("#data_session_username").text().trim();
- //ao_module Float Window functions
- ao_module_setWindowTitle("IoT Hub");
- ao_module_setWindowSize(465,730,true);
- if (!ao_module_virtualDesktop){
- $("body").css("background-color","white");
- }
- //Initiate the page content
- loadDevList();
-
- function inputbox(message, placeholder = ""){
- var input = prompt(message, placeholder);
- if (input != null) {
- return input;
- }else{
- return false;
- }
- }
- function scanDevices(){
- $("#loadingMask").show();
- $.get("../../../system/iot/scan", function(data){
- loadDevList();
- $("#loadingMask").hide();
- });
- }
- function hideSideMenu(){
- ts('.right.sidebar').sidebar('hide');
- }
- function showMore(object){
- var device = $(object).parent().parent();
- var duid = device.attr("uuid");
- var lastseen = device.attr("devip");
- var deviceData = device.attr("devicedata");
- deviceData = JSON.parse(decodeURIComponent(deviceData))
- console.log(deviceData);
- $("#duid").val(duid);
- $("#ipaddr").val(lastseen);
- $("#comport").val(deviceData.Port);
- $("#manufacturer").val(deviceData.Manufacturer);
- $("#version").val(deviceData.Version);
- currentlyViewingDevices = duid;
- $("#moreInfoInterface").fadeIn('fast');
- }
- function loadDevList(){
- $("#devList").html("");
- $.get("../../../system/iot/list", function(data){
- if (data.error !== undefined){
- alert(data.error);
- }else{
- data.forEach(device => {
- deviceData = encodeURIComponent(JSON.stringify(device));
- $("#devList").append(`<div class="ts segment HDSDev" devicedata="${deviceData}" uuid="${device.DeviceUUID}" devIp="${device.IPAddr}" port="${device.Port}" location="local">
- <div class="ts grid">
- <div class="four wide column"><img class="ts tiny devIcon image" src="img/system/loading.gif"></div>
- <div class="twelve wide column">
- <div class="ts container">
- <div class="ts header">
- <span class="devHeader">${device.Name}</span>
- <div class="sub devProperty header">${device.Model}</div>
- </div>
- </div>
- </div>
- </div>
- <div class="controlBtn infoMount">
- <button class="ts icon button" onClick="showMore(this);"><i class="notice icon"></i></button>
- <button class="ts primary icon button" onClick="action(this);"><i class="options icon"></i></button>
- </div>
- </div>`);
- });
-
- }
- });
- }
- function toggleSideMenu(){
- //$("#sideMenu").toggle();
- ts('.right.sidebar').sidebar('toggle');
- }
- function executeEndpoint(object, targetValue=""){
- var deviceID = $(object).attr("devid");
- var epd = JSON.parse(decodeURIComponent($(object).attr("epd")));
- if (epd.Type == "integer" || epd.Type == "float"){
- //Check if it is in range
- if (epd.Max && targetValue > epd.Max ){
- //Snap to max value if over max
- targetValue = epd.Max;
- }
- if (epd.Min && targetValue < epd.Min){
- //Snap to min value if under min
- targetValue = epd.Min;
- }
- }else if (epd.Type == "string"){
- //Check if regex
- if (epd.Regex && targetValue.match(stringToRegex(epd.Regex)) == null){
- //Invalid string input. Reject operation
- alert("Input string does not match request regex structure: " + epd.Regex);
- return;
- }
- }
- console.log(deviceID, epd, targetValue);
- }
- const stringToRegex = str => {
- // Main regex
- const main = str.match(/\/(.+)\/.*/)[1]
-
- // Regex options
- const options = str.match(/\/.+\/(.*)/)[1]
-
- // Compiled regex
- return new RegExp(main, options)
- }
- function action(object){
- //Clear the action form
- $("#actionForm").html("");
- //Generate the list of endpoints from the device data
- var device = $(object).parent().parent();
- var deviceData = device.attr("devicedata");
- deviceData = JSON.parse(decodeURIComponent(deviceData));
- var epts = deviceData.ControlEndpoints;
- if (epts.length == 0){
- //This device has no control endpoints
- }else{
- epts.forEach(ept => {
- //Check which type of ept is this. Accept {string, integer, float, bool, none}
- var encodedEptData = encodeURIComponent(JSON.stringify(ept));
- var deviceID = deviceData.DeviceUUID;
- var name = ept.Name;
- if (ept.Type == "string"){
- $("#actionForm").append(`<div name="${ept.Name}" devid="${deviceID}" epd="${encodedEptData}" class="field">
- <label>${ept.Desc}</label>
- <div class="ts action input">
- <input type="text" placeholder="${name}">
- <button class="ts primary icon button" title="Send" onclick="executeEndpoint(this.parentNode.parentNode, this.parentNode.parentNode.getElementsByTagName('input')[0].value)"><i class="send icon"></i></button>
- </div>
- </div>`);
- }else if (ept.Type == "integer"){
- var min = "";
- var max = "";
- if (ept.Min != undefined){
- min = ept.Min;
- }
- if (ept.Max != undefined){
- max = ept.Max;
- }
- $("#actionForm").append(`<div name="${ept.Name}" devid="${deviceID}" epd="${encodedEptData}" class="field">
- <label>${ept.Desc}</label>
- <div class="ts action input">
- <input type="number" min="${min}" max="${max}" placeholder="${name}">
- <button class="ts primary icon button" title="Send" onclick="executeEndpoint(this.parentNode.parentNode, this.parentNode.parentNode.getElementsByTagName('input')[0].value)"><i class="send icon"></i></button>
- </div>
- </div>`);
- }else if (ept.Type == "float"){
- var min = "";
- var max = "";
- var step = "0.1";
- if (ept.Min != undefined){
- min = ept.Min;
- }
- if (ept.Max != undefined){
- max = ept.Max;
- }
- if (ept.Steps != undefined){
- step = ept.Steps;
- }
- $("#actionForm").append(`<div name="${ept.Name}" devid="${deviceID}" epd="${encodedEptData}" class="field">
- <label>${ept.Desc}</label>
- <div class="ts action input">
- <input type="number" min="${min}" max="${max}" step="${step}" placeholder="${name}">
- <button class="ts primary icon button" onclick="executeEndpoint(this.parentNode.parentNode, this.parentNode.parentNode.getElementsByTagName('input')[0].value)" title="Send"><i class="send icon"></i></button>
- </div>
- </div>`);
- }else if (ept.Type == "bool"){
- $("#actionForm").append(`<div name="${ept.Name}" devid="${deviceID}" epd="${encodedEptData}" class="field">
- <div class="ts toggle checkbox">
- <input type="checkbox" id="${encodeURIComponent(ept.Name)}" onchange="executeEndpoint(this.parentNode.parentNode, this.value);">
- <label for="${encodeURIComponent(ept.Name)}">${ept.Name}</label>
- </div></div>`);
-
- }else if (ept.Type == "none"){
- //No action. (aka just a GET request endpoint)
- $("#actionForm").append(`<div devid="${deviceID}" epd="${encodedEptData}" class="field">
- <button class="ts info fluid button" title="${ept.Desc}" onclick="executeEndpoint(this.parentNode);">${name}</button>
- </div>`);
- }
- });
- //Get its status
- $.ajax({
- url: "../../../system/iot/status",
- data: {devid: deviceData.DeviceUUID},
- success: function(data){
- //Look for fields that have the same name. If not, append it to status field
- if (data.error !== undefined){
- $("#statusList").html(`<h3>Connection Lost</h3><br><p>${data.error}</p>`);
- }else{
- //OK! Append it
- $("#statusList").html("");
- for (var key in data) {
- var found = false;
- $("#actionForm").find(".field").each(function(){
- var thisName = $(this).attr("name");
- if (thisName == key){
- //Set its value
- var targetInput = $(this).find("input");
- if (targetInput.attr('type') == "checkbox"){
- //For handling checkbox
- if (data[key] == true){
- targetInput[0].checked = true;
- }else{
- targetInput[0].checked = false;
- }
- }else{
- //For handling other input fields
- $(this).find("input").val(data[key]);
- }
-
- found = true;
- }
- });
- if (found == false){
- //Append to status field
- $("#statusList").append(`<div class="ts header">
- ${data[key]}
- <div class="sub header"><i class="marker icon"></i> ${key}</div>
- </div>`);
- }
- }
- }
- }
- })
- }
- console.log(deviceData);
- $("#actioninterface").fadeIn('fast');
- }
- function updateIframeSize(){
- $("#controlUI").attr("width",$("#actionMainUI").width());
- $("#controlUI").attr("height",$("#actionMainUI").height());
- $("#controlUI").css("width",$("#actionMainUI").width());
- $("#controlUI").css("height",$("#actionMainUI").height());
- }
- $(window).on("resize",function(){
- updateIframeSize();
- });
- </script>
- </body>
- </html>
|