Running a script from html


(James) #1

I am using /etc/openhab2/html/ to serve webpages. I would like to know if I can run scripts from here. Is there a script alias setup to access /etc/openhab2/scripts or some other location? How do I configure this? If not, is there a way I can serve php from this html directory? Any server side scripting language will do.

The only way I have currently gotten around this is by creating a exec thing with a string item set to output and a switch item set to run. My javascript sets switch to ON, waits for status to change to OFF, then gets the value of the string.


(Rich Koshak) #2

I don’t think it is possible but I could be wrong. Hopefully, someone else will chime in. I do know OH uses Jetty for its web server and there are instructions for how to enable php and other CGI on Jetty, but how those translate to how Jetty is deployed in the Karaf console in OH.

However, I think the community would benefit if you posted how you made this work using your Items and JavaScript.


(James) #3

Sure. I made a working roku remote that I can insert as a iframe into habpanel. Works great on iPad and PC. The keyboard function uses the devices on-screen keyboard but keyboard does not work properly in android OS. This dynamically finds your roku(s) and finds the installed apps. Here is the screen shot.


exec.things file

Thing exec:command:getRokus [command="/etc/openhab2/scripts/searchRokus.py"]

roku.items file

String rokuCommand
String rokuDiscoveryResponse {channel="exec:command:getRokus:output"}
Switch discoverRokus {channel="exec:command:getRokus:run"}

roku.rules file

rule "Send Roku Command"
when
	Item rokuCommand received update
then
	sendHttpPostRequest(rokuCommand.state.toString)
	logInfo("Roku", rokuCommand.state.toString)
end

/etc/openhab2/scripts/searchRokus.py

#!/usr/bin/python

import sys
import socket
import re
import xml.etree.ElementTree as ET
import urllib2
import json

ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
        "HOST: 239.255.255.250:1900\r\n" + \
        "Man: \"ssdp:discover\"\r\n" + \
        "MX: 5\r\n" + \
        "ST: roku:ecp\r\n\r\n";
socket.setdefaulttimeout(8)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto(ssdpRequest, ("239.255.255.250", 1900))
response = "["
while True:
    try:
        name = "Unknown"
        model = "Unknown"
        privateListening = "Unknown"
        resp = sock.recv(1024)
        matchObj = re.match(r'.*USN: uuid:roku:ecp:([\w\d]{12}).*LOCATION: (http://.*/).*', resp, re.S)
        serialNumber = matchObj.group(1)
        address = matchObj.group(2)
        url = address + "query/device-info"
        tree = ET.parse(urllib2.urlopen(url))
        root = tree.getroot()
        name = root.find('user-device-name').text
        model = root.find('model-name').text
        privateListening = root.find('supports-private-listening').text
        url = address + "query/apps"
        tree = ET.parse(urllib2.urlopen(url))
        root = tree.getroot()
        response+='{"name": "' + str(name) + '", "model": "' + str(model) + '", "serial": "' + str(serialNumber) + '", "address": "' + str(address) + '", "privateListening": "' + str(privateListening) + '", "apps": ['
        for app in root.findall('app'):
        		appName = app.text
        		appId = app.get('id')
        		response+='{"appName": "' + str(appName) + '", "appId": "' + str(appId) + '"},'
        response= response[:-1]
        response+=']},'
        
    except socket.timeout:
        break
response= response[:-1]        
response+=']'
print response

/etc/openhab2/html/roku.html
(url: http://OpenHabIP:8080/static/roku.html)

<html>
	<head>
		<script src="javascript/jquery-3.2.1.min.js"></script>
		<script src="javascript/roku.js"></script>
		
		<link rel="stylesheet" href="style/bootstrap/css/bootstrap.min.css">
		<link rel="stylesheet" href="style/roku.css">
	</head>
	<body>
		<input id="hiddenBox" type="text" autocorrect="off"/>
		<div id="rokuControllerContainer">
			<div id="deviceSelectorContainer">
				<h3 style="color: white;">Roku Controller</h3>
    			<ul id="customRadio"></ul>
			</div>
			<div id="controlButtonsContainer">
				<div id='Backspace' class="control glyphicon glyphicon-arrow-left btn btn-default"></div>
				<div id='Home' class="control glyphicon glyphicon-home btn btn-default"></div></br>
				<div id='Up' class="control glyphicon glyphicon-menu-up btn btn-default"></div></br>
				<div id='Left' class="control glyphicon glyphicon-menu-left btn btn-default"></div>
				<div id='Select' class="control glyphicon glyphicon-ok-sign btn btn-default"></div>
				<div id='Right' class="control glyphicon glyphicon-menu-right btn btn-default"></div></br>
				<div id='Down' class="control glyphicon glyphicon-menu-down btn btn-default"></div></br>
				<div id='InstantReplay' class="control glyphicon glyphicon-repeat btn btn-default"></div>
				<div id='Info' class="control glyphicon btn btn-default"><div style="height:24px;width: 19.98px;line-height: 43px">*</div></div>
				<div id="keyboardAccess" class="btn btn-default">Keyboard</div></br>
				<div id='Rev' class="control glyphicon glyphicon-backward btn btn-default"></div>
				<div id='Play' class="control glyphicon glyphicon-play btn btn-default"></div>
				<div id='Fwd' class="control glyphicon glyphicon-forward btn btn-default"></div><br><br>
			</div>
			<div id="appsContainer"></div>
		</div>
		
	</body>
</html>

/etc/openhab2/html/javascript/roku.js

$(document).ready(function(){
	discoverRokus();
	//changes state of rokuCommand to the selected button
	$('.control').click(function () {;
	
	//when keyboard button is click then place cursor in textbox that is off screen to get on-screen keyboard on mobile devices to pop-up, when clicked again take cursor out of field
	$('#keyboardAccess').click(function () {;
	
	//captures keypresses in text box for keyboard input - This is know to not work properly in android devices
	$('#hiddenBox').keyup(function (e) {
		
		var keynum;
		var key;
		
		if(window.event) { // IE                    
			keynum = e.keyCode;
		} else if(e.which){ // Netscape/Firefox/Opera                   
			keynum = e.which;
		} 
		
		if (keynum == 13) {
			key = "ENTER";
		} else if(keynum == 8){
			key = "BACKSPACE";
		} else {
			var inBox = $('#hiddenBox').val();
			key = "LIT_" + inBox.substr(inBox.length - 1);
		}
		$.ajax({
			type       : "PUT",
			url        : "http://192.168.1.45:8080/rest/items/rokuCommand/state",
			data       : currentAddress + "keypress/" + key, 
			headers    : { "Content-Type": "text/plain" }
		});
	
	});
	
});
availableRokus = [];

function getState(item){
function setState( item ,txtNewState ){
function sendCommand( item , txtCommand ){
function discoverRokus() {
	console.log("Discovering Roku's");
	$('#customRadio').html('<span style="color: white;">Discovering Rokus</span>');
	//Turns this item on to start running script
	$.ajax({
		type       : "POST",
		url        : "http://192.168.1.45:8080/rest/items/discoverRokus",
		data       : "ON",
		headers    : { 'Content-Type': 'text/plain' }
	}).done( function(data){ 
		//while the state is ON (command is running) then do nothing
		while (getState('discoverRokus') == 'ON'){}
		$('#customRadio').html('');
		var counter = 0;
		//get JSON response and turn it into javascript object
		rokuDiscoveryResponse = getState('rokuDiscoveryResponse');
		rokusObject = JSON.parse(rokuDiscoveryResponse);
		$('#customRadio').html('');

		currentName = rokusObject[0]['name'];
		currentAddress = rokusObject[0]['address'];
		currentSerial = rokusObject[0]['serial'];
		currentPrivateListening = rokusObject[0]['privateListening'];
		currentModel = rokusObject[0]['model'];
		if (currentName == 'None') {
			currentName = 'Unknown';
		}
		var checked = "checked";
		for (var key in rokusObject) {
			if (rokusObject[key].name == 'None') {
			rokusObject[key].name = 'Unknown';
		}
			$('#customRadio').append('<li><input type="radio" id="option-' + key + '" name="selector" ' + checked + '/><label for="option-' + key + '">' + rokusObject[key].name + '</label></li>');
			checked = null;	
		}
		
		$('#customRadio li input[type=radio]').click(function () {
			var key = $("input[name='selector']:checked").attr('id');
			key = key.substr(key.length - 1);
			currentName = rokusObject[key]['name'];
			currentAddress = rokusObject[key]['address'];
			currentSerial = rokusObject[key]['serial'];
			currentPrivateListening = rokusObject[key]['privateListening'];
			currentModel = rokusObject[key]['model'];
			loadApps(key);
		});
		
		
		loadApps(0);
		

	}).fail( function(jqXHR, textStatus ){ 
		console.log( "Failure: " + textStatus );
	});

}
function loadApps(rokuKey) {
	$('#appsContainer').html("");
	for (var appKey in rokusObject[rokuKey].apps) {
			var currentAppId = rokusObject[rokuKey]['apps'][appKey].appId;
			var currentAppName = rokusObject[rokuKey]['apps'][appKey].appName;
			$('#appsContainer').append('<img alt="' + currentAppId + '" class="appIcon btn btn-default" src="' + currentAddress + 'query/icon/' + currentAppId + '"/>');		
				
	}
	
	$('.appIcon').click(function () {
		var appId = $(this).attr('alt');
		$.ajax({
			type       : "PUT",
			url        : "http://192.168.1.45:8080/rest/items/rokuCommand/state",
			data       : currentAddress + "launch/" + appId, 
			headers    : { "Content-Type": "text/plain" }
		});
	});
}

/etc/openhab2/html/style/roku.css

body{
	background-color: #456;
	text-align: center;
}
#rokuControllerContainer{
	text-align: center;
	width: 100%;
	height: 500px;

}
#deviceSelectorContainer{
	text-align: center;
}
#customRadio{
  list-style: none;
  position: relative;
  margin: 0 auto;
  padding: 0;
  height: 45px;
}
/*style untouched button*/
#customRadio li{
  color: #AAAAAA;
  display: inline-block;
  position: relative;
  height: 45px;
	background-color: gray;
  text-align: center;
  margin: 0 4px;
}
#customRadio li input[type=radio]{
  position: absolute;
  visibility: hidden;
}
#customRadio li label{
  display: block;
  position: relative;
  font-weight: 300;
  font-size: 12px;
  line-height: 45px;
  padding: 0 20px;
  margin: 0 auto;
  height: 45px;
  z-index: 9;
  cursor: pointer;
  -webkit-transition: all 0.25s linear;
  
}
/*Style hover over button*/
#customRadio li:hover label{
	
	color: #FFFFFF;
}
/*style selected button*/
input[type=radio]:checked ~ label{
  color: white;
  background-color: #0db9f0;
}
.glyphicon {
    font-size: 20px;
    margin: 3px;
    color: white;
}
#controlButtonsContainer{
	text-align: center;
}
.appIcon{
	width: 30%;
}
#appsContainer{
	height: 155px;
	overflow-y: scroll;
	width: 80%;
	margin: 0 auto;
	max-width: 450px;
}
.control{
	background-color: purple;
	border: 0;
	color: white;
}
.btn-default:hover{
	background-color: purple;
	border: 0;
}
#Up{
	margin-bottom: -5px;
	border-bottom: 0;
	border-bottom-left-radius: 0;
	border-bottom-right-radius: 0;
}
#Left{
	margin-right: -7px;
	border-right: 0;
	border-top-right-radius: 0;
	border-bottom-right-radius: 0;
}
#Select{
	border-radius: 0;
	border: initial;
}
#Right{
	margin-left: -7px;
	border-left: 0;
	border-top-left-radius: 0;
	border-bottom-left-radius: 0;
}
#Down{
	margin-top: -4px;
	border-top: 0;
	border-top-left-radius: 0;
	border-top-right-radius: 0;
}
#Info{
	font-family: Arial, Helvetica, sans-serif;
	font-size: 40px;
	overflow: hidden;
	width: 46px;
	height: 42px;
}
#keyboardAccess{
	border: 0;
	color: white;
	background-color: purple;
	position: relative;
	height: 42px;
	line-height: 31px;
}
#hiddenBox{
	height: 20px;
	width: 100px;
	position: absolute; 
	top: -25px;
}

custom habpanel widget html

<div>
    <iframe style="width: 100%;height: 600px;" src="/static/roku.html" frameBorder="0">      
    </iframe>
</div>

other files needed…

JQuery
/etc/openhab2/html/javascript/jquery-3.2.1.min.js

Bootstrap v3.3.7
I use fonts and css folder and copied them into /etc/openhab2/html/style/bootstrap/