technpolhttps://technpol.wordpress.com
Some technology, some politics, and some of whatever else I likeThu, 22 Jun 2017 19:30:00 +0000enhourly1http://wordpress.com/https://s2.wp.com/i/buttonw-com.pngtechnpolhttps://technpol.wordpress.com
Openhab Heating Configurationhttps://technpol.wordpress.com/2016/04/10/openhab-heating-configuration/
https://technpol.wordpress.com/2016/04/10/openhab-heating-configuration/#commentsSun, 10 Apr 2016 06:39:23 +0000http://technpol.wordpress.com/?p=1263Continue reading →]]>This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house. Refer to the index here.

In this post I cover a detailed configuration of Openhab for heating purposes. We create the rule sets to allow us to have an arbitrary number of zones, with each zone having 4 setpoints at configurable times during the day. The zones push those setpoints down to the devices in the zone. We allow people to change the temperature in a zone using the wall thermostat, but override again at the next timed change.

We also control the running of the boiler based on how many valves are open – this is to avoid the boiler short cycling when there are very few valves or valves only partly open. We’ll cover this in more detail when we get to the relevant rules.

We create a sitemap that gives us access to most of this information.

Let’s start with the items configuration. This creates all the groups necessary for the rules to interact with zones and devices generically, rather than any of the rules knowing about specific zones. This means we can add or remove zones, and change which devices are in which zones, without changing the rules.

We still need to define each zone and each device individually in here, but in general we only need to do that here and in the sitemap.

Create a file /etc/openhab/configurations/items/heating.items. Include the below content in the file.

Next we want to configure persistence – we want the settings that we create to be stored. We’ll use the rrd4j engine, as this is a simple file based service. You could choose instead to use a database if you have one available.

sudo aptitude install openhab-addon-persistence-rrd4j

Edit /etc/openhab/configurations/openhab.cfg to include the following block to tell openhab we want to use rrd4j (include this towards the bottom of the general configurations):

# The name of the default persistence service to use
persistence:default=rrd4j

Create /etc/openhab/configurations/persistence/rrd4j.persist, which tells openhab which of our values we want to persist when we reboot, or alternatively which we want it to keep track of so that we can graph them at a later time if we wish. Content as follows:

Next we’re into the rules to tie all this together. Let’s start with initialisation of all the important values to some sort of sensible default. The initialisation rules will set these values on startup, unless they’ve already been restored from the persistence service to something useful.

It’s important to default, because elements such as setpoints can’t be edited until they have a value in them.

Create a file /etc/openhab/configurations/rules/initialisation.rules, with the following content:

Once saved, you should see your openhab automatically run this and the values default within your openhab UI.

Next, we need some rules to handle the UI time entry within zones. When people move the setpoint up or down we want it to treat the value as if it were hours and minutes – so it should wrap around at 60 minutes to the next hour.

Then we’ll build the rules that look at the settings on the zone(s), and decide what the current setpoint should be. Rather than trying to work out when someone has changed something (which has a bit of performance impact on the UI), we’ll just check these settings every minute at 5 seconds past the minute.

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.core.library.types.DecimalType
import org.joda.time.*
/*
These rules check the current time of day and the time of day settings on each zone, and work
out what the current setpoint should be. The rules are scheduled to run every minute - the resolution
of the setting times can only be up to 15 minute intervals, but you could change a setting and
want it to apply immediately, so we run more frequently
*/
/*
This function calculates the correct temp for a given zone, and only changes that
setpoint if it's different than what's already set (to avoid needlessly cascading changes, which
would override any temporary settings made via a wall thermostat).
If the zone is turned off, it sets the temp to 5
*/
val org.eclipse.xtext.xbase.lib.Functions$Function1 setZoneSetpoint = [
org.openhab.core.items.GroupItem zone |
var int currentHours = now().getHourOfDay()
var int currentMinutes = now().getMinuteOfHour()
var int currentTime = currentHours * 100 + currentMinutes
var org.openhab.core.items.GroupItem settings = zone.members.filter( m | m.name.startsWith('zoneSettings')).last
var org.openhab.core.items.GroupItem times = settings.members.filter( m | m.name.startsWith('zoneSettingsTimes')).last
/* we use the setpoint from the highest time that is less than the current time. If there isn't one less than current time,
then we use the last setpoint, which should be the night setpoint. We assume settings are in time order, if someone
sets time1 to be higher than time2, then this will break */
var org.openhab.core.items.GroupItem lastTime = times.members.last
var int setpointNumber = 0
times.members.forEach( aTime | {
var int time = (aTime.state as DecimalType).intValue
if( time <= currentTime ) {
setpointNumber = setpointNumber + 1
lastTime = aTime
}
})
/* night setpoint when early hours of morning */
if( setpointNumber == 0 ){
setpointNumber = 4
}
var org.openhab.core.items.GroupItem setPoints = settings.members.filter( m | m.name.startsWith('zoneSettingsSetpoints')).last
var int newSetpoint = ( setPoints.members.filter( m | m.name.startsWith('set' + setpointNumber)).last.state as DecimalType )
var org.openhab.core.library.items.NumberItem currentSetpoint = settings.members.filter( m | m.name.startsWith('setCurrent')).last
if( settings.members.filter( m | m.name.startsWith('sw')).last.state == OFF ){
newSetpoint = 10 // set the valve to 10 degrees, which we treat as effectively off
}
logDebug( 'zones', 'Calculated setpoint for zone ' + zone.name + ' is setpointNumber ' + setpointNumber + ' with value of ' + newSetpoint + ', old setpoint was ' + currentSetpoint.state )
if( currentSetpoint.state == Uninitialized || newSetpoint != (currentSetpoint.state as DecimalType) ) {
postUpdate( currentSetpoint, newSetpoint )
}
]
rule "Roll current zone setpoints down from timed settings"
when
Time cron "5 * * * * ?"
then
logDebug( 'zones', 'Running zone settings' )
Zones?.members.forEach( zone | {
setZoneSetpoint.apply( zone )
})
end

You should see your zone settings applied to the current setpoint every minute.

Next, we want to take the zone setpoint and apply it to the device setpoints. We want to do this only when the zone setpoint changes – then if someone has manually overridden the temp on one of the devices it’ll only return to the programmed value at the next timed setting change, rather than at the next minute.

You should now see your devices starting to inherit the setpoint from the zone. Note that there is sometimes a lag for the various devices to update, particularly if you have a lot of devices.

Finally, we want the rules that control the boiler pump. These rules decide when to turn the boiler on and off. Create a file /etc/openhab/configurations/rules/pump_timers.rules:

import org.openhab.core.library.types.*
import org.openhab.core.library.items.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.core.library.types.DecimalType
import org.joda.time.*
import java.util.ArrayList
var org.openhab.model.script.actions.Timer pumpTimer
/*
This set of rules notices when a valve opening has changed, and manages the timers
for running the boiler pump appropriately.
The logic is that when there are only a few valves open, and those valves open only a small
amount, then we don't actually want to run the boiler until hot water returns - we want our
heaters to get a smallish amount of hot water, then wait while that heat percolates into the
room.
When there is a reasonable amount of valve opening, then we probably want to just run the boiler
till all the heaters demanding heat are hot.
Firstly, let's deal with changes to valve openings. Any time a valve opening changes, we need
to evaluate our state.
- If the aggregate valve opening is greater than the autoRunThreshold, then set mode to ON, and exit
- If the aggregate valve opening is zero, then we set mode to OFF, and exit
- If the mode is WAIT, do nothing - we'll re-evaluate when the wait timer finishes.
- If the mode is RUN, do nothing, we'll pick it up in the next run cycle.
- If the mode is something else, then set it to RUN. Something else could mean OFF or ON, or could
mean undefined
Next, the timer ends.
- If the timer ends and the mode was WAIT, then set mode to RUN
- If the timer ends and the mode was RUN, then set mode to WAIT
When the mode changes to ON, cancel any timer that is running, set the pump to ON
When the mode changes to OFF, cancel any timer that is running, set the pump to OFF
When the mode changes to WAIT, cancel any timer that is running (log a warning, as there shouldn't
be one), and set a WAIT timer for the specified wait seconds.
When the mode changes to RUN, cancel any timer that is running (log a warning, as there shouldn't
be one) and set a RUN timer for the desired run seconds.
The pump run time is based on a configured minimum run time (in theory, about filling the pipes with hot
water) plus how many valves are open / how much they are open times the pump run factor.
The pump wait time is a constant from the configuration.
*/
rule "Adjust timers whenever the amount of valve opening changes"
when
Item DeviceValves changed
then
logDebug( 'pump', 'Valve opening changed, deciding what to do')
if( ( DeviceValves.state as DecimalType ).intValue == 0 ) {
postUpdate( stringPumpMode, "OFF" )
logDebug( 'pump', 'No valves open, turning pump OFF')
}
else if( ( DeviceValves.state as DecimalType ).intValue >= ( numberPumpAutoRunThreshold.state as DecimalType ).intValue ) {
postUpdate( stringPumpMode, "ON" )
logDebug( 'pump', 'Valves greater than threshold, turning pump ON')
}
else if ( stringPumpMode.state == "WAIT" ) {
logDebug( 'pump', 'Already waiting, do nothing, valve position will be taken into account on next run')
}
else if ( stringPumpMode.state == "RUN" ) {
logDebug( 'pump', 'Already running, do nothing, valve position will be taken into account on next run')
}
else {
logDebug( 'pump', 'Pump state was ON, OFF or undefined, change to RUN')
postUpdate( stringPumpMode, "RUN" )
}
end
rule "Pump mode changed to OFF"
when
Item stringPumpMode changed to "OFF"
then
logDebug( 'pump', 'Mode changed to OFF')
if( pumpTimer != null ){
pumpTimer.cancel()
pumpTimer = null
logDebug( 'pump', 'Timer was present, cancelled it')
}
postUpdate( swPump, OFF )
logDebug( 'pump', 'Pump turned OFF')
end
rule "Pump mode changed to ON"
when
Item stringPumpMode changed to "ON"
then
logDebug( 'pump', 'Mode changed to ON')
if( pumpTimer != null ){
pumpTimer.cancel()
pumpTimer = null
logDebug( 'pump', 'Timer was present, cancelled it')
}
postUpdate( swPump, ON )
logDebug( 'pump', 'Pump turned ON')
end
rule "Pump mode changed to WAIT"
when
Item stringPumpMode changed to "WAIT"
then
logDebug( 'pump', 'Mode changed to WAIT')
if( pumpTimer != null ){
pumpTimer.cancel()
pumpTimer = null
logDebug( 'pump', 'Timer was present, cancelled it')
}
if( swPump.state == ON ){
postUpdate( swPump, OFF )
logDebug( 'pump', 'Pump was on, turned it off')
}
var int pumpWaitSeconds = (numberPumpWaitSeconds.state as DecimalType).intValue
postUpdate( stringTimerEnd, now().plusSeconds( pumpWaitSeconds ).toString('H:m:s') )
pumpTimer = createTimer( now().plusSeconds( pumpWaitSeconds ) ) [ | {
logDebug( 'pump', 'End of pump wait timer')
postUpdate( stringPumpMode, "RUN" )
logDebug( 'pump', 'Set mode to RUN')
}]
end
rule "Pump mode changed to RUN"
when
Item stringPumpMode changed to "RUN"
then
logDebug( 'pump', 'Mode changed to RUN')
if( pumpTimer != null ){
pumpTimer.cancel()
pumpTimer = null
logDebug( 'pump', 'Timer was present, cancelled it')
}
var int pumpRunSeconds = ( numberPumpRunBaseSeconds.state as DecimalType ).intValue + ( ( DeviceValves.state as DecimalType ).intValue * ( numberPumpRunFactor.state as DecimalType).intValue ) / 100
postUpdate( stringTimerEnd, now().plusSeconds( pumpRunSeconds ).toString('H:m:s') )
pumpTimer = createTimer( now().plusSeconds( pumpRunSeconds ) ) [ | {
logDebug( 'pump', 'End of pump run timer')
postUpdate( stringPumpMode, "WAIT" )
logDebug( 'pump', 'Set mode to WAIT')
}]
end

Finally, we should add configurables to the logging subsystem to allow us to individually debug each of our rules. In the example below we’ve set the pump rules to debug, all other rules to info. Edit /etc/openhab/logback.xml to add the following blocks:

And that should be it for the rule sets.

You should be able to go to the settings within the UI, and manually change the valve opening for the Master Bedroom Valve, which in turn should turn the pump on and off.

]]>https://technpol.wordpress.com/2016/04/10/openhab-heating-configuration/feed/2paullambert1Configuration of MAXCUL and CUL Donglehttps://technpol.wordpress.com/2016/04/09/configuration-of-maxcul-and-cul-dongle/
https://technpol.wordpress.com/2016/04/09/configuration-of-maxcul-and-cul-dongle/#commentsSat, 09 Apr 2016 06:30:20 +0000http://technpol.wordpress.com/?p=1135Continue reading →]]>This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house. Refer to the index here.

In this post I cover the installation of the firmware for the CUL dongle (culfw), the programming of the dongle to work with your raspberry pi, and configuration of the maxcul binding for Openhab.

At the end of this tutorial you should have one wall thermostat and one radiator valve paired to your raspberry pi via the CUL dongle.

The first thing to do is to obtain the CUL firmware. This downloads from culfw.de:

Next, plug your CUL stick into your raspberry pi, using a pin or other implement to hold in the small program button on the bottom of it. The green LED should not be flashing.

Then install the firmware using the supplied program (use the appropriate version – my stick is a v3):

cd culfw-1.66
cd Devices/CUL
sudo make usbprogram_v3

Unplug and replug your usb stick, and the green led should be flashing, and you should have a device at /dev/ttyACM0.

ls -l /dev/ttyACM0

The device should have a group owner of dialout. (Note – this section is partly from memory, I flashed my stick earlier, and it doesn’t seem to want to flash again. I recall a lot of pain in this area….sorry).

Add the openhab user to the dialout group so that they can interact with the device.

sudo usermod openhab -a -Gdialout

Next, you want to install the maxcul binding for openhab.

aptitude install openhab-addon-binding-maxcul openhab-addon-io-cul

Create some configuration for the maxcul binding in /etc/openhab/configurations/openhab.cfg:

#######################################################################################
##### General configurations #####
#######################################################################################
# Configuration folders (must exist as a subdirectory of "configurations"; the value
# tells the number of seconds for the next scan of the directory for changes. A
# value of -1 deactivates the scan).
# A comma separated list can follow after the refresh value. This list defines a filter
# for valid file extensions for the models.
folder:items=10,items
folder:sitemaps=10,sitemap
folder:rules=10,rules
folder:scripts=10,script
folder:persistence=10,persist
#######################################################################################
##### Binding configurations #####
#######################################################################################
################################ Max!CUL Binding###########################################
# set the device of the CUL device
maxcul:device=serial:/dev/ttyACM0
# set the refresh interval
maxcul:refreshInterval=60000
# set timezone you want the units to be set to - default is Europe/London
maxcul:timezone=Pacific/Auckland

Modify the logging configuration in /etc/openhab/logback.xml, adding the following block after the eventfile appender:

Also change the loglevel on maxcul to debug so we can see what’s going on, do that by adding a block:

^M
^M
^M

Create a basic items file in /etc/openhab/configurations/items/heating.items, we’re just going to have our thermostat, our wall switch, and switches to turn on pairing and monitoring of the network traffic on the CUL dongle. We’re creating the placeholders for all the information from the valve and wall thermostat, but won’t put the id onto each until we’ve paired the valve and thermostat.

Put the batteries into your wall thermostat, and hold in the boost button to pair with openhab. You should see a 30 second timer appear on the screen. Look in /var/log/openhab/maxcul.log, and you should see an error message along the lines of:

Unable to find configuration for serial MEQ0856945. Do you have a binding for it?

Edit your heating.items file to replace the TBD for the wall thermostat with MEQ0856945 on each of the wall thermostat items, for example:

Toggle the pairing switch again, and again hold in the boost button to trigger pairing. When you look in the maxcul.log you should see the device successfully pairing, and you should receive a temperature in the wall thermostat temperature, and you should be able to directly change the setpoint in openhab with it reflecting (after a short delay) on the wall thermostat.

Next we want to pair a valve. The process is quite similar. Hold in the boost button on the valve, and flick the pairing switch in the openhab ui. Again copy the device name, and add it to the valve configurations in heating.items. Pair again, and look to see the settings update in the UI (again there’ll be a bit of a lag).

Finally, we’ll associate the wall thermostat with the valve, so that changes to the wall thermostat update the valve setting. Edit the valve setpoint line to create an association with the wall thermostat, also adding in a specification that we’re using feature=thermostat, as using default doesn’t seem to work with an association:

Now you should see that changes to the setpoint on the wall thermostat ripple through to the setting on the valve.

]]>https://technpol.wordpress.com/2016/04/09/configuration-of-maxcul-and-cul-dongle/feed/40paullambert1Hardware Overviewhttps://technpol.wordpress.com/2016/04/09/hardware-overview/
https://technpol.wordpress.com/2016/04/09/hardware-overview/#commentsSat, 09 Apr 2016 03:12:24 +0000http://technpol.wordpress.com/?p=1099Continue reading →]]>This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house. Refer to the index here.

In this post I cover the hardware I’ve chosen and how I purchased it.

Firstly, I chose to use a raspberry pi 3 model B, which provides bluetooth, wifi, a 64-bit 4 core CPU and 1GB of RAM. I think this is the most future proof pi model around at the moment, and it’s not a lot of money.

Whilst I was at it I also bought a 2 relay board from the pi shop – an RPI-RELAY-2. The opensprinkler will provide a power supply, and in the meantime I had a supply available from my older pi model B.

I got a 16GB micro-SD card off the web. The main thing here is to check what speed it is – you want class 10 if possible. I got some jumper cables (40 x 1P Dupont Jumper Wire 20cm Female to Female) to connect the relay board to the GPIO pins on the raspberry pi.

Next, the equipment to connect to the radiator valves. I wanted a the CUL dongle from busware, but they didn’t ship to my location. I resolved this by registering with mailboxde.com, who provide a remailing service from Germany and cost me about $5 for this package.

The radiator valves I bought from conrad.com. You need to have thermostatic radiator heads already (I didn’t so needed to replace them all), you then remove the manual thermostatic head and replace with the EQ-3 valve. These shipped direct to me, as did the wall thermostats. I didn’t buy the MAX controller, as the Raspberry Pi will control all that (given enough fiddling).

Finally, I bought the opensprinker board from Ray’s Hobbies. You may also need a 24 volt AC power supply (I already had one).

]]>https://technpol.wordpress.com/2016/04/09/hardware-overview/feed/1paullambert1Openhab Architecture Overviewhttps://technpol.wordpress.com/2016/04/09/openhab-architecture-overview/
https://technpol.wordpress.com/2016/04/09/openhab-architecture-overview/#commentsSat, 09 Apr 2016 02:53:24 +0000http://technpol.wordpress.com/?p=1082Continue reading →]]>This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house. Refer to the index here.

In this post we describe the overall architecture we’re trying to achieve for the heating and watering system, and how the components interact.

The aim is to have a set of automatic radiator valves, with each valve knowing it’s current setpoint. This setpoint is changed during the day based on the zone that particular valve is in, and the settings I’ve made for each zone. We control the boiler so that it only turns on if valves are open, and we control the boiler runtime when there are only a few valves open.

The core of the system is a raspberry pi running linux and an open source home automation server called openhab.

Openhab in turn is using an 868MHz radio dongle (known as a CUL) to communicate to a set of wireless radiator valves throughout the house. The radiator valves are Max! EQ-3 valves, and we also have wireless wall thermostats to allow a degree of manual control over the system.

Openhab communicates with the boiler through two raspberry pi relays, controlled through GPIO pins. These relays open and close valves to the heating loop and turn the boiler on and off.

We also use an opensprinkler board to control our sprinklers. This board also powers the raspberry pi. The opensprinkler board again is controlled by openhab.

]]>https://technpol.wordpress.com/2016/04/09/openhab-architecture-overview/feed/1paullambert1Installing Openhab on Pihttps://technpol.wordpress.com/2016/04/09/installing-openhab-on-pi/
https://technpol.wordpress.com/2016/04/09/installing-openhab-on-pi/#commentsSat, 09 Apr 2016 02:42:12 +0000http://technpol.wordpress.com/?p=1018Continue reading →]]>This tutorial is a section of my wider series on creating a home automation solution for heating and watering in my house. Refer to the index here.

In this post we install a new Raspberry Pi from scratch, and get OpenHab running on it. We choose to use Wifi, and we install it headless (no GUI and no monitor). We install by connecting the card reader to a linux machine, which gives us access to the file system as we build it.

I bought a new Raspberry Pi 3. I’m choosing to run Raspbian on that, and for a variety of reasons I’m preferring to run headless (most importantly, because this Raspberry Pi will typically have no monitor at all).

We start by downloading the raspbian lite version and copy it onto our memory card using the instructions at raspberrypi.org. In my case the memory card was on /dev/sdi, and at the conclusion of that copy I have two partitions – /dev/sdi1 at 60MB and /dev/sdi2 at 1.2G.

In my case I had a 16GB memory card, and the lite version is a 2GB disk image – we need to resize the partition table so that /dev/sdi2 uses the remainder of the card otherwise we’re wasting space. We follow the instructions from geekpeek to do this. We start by listing the current partitions, and taking note of the start sector for /dev/sdi2

sudo fdisk -l /dev/sdi

In my case that partition starts at sector 131072. We then run fdisk proper and delete the partition, recreating it with a larger size:

Since we have a pi3 we want to use the wireless network rather than the wired network. We want to configure the wireless network before we put the card into our pi and boot it, so that it will come up straight away on the network.

Then check the webpage at http://raspberrypi2:8080/ (use your machine name if you chose a different hostname for your raspberry pi, and note that this assumes your wireless router automatically gives your machine the correct hostname on your local network, you may need to find and use the ip address instead).

You should see an openhab error page telling you that you have no default sitemap.

We can check the logs in /var/log/syslog, and /var/log/openhab/* if we’re getting problems.

]]>https://technpol.wordpress.com/2016/04/09/installing-openhab-on-pi/feed/1paullambert1Using Pi and OpenHab to control radiators and wateringhttps://technpol.wordpress.com/2016/04/09/using-pi-and-openhab-to-control-radiators-and-watering/
https://technpol.wordpress.com/2016/04/09/using-pi-and-openhab-to-control-radiators-and-watering/#commentsSat, 09 Apr 2016 01:58:55 +0000http://technpol.wordpress.com/?p=1004Continue reading →]]>Our house has hydronic radiator heating, we also have a watering system and other equipment. I wanted to use a Raspberry Pi to control the heating, as our radiators previously had manual valves. I also wanted to control the garden watering system whilst I was at it.

This tutorial series will cover the process of installing and configuring the software to achieve this, with topics being:

]]>https://technpol.wordpress.com/2016/04/09/using-pi-and-openhab-to-control-radiators-and-watering/feed/5paullambert1Exporting playlists from mythmusichttps://technpol.wordpress.com/2016/02/26/exporting-playlists-from-mythmusic/
https://technpol.wordpress.com/2016/02/26/exporting-playlists-from-mythmusic/#respondFri, 26 Feb 2016 07:25:38 +0000http://technpol.wordpress.com/?p=991Continue reading →]]>In my new house I don’t have any free to air TV – reception is too poor. So my mythtv installation is less useful than it could be – it’s primarily a setup that records TV. It also plays music, but it’s not inspiring at it.

My frontend died and needed replacing, and after fighting for a while I couldn’t get LIRC/remote controls going with the new hardware. I looked around and Kodi (an evolution of XBMC) looks to have a really good remote app that goes on my iPhone. Way better.

I’ve installed Kodi and it’s working well after some fiddling around. But I had a lot of music playlists in mythtv. I want them in Kodi. Kodi can import standard m3u playlists, mythtv doesn’t have a standard export for them.

After googling around a bit, I decided to write a perl script that does it. Without further ado, here it is for anyone that might need such a thing.

some level of heat storage – so that we don’t have to run the wood fire whenever we want heat

a way for that storage to stay reasonably warm for 4-5 days, so we can go away and have the heating automatically run before we return home

thermostat control on the individual radiators so we can hold a temperature, rather than adjusting temperature through how vigorously we stoke the fire

zoning of the rooms, so that those rooms not in use can not consume heat

allow me to run the boiler hard, rather than damping it down, which reduces pollution and increases heat output from a given weight of wood

the boiler also runs the domestic hot water (DHW) in winter, currently that’s an open cylinder rather than mains pressure, it’s a bit small, and takes forever to get hot water to the kitchen

the thermostat on the boiler that controls the pump is slow to cycle, leading to the boiler overheating and boiling the water, rather than heating it. This is wasteful of heat.

Current planning for the solution comes in multiple parts.

Convert the boiler to drive a mains pressure hot water, and a buffer tank. This means we can run the boiler hard, with all the heat going directly into the DHW and the buffer tank, irrespective of current heat demand. This would be combined with a new controller unit for the pump, with an electronic thermostat so that it cycles much faster

Implement a new pump circuit (reusing one of the old solar hot water pumps) to drive the radiators from the buffer tank

Convert the DHW system to mains pressure, allowing a larger cylinder (the current one is elevated a bit, a new one could go all the way to the floor). This would be combined with a ring main + supply pump, and lagging on the hot water pipes, so that there is always hot water near the kitchen

Implement a control system that can measure the temperature in each room, adjust the radiator valves, control the circulation pump run-time, and implement zoning and set points for daytime and nighttime use

For a buffer tank, I’m looking at a Fiorini buffer tank, similar to this 1000L one, but preferably in 2000L. The main site suggests they’re available. This tank has no coils in it, so reasonably low tech. It’s very large, review on the web suggests that a 2000L tank with a usable 40 degree temperature delta (40 degrees to 80 degrees) would have 100kwh of heat storage. In a steady state that’d probably heat our large and somewhat draughty house for about 1 day.

This would give a boiler loop that looks something like:

We’d need a new pump controller, I haven’t researched those yet.

The radiators are then driven from the buffer tank. If the buffer tank is mostly cold that’s still OK, as the hot water goes in the top from the boiler, and then comes out immediately to go to the radiators.

For a tank, I’d be looking at something with two electric elements plus a heating coil, perhaps something like this Rheem 300L stainless jobby.

The aim is that we have a coil that heats from the boiler (but doesn’t mix the heating water with the DHW), then two electric elements – one driven from night rate and one from normal power. The night rate one would be set to 80 degrees, the day rate one to about 50 degrees. That way we mostly use night rate or boiler energy, but can use day power when we have lots of guests or otherwise run out of hot water.

We’d combine this with a ring main core hot water loop, driven by an on-demand pump such as this grundfos one, which information here suggests uses 5-8w when running, and auto adapts to when you use water such that it costs only a couple dollars a year to run.

This means picking the main loop of hot water, and installing a return line to the DHW cylinder, then lagging that entire loop so that it doesn’t lose much temperature. Some of our piping is plastic, I’d rather it were all copper, so we’d replace that the same time.

Finally, since this hot water will run at up to 80 or 90 degrees when the heating is running hot, it needs tempering valves on every tap so that the actual available hot water temperature is about 60 degrees in the kitchen(s), and 50 degrees everywhere else. As noted in the link this allows storing a smaller amount of very hot water, and mixing with cold at point of use to reduce your overall hot water usage (and improve safety). These valves will also allow constant water output temperature from the ring main, even as temperature fluctuates due to cooling in the pipes.

Control System

For the control system I’m looking at OpenHab, combined with the Max wireless control system.

If I use the Max CUL binding, I can get directly at the valve controls. I’ll write more on this, but in theory what I’d want is:

The most basic Max valves, as I won’t be using the programming capability. These provide a thermostat (they know the temperature of the room near themselves), and allow setting of a desired temperature plus report back the valve open position each time it changes

Temperature sensors on the buffer tank – top, middle and bottom. This allows me to turn off the pump when we run out of heat, and to estimate how much heat is stored in the tank. Need to use the openHab one-wire binding

Temperature sensors on the return from the radiators, telling me if the return water is hot (indicating we should stop circulating)

Logic that adjusts the set point on each for night time, for zoning rooms on and off

Logic that assesses how long to run the pump for based on when it last ran, how far away we are from the set point, how cold it is outside, and how warm the return water is. The aim is to let the bottom of the radiators get quite cold to maximise heat extraction, but maybe that’s not a good aim – maybe we should aim to keep the radiators hot to maximise the warming, we can always reuse the water later so long as it goes back to the buffer tank

Some of the radiators need to not have controllers, in case we accidentally run the pump when all the radiators are off. Probably the towel rail in the main bathroom would be the one that had no thermostat (maybe in the other bathroom too – who needs a thermostat on a towel rail anyway….just means you can’t zone it off)

]]>https://technpol.wordpress.com/2015/10/03/automating-radiator-based-heating-system/feed/2paullambert1Boiler and Heating Looptowel-rail-with-towelsDHW Ring MainOpenHabMax Valve HeadUsing protractor to e2e test ui-grid 3.0 (ng-grid)https://technpol.wordpress.com/2014/09/08/using-protractor-to-e2e-test-ui-grid-3-0-ng-grid/
https://technpol.wordpress.com/2014/09/08/using-protractor-to-e2e-test-ui-grid-3-0-ng-grid/#commentsMon, 08 Sep 2014 04:59:33 +0000http://technpol.wordpress.com/2014/09/08/using-protractor-to-e2e-test-ui-grid-3-0-ng-grid/Continue reading →]]>In my previous post I described upgrading to ui-grid 3.0, which is the not-yet-beta version of ng-grid. Over time this will offer significant benefits, at the moment it feels like a faster ng-grid. As part of implementing it on my core application I needed to rewrite the library routines for my end-to-end testing using protractor. These were reasonably tricky to work out, so I thought I’d post them here for anyone else trying something similar.

The trickiness here is finding the right syntax to identify the elements within the grid, and extract the right row. I also had quite a few issues with clicking on a row to select it.

In my code, I have a decorator that adds these functions onto my pageObject, and I rely on the fact that my pageObject has this.grid defined to be my grid id (for example, “risks).

]]>https://technpol.wordpress.com/2014/09/08/using-protractor-to-e2e-test-ui-grid-3-0-ng-grid/feed/4paullambert1Upgrading to ng-grid 3.0 (ui-grid)https://technpol.wordpress.com/2014/08/23/upgrading-to-ng-grid-3-0-ui-grid/
https://technpol.wordpress.com/2014/08/23/upgrading-to-ng-grid-3-0-ui-grid/#commentsSat, 23 Aug 2014 01:38:02 +0000http://technpol.wordpress.com/2014/08/23/upgrading-to-ng-grid-3-0-ui-grid/Continue reading →]]>In this tutorial segment I upgrade the league application to use the new ui-grid (ng-grid 3.0). Note that ui-grid is at this time still early beta, but offers the likelihood of better performance, a cleaner interface, easier edit in place, and removes the previous dependency on jQuery.

We then obtain the beta files for the new ui-grid. These aren’t installable with bower at the moment, so we download them directly following the links in the ng-grid github. Create a directory vendor/ui-grid, and in that directory:

We then follow the upgrade instructions to change our code to use ui-grid properly. First, we change our controllers in src/app/team/team.js and src/app/club/club.js to include ui.grid instead of ngGrid:

Next, the ui-grid has split out many of the functions into standalone modules, including ui.grid.edit and ui.grid.resizeColumns. The full API can be found in the docs. We’d like to provide edit in place functionality, and to make our columns resizable.

This works, but it calls update after each field edit. It would be preferable for this to be called after the user clicks off the row. This can potentially be achieved through using ui.grid.selection, and the rowSelectionChanged event, although I haven’t implemented that as yet.

The filter functionality also requires modification to continue working. Referring to the tutorial, and guessing a bit from looking at the code, we can make the following changes to the teams controller. We’re turning on filtering on the grid, and if the clubId is present, we’re setting a filter term on the club id column: