Display charts graphics in tiles


(PPO16) #1

Hi there,

I struggled for a while to understand how to display a chart (bar graph or other charts) inside a tile. I checked on the forum but I never saw something straight forward like the below, so I am sharing it.

Basically, I solved that by referencing a php script as an icon url that runs on my server.
The php runs pChart which is a php charting library.

So the DTH always points the same picture while the content is updated by the server running the php.

Example of DTH tile:

standardTile("chart", "device.chart",  width: 6, height: 5,  canChangeIcon: false ) {
        state "default", label: 'my chart', icon: "http://192.168.1.49/chart.php"

Which leads to this:

The php code to generate that chart is simply:

<?php session_start(); include "./pChart/class/pDraw.class.php"; include "./pChart/class/pImage.class.php"; include "./pChart/class/pData.class.php"; /* Create your dataset object */ $myData = new pData;

/* Add data in your dataset */
$myData->addPoints(array(VOID, 3,4,3,5));

/* Create a pChart object and associate your dataset */
$myPicture = new pImage(700,230,$myData);

/* Define the boundaries of the graph area */
$myPicture->setGraphArea(60,40,670,190);

/* Choose a nice font */
$myPicture->setFontProperties(array(“FontName”=>"/usr/share/fonts/truetype/freefont/FreeSansBold.ttf",“FontSize”=>11));

/* Draw the scale, keep everything automatic */
$myPicture->drawScale();

/* Draw the scale, keep everything automatic */
$myPicture->drawSplineChart();

/* Build the PNG file and send it to the web browser */
$myPicture->Stroke();
?>

More about pChart on: http://www.pchart.net/

Have fun!


(Andreas A.) #2

You can achieve graphs inside a DTH tile without the need for an external server by using an htmlTile and dynamically setting the dataset for a chart created using Google chart (you can query ST for historical data of your device) - this is what I am doing for my solar monitoring DTH:


(PPO16) #3

Thanks Andreas, this looks great.
I would like to avoid google services for this and keep my local graph generation on my raspberry that runs locally on my network.
My raspberry is at 192.168.1.49

Based on your source, I am trying to do this:

htmlTile(name:"UGW_web",
                action: "getGraphHTML",
                refreshInterval: 10,
                width: 6,
                height: 4, 
                whitelist: ["192.168.1.49"])

To make a test, I put a snow.gif image on my raspberry which I can access from my browser.

To get this gif displayed, I modified your source:

def getGraphHTML() {
	def html = """
		<!DOCTYPE html>
			<html>
				<head>
					<meta http-equiv="cache-control" content="max-age=0"/>
					<meta http-equiv="cache-control" content="no-cache"/>
					<meta http-equiv="expires" content="0"/>
					<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"/>
					<meta http-equiv="pragma" content="no-cache"/>
					<meta name="viewport" content="width = device-width">
					<meta name="viewport" content="initial-scale = 1.0, user-scalable=no">
				</head>
				<body>
					
                    <img src="http://192.168.1.49/snow.gif" alt="Snow icon" height="42" width="42"> 
 
                    
				</body>
			</html>
		"""
	render contentType: "text/html", data: html, status: 200}

The behavior on Android 6.0.1: the tile keeps a spinning icon
The behavior on iOS: it displays {“error”:“true”, “type”:“SmartAppException”,“message”:“Not found”}

I have no idea what is not found. Do I have to setup something additional to get the htmlTile working?

Thanks for your help


(Andreas A.) #4

My DTH doesn’t send any data to Google - it only loads the JavaScript from Google servers but then adds the date sets locally (i.e., Google never sees them).

I am pretty sure that anything shown in a htmlTile needs to be reachable by the ST servers so that they can then serve the data to your device(s).


(PPO16) #5

I see…
Ok, I’ll switch to your setup then.

Thanks a lot!


(PPO16) #6

hmm…

I am still having the same issue… I have an icon spinning instead of a graph (even empty). Do you have any idea?

Here is the code I have now:

same as yours:

htmlTile(name:"graphHTML",
  	action: "getGraphHTML",
  	refreshInterval: 1,
  	width: 6,
  	height: 4,
  	whitelist: ["www.gstatic.com"])

Same as yours:

 mappings {
 	path("/getGraphHTML") {action: [GET: "getGraphHTML"]}
 }

Stubbed the getStartTime and getDataString

String getDataString(Integer seriesIndex) {
 	def dataString = "2,3,5,7,10"
 	return dataString
 }


def getStartTime() {
	def startTime = 24
	
	return startTime
}

Same as yours:

def getGraphHTML() {
	def html = """
		<!DOCTYPE html>
			<html>
				<head>
					<meta http-equiv="cache-control" content="max-age=0"/>
					<meta http-equiv="cache-control" content="no-cache"/>
					<meta http-equiv="expires" content="0"/>
					<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT"/>
					<meta http-equiv="pragma" content="no-cache"/>
					<meta name="viewport" content="width = device-width">
					<meta name="viewport" content="initial-scale = 1.0, user-scalable=no">
					<style type="text/css">body,div {margin:0;padding:0}</style>
					<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
					<script type="text/javascript">
						google.charts.load('current', {packages: ['corechart']});
						google.charts.setOnLoadCallback(drawGraph);
						function drawGraph() {
							var data = new google.visualization.DataTable();
							data.addColumn('timeofday', 'time');
							data.addColumn('number', 'Energy (Yesterday)');
							data.addColumn('number', 'Power (Yesterday)');
							data.addColumn('number', 'Energy (Today)');
							data.addColumn('number', 'Power (Today)');
							data.addRows([
								${getDataString(1)}
								${getDataString(2)}
								${getDataString(3)}
								${getDataString(4)}
							]);
							var options = {
								fontName: 'San Francisco, Roboto, Arial',
								height: 240,
								hAxis: {
									format: 'H:mm',
									minValue: [${getStartTime()},0,0],
									slantedText: false
								},
								series: {
									0: {targetAxisIndex: 1, color: '#FFC2C2', lineWidth: 1},
									1: {targetAxisIndex: 0, color: '#D1DFFF', lineWidth: 1},
									2: {targetAxisIndex: 1, color: '#FF0000'},
									3: {targetAxisIndex: 0, color: '#004CFF'}
								},
								vAxes: {
									0: {
										title: 'Power (W)',
										format: 'decimal',
										textStyle: {color: '#004CFF'},
										titleTextStyle: {color: '#004CFF'}
									},
									1: {
										title: 'Energy (kWh)',
										format: 'decimal',
										textStyle: {color: '#FF0000'},
										titleTextStyle: {color: '#FF0000'}
									}
								},
								legend: {
									position: 'none'
								},
								chartArea: {
									width: '72%',
									height: '85%'
								}
							};
							var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
							chart.draw(data, options);
						}
					</script>
				</head>
				<body>
					<div id="chart_div"></div>
				</body>
			</html>
		"""
	render contentType: "text/html", data: html, status: 200
}

(Andreas A.) #7

Did you try running in the simulator? That way you can look at the HTML and see whether there is something wrong with it.


(PPO16) #9

Just did and learn it ha…

I can see the html code is populated with the stubbed values as addRows and minValue I made for the getStartTime and getDataString

But still, nothing is displayed in the window and nothing visible in the console either.

Do you have to setup something to enable the undocumented htmlTile ?


(PPO16) #10

Hey got some progress… In order to avoid running into my lack of knowledge in google stuff, I get back to a very simple html content that just displays my chart.php.

I am now getting it working in the simulator but it doesn’t work in the mobile app.
I know you said they might need to access form their servers but it looks like the simulator is accessing my picture through their servers already based on the URL so I believe it should work.
And also, my original post showed that an icon url can use a local address.

But still, the mobile app keeps the icon spinning.


(Andreas A.) #11

Does your HTML validate?


(PPO16) #12

Not sure I understand your question.

On the simulator, the html read by the simulator window is what I expected.
But on mobile, I have no way to see it.
I did browse the simulator URL from my mobile browser and after being authenticated on ST IDE, I could see the same as in the simulator on my PC.
So something is not working via the app.

BTW, are you on Android or iPhone?


(Andreas A.) #13

If you copy the source from the simulator into an HTML validator - does it validate as correct HTML?

I’m using iOS but people are using the handler with Android as well. Also, the NST Manager uses htmlTiles with graphs and they work on both, Android and iOS.

Also, try to have the htmlTile in your DTH as early as possible - apparently there are some bugs when showing some other tiles before it.


(PPO16) #14

Very new interesting thing: in fact now the spinning icon disappeared (I left my phone for a while, doing other things). Then now the tile is blank, but while taking a snapshot of it, I could see as a blink the right content, then the tile became blank again.

BTW, this is the same behavior using your DTH (I don’t have the physical device to work it with so I just installed it and left the configuration blank).


(Andreas A.) #15

Maybe they broke things again with their latest app update on Android? It seems that they are getting really good at breaking two things for every one they fix these days…


(PPO16) #16

Just confirmed with an iOS owner sharing my device: she can see the html content despite the screen snapshot cannot capture it…

Anyway, filled a bug report to ST team


#17

When viewing any of the NST Devices in Things on Android, the HTML content will load the first time you view the device. If you exit out of the device and open it again, the HTML content will not reload. This is an issue with the Android OS according to tonesto. Not sure if the HTML issue above might share some if the same relationship with reloading the HTML content. Furthermore, if I force stop SmartThings App and then go back into any of my Nest devices, it will then load the content the first time again. Just FYI around Android.


(PPO16) #18

Yes. HTML is very simple so no error.

I don’t know NST/NEST sources. I didn’t find them in the public repo. Any link you can share?

This helps indeed to get rid of the spinning icon phase on my Android but still no display. I had again a “flash” display of my content but then it goes away.

def getGraphHTML() {

renderHTML() {
        head {
           """
        """ 
        }
        body {
        """
            <img src="http://192.168.1.49/chart.php" >
        """
        }
	}


}

Here are the 2 screens iOS vs Android with the htmlTile at first.


(PPO16) #19

You are correct. This is the same issue:

I illustrated it on Android by having 2 times the same htmlTile id in the details list:
details(["GraphHTML","GraphHTML","iaqlevel",...
On first publish and DTH view, only the 1st occurrence has the spinning icon and remain blanks.
The second one displays properly at once.
But then going back and forth, the second also becomes blank.
Then adding a 3rd instance and publishing:
details(["GraphHTML","GraphHTML","GraphHTML","iaqlevel",...
then the 3rd one displays correctly then stops working as the 2 previous ones.

So something is very wrong and that’s not the code of the DTH.


#20

This is a quote from @tonesto about the issue:

“The android client removed it’s current url document path so that’s why the page doesn’t reload html content.”

According to him this is eventually supposed to be resolved in a future release of Android.


#21

Meant @tonesto7 (He’s the developer for NST Manager)