Home Monitoring (home made) – Reborn

I’d previously shared on my blog the home made monitoring application I’d built to aggregate pv, meter and weather data – see: http://blog.v-s-f.co.uk/2014/03/home-monitoring-home-made-overview/.

Over the last few months I re-wrote the app to not only output the data to PVOutput every minute, but store that same data into an HSQLDB on my server. The new code base uses less Java than the previous version and moves a lot of the aggregation into Mule flows. I also took the opportunity to try out Git Hub, so the code is all available online here: https://github.com/vls29/aggregator

So far it’s been running very stable since the start of January and the refactoring enables new data sources to be added very quickly, e.g. Mains Voltage as can be seen below on the graph as a purple line starting above 3000W:

mains-voltage

(link to my system on PVOutput: http://pvoutput.org/intraday.jsp?id=4836&sid=4409)

Mule Enum in Flow – issue with enum of same name as variable

When creating a flow in Mule recently, I hit an issue that kept me scratching my head for a number of hours, so thought I’d share it…

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:servlet="http://www.mulesoft.org/schema/mule/servlet" xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
	xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.5.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
http://www.mulesoft.org/schema/mule/servlet http://www.mulesoft.org/schema/mule/servlet/current/mule-servlet.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">

    <flow name="input-data" doc:name="input-data">
        <composite-source doc:name="Composite Source">
            <vm:inbound-endpoint exchange-pattern="one-way" path="pvoutput-data" doc:name="vm-pvoutput-data"/>
            <servlet:inbound-endpoint path="/pvoutput-data" responseTimeout="10000" doc:name="servlet-pvoutput-data"/>
        </composite-source>
        <set-variable variableName="Received" value="#[new java.util.GregorianCalendar()]" doc:name="Received Date Time"/>
        <set-variable variableName="DataSource" value="#[DataSource.valueOf(message.inboundProperties['X-Data-Source'])]" doc:name="Source"/>
        <http:body-to-parameter-map-transformer doc:name="Body to Parameter Map"/>
        <logger message="#[message]" level="DEBUG" doc:name="Logger"/>
        <logger message="Received #[DataSource] Data: #[payload]" level="INFO" doc:name="Logger"/>
        <choice doc:name="Source Choice">
            <when expression="#[DataSource == DataSource.HOT_WATER]">
                <expression-transformer doc:name="Hot Water" expression="#[new HotWaterData(Received, payload);]" />
            </when>
            <when expression="#[DataSource == DataSource.WEATHER]">
                <expression-transformer doc:name="Weather" expression="#[new WeatherData(Received, payload);]" />
            </when>
            <when expression="#[DataSource == DataSource.INVERTER]">
                <expression-transformer doc:name="Inverter" expression="#[new GenerationData(Received, payload);]" />
            </when>
            <when expression="#[DataSource == DataSource.METER]">
                <expression-transformer doc:name="Meter" expression="#[new MeterData(Received, payload);]" />
            </when>
            <otherwise>
                <logger message="Unexpected Data Source Type: #[DataSource]" level="ERROR" doc:name="Logger"/>
            </otherwise>
        </choice>
        <vm:outbound-endpoint exchange-pattern="one-way" doc:name="combine-data" path="combine-data"/>
    </flow>
</mule>

(or in pictorial format)
aggregator

I’ve created a simple flow which receives a request on a servlet endpoint and then adds a variable depending on the source. The variable is named “DataSource”, but I also have an enum named DataSource which contains the following values:

package uk.co.vsf.aggregator.domain;

public enum DataSource {
	HOT_WATER,
	WEATHER,
	INVERTER,
	METER
	;
}

There’s also a Mule configuration block which has imports to a number of classes including the DataSource enum.

<configuration doc:name="Configuration">
		<expression-language autoResolveVariables="true">
			<import class="uk.co.vsf.aggregator.domain.DataSource"/>
			<import class="uk.co.vsf.aggregator.domain.HotWaterData"/>
			<import class="uk.co.vsf.aggregator.domain.WeatherData"/>
			<import class="uk.co.vsf.aggregator.domain.GenerationData"/>
			<import class="uk.co.vsf.aggregator.domain.MeterData"/>
			<import class="uk.co.vsf.aggregator.pvoutput.domain.AddStatusRequest"/>
			<import class="uk.co.vsf.aggregator.CalendarUtils"/>
			<import class="java.util.Calendar"/>
			<import class="java.util.GregorianCalendar"/>
		</expression-language>
	</configuration>

I’ve then written a simple test which calls the composite input vm with a set of values and a data source of Hot_Water. You’ll notice from the flow that after determining the data source, it logs out the message, so we can see the stored variable:

Message properties:
  INVOCATION scoped properties:
    DataSource=HOT_WATER
...

All ok at the moment…
Just below that log statement is another which prints out the DataSource, but this time we get:

Received class uk.co.vsf.aggregator.domain.DataSource Data: {t=40.56, i=10}

Not what I’d expected!
And after that log statement the data source is used to determine the route of the message being processed. I expect it to get transformed into a HotWaterData object, but instead the message goes to the else statement:

Unexpected Data Source Type: class uk.co.vsf.aggregator.domain.DataSource

Well… after much head scratching… it was as simple as renaming the variable to something other than the same name as the enum value! (DOH)

Now I get the results I’d expected:

Received HOT_WATER Data: {t=40.56, i=10}

And the returned object is an instance of HotWaterData.

Hope this helps someone else!