Perspective Chart Calculated Historical Tags

Hello,

I gave myself a home project to implement to get more experience with Perspective.

The project is to collect data from a website’s api and show it on a chart on my phone.

I chose to get weather info for my gps coordinates from OpenWeather and so I have a gateway event timer script configured to run every 10 minutes that gets the data and puts them into memory tags that I have enabled tag history on.

I then placed a Time Series Chart component on a screen and configured it to show a set of temperature tags (actual, apparent, minimum and maximum). I have these showing nicely on the chart.

The temperatures coming in are in Kelvin and i would like to have a radio group on the screen to switch between Kelvin, Celcius and Fahrenheit.

C = K - 273.15
F = (K - 273.15) × 9/5 + 32

How/where can I add calculated datasets such as these to my chart’s properties?

@dion.botha, that can be accomplished by adding a transform to your tag history binding. The transform will use the value from your radio button to apply the appropriate calculation to the dataset from tag history.

1 Like

Thanks Josh, this is what I came up with:

def transform(self, value, quality, timestamp):
	"""
	Transform the incoming value and return a result.

	Arguments:
		self: A reference to the component this binding is configured on.
		value: The incoming value from the binding or the previous transform.
		quality: The quality code of the incoming value.
		timestamp: The timestamp of the incoming value as a java.util.Date
	"""
	unit = self.getSibling("RadioGroup").props.value
	kelvin = value
	if unit == 1 or unit == 2:
		conversion = kelvin
		for row in range(conversion.getRowCount()):
			for col in range(1, conversion.getColumnCount()):
				if unit == 1: # celcius
					conversion = system.dataset.setValue(conversion, row, col, conversion.getValueAt(row, col) - 273.15)
				elif unit == 2: # fahrenheit
					conversion = system.dataset.setValue(conversion, row, col, (conversion.getValueAt(row, col) - 273.15) * 1.8 + 32)
		return conversion

Unfortunately the Fahrenheit conversion is a little off and I don’t understand why… Could it be a rounding error? Its also weird that when I replace 1.8 with (9/5) I get a completely different value…

Also, I have an onClick event configured on the radio group that simply refreshes. When I click a radio button on my mobile device, the page seems to refresh but the kelvin values are still showing… When I put the designer in preview mode and switch to either Celsius or Fahrenheit, the designer says Refresh action not allowed in the Designer but if I click into the charts tag history binding and then click OK, it shows the correct data (minus the Fahrenheit inaccuracies described above)…

Playing around, I see that whatever the designer radio button is selected when last I saved is what values are being shown on the chart regardless of whether or not I select a different radio button.

I think I am doing something wrong…

@dion.botha, you could enable Polling on the Tag history binding at some interval to update the bound Dataset. That’ll refresh just the chart data at whatever interval you choose:

I recreated your script and modified a couple things. To get the division of 9/5 to work correctly, you need to specify the numbers as floats (9.0/5.0). For the conversion to Fahrenheit, you’ve just got a logic issue in your formula (check my parenthesis below):

convertedData = value;
	unit = self.getSibling("RadioGroup").props.value;
	
	system.perspective.print("1.8: " + str(1.8)); # debug console stmt; can remove
	system.perspective.print("9.0/5.0: " + str(9.0/5.0)); # debug console stmt; can remove
		
	for row in range(value.getRowCount()):
		for col in range(1, value.getColumnCount()):
			if unit == "c": 
				convertedData = system.dataset.setValue(convertedData, row, col, (convertedData.getValueAt(row, col) - 273.15));
			elif unit == "f": 
				convertedData = system.dataset.setValue(convertedData, row, col, ((convertedData.getValueAt(row, col) - 273.15) * (9.0/5.0)) + 32);
	return convertedData;
1 Like

Thanks Josh, works like a charm.

For home projects, I have the luxury of time (no deadline) on my side. As such I am trying to do things with my home ‘Maker’ system the ‘best’ way I can think of, this translates to better abilities for my customers at work. For this application, polling works fine but I feel like it is better to refresh at the point when the units (radio group) are changed or if the browser page is refreshed by the user (please jump in if my thinking in this direction is flawed). Surely there is a way to refresh the chart when the user changes the radio group.

Also, is there a way to make the Tag History Binding’s properties dynamic? I would like to give the user the ability to switch between Realtime and Historical.

I could have 2 charts on top of each other (one for Realtime and one for Historical) and make a radio group selection hide and make visible the chart the user wants but this does not seem like the ‘best’ way to do things.

I have a example where I would like the value which is recorded in my history provider as Kelvin to be converted to Celcius which is what this thread is disucssing about however, the difference in my application is that I would like the binding type be "Expression" instead of "Tag History" since I would like to do indrection on my tag which I have selected.
The script applies for "Tag History" binding as the return value is a dataset, however if I use "Expression" binding is there a similar script which I could use on the transform when the return value is an 'expression' as well ?

You still want a tag history binding. You want the expression within that for the tag path.

You probably should use a transform to convert the unit.

1 Like

Is dynamic expression of a tag can be done using expression ?
Following throws a error ,

[HistorianDB/ignition-toc:default]mqtt tags/temp {../Dropdown.props.options[0].value}

Could you help with an example of how you can use indirection in the expression for tag history in perpective ?