Setup and Tools

Introduction

1-Wire devices have a unique ID on the network, like "10.21501B000800".
As these IDs are not very easy to remember and might change over the years when a defective sensor is replaced, there needs to be an abstraction layer.

The most naïve aproach is to use a uniqe name for each sensor, for example:
A sensor with name "Outside Temperature" points to "10.21501B000800".

There is, however, a problem with this approach as some sensors have only one ID, but can measure several seperate things, for example a DS2423 with 2 distinct counters.

In order to cope with these things, I chose to uniqly identify a sensor by its location and its type.
These locations and types are just numerical IDs and are arbitrarily.

Location and type

All configuration is stored in a mySQL database as I need a DB for other things anyway.

Locations

Locations are meant to be physical locations, example:

  1. Outside
  2. Livingroom
  3. Wire Closet
  4. Boiler Top
  5. Boiler Middle
  6. Boiler Bottom
  7. ...

It is important to think about the used IDs as they are used to initiate a measurment. It is best to have a logical hierarchy, but not required.

Types

Maybe "types" is not the best name, but it signifies all different sensor types and what exactly it measures from a sensor.
Example:

  1. Temperature
  2. Humidity
  3. Barometric presure
  4. Counter.A
  5. Counter.B
  6. ...

When a measurement is requested of a sensor in location "3" of type "4" a different counter is accessed as when the same sensor is measured with type "4".
The IDs of these types are important as the measurement script uses these to know what to measure, so you can not change them without changing the code.

Remarks

It is very important to understand the combination of "location" and "type" must be unique.
This means you can not have two different sensors at the same location with the same type.

If you require redundancy in measurements, you need to define different "locations", example:

  1. Furnace Temperature (Main)
  2. Furnace Temperature (Backup)
  3. ...

When new sensors, or types of sensors, are added to the 1-wire network these tables will grow.
Howver, the existing entries will never change.

The names used for the locations and types are not important. They are only used for display purposes.

The IDs used for the "types" are very important, as in the measurement script these are used to differentiate between different sensors. The numerical value of the "type" determines how to retrieve a usable value from the sensor.

mySQL tables

create table Locations
(

LocationID	tinyint(3)	not null,
LocationString	varchar(50)	not null,

PRIMARY KEY (LocationID)
);

create table Types
(

TypeID		tinyint(3)	not null,
TypeString	varchar(50)	not null,

PRIMARY KEY (TypeID)
);

Sensors

Sensors are also added to a mySQL table, they can only be added for an existing location and type.
The sensor table has a reference to these, but also the sensor ID, a name and a special column called "Alert".

The sensor ID is not unique, as it might be reused with a different Type.
The name column is a unique name for this sensor and is not only used for diplay purposes but can also be used to refer to this sensor.
The "alert" column is a boolean and set to true when you want to receive an alert when this sensor disapears from the 1-Wire network. This is used as for monitoring.

Example:

4   1   10.111111111111   BoilerTempTop      1
5   1   10.222222222222   BoilerTempMiddle   1
6   1   10.333333333333   BoilerTempBottom   1

This defines 3 temperature sensors (type = 1) at 3 different locations. (4, 5 and 6.)
They all 3 have a different 1-wire ID and a unique name. All 3 sensors also need to be present on the 1-Wire network in order to not have any alerts.

Remarks

If you have the same sensor ID with different "types" in the sensorlist, you probably want to have only one entry with the "Alert" boolean set. Otherwise you will receive duplicate alerts when the sensor becomes unreachable.

mySQL tables

create table OW_Sensors
(

LocationID	tinyint(3)	not null,
TypeID		tinyint(3)	not null,
OWID		varchar(30)	not null,
Name		varchar(50)     not null	unique,
Alarm		boolean		not null	default 0,

PRIMARY KEY (LocationID, TypeID)
);

Sensor Monitoring

This MisterHouse Perl snippet monitors if the selected sensors are still available on the 1-Wire network.
It does not verify if the sensor is operating as expected. Your code should always check if the returned sensorvalues make any sense.
Currently the code simply prints a warningmessage when a sensor that has the alarm function enabled is not found on the 1-Wire network. You probably want to write better alert handling.

# Category = OWFS
#@This program is resposible for all verifying if critical OWFS sensors are still available.
#@This is to ensure MisterHouse can operate in normal conditions.
#@It requires a running owserver and certain SQL databases.

####################################################################################
use DBI;
use Data::Dumper;
use OW;

my $SQLServer   = "127.0.0.1";
my $SQLUser     = "mh";
my $SQLPassword = "password";
my $SQLDatabase = "domotica";

my $OWFSServer  = "127.0.0.1";

my @Alert_Sensors;

my $debug       = 0;
####################################################################################
# noloop=start

# noloop=stop
####################################################################################

if ( $Startup || $Reread )
{
  print "Sensor alerts: DB read requested.\n" if $debug;
  &Read_Critical_Sensors;
}

if ( $New_Minute )
{
  print "Sensor alerts: Checking sensor presence.\n" if $debug;
  &Check_Sensor_Presence;
}
####################################################################################
sub Read_Critical_Sensors()
{
  print "Sensor alerts: Connecting to database.\n" if $debug;
  my $db = DBI->connect("DBI:mysql:$SQLDatabase:$SQLServer:3306", "$SQLUser", "$SQLPassword");
  my $sql_query = $db->prepare("Select OWID from OW_Sensors where Alarm = 1;");
  $sql_query->execute();

  print "Sensor alerts: Fetching query results.\n" if $debug;
  while ( (my @result) = $sql_query->fetchrow_array() )
  {
    push(@Alert_Sensors, $result[0]);
  }

  print "Sensor alerts: Query results:\n" if $debug;
  print Dumper(@Alert_Sensors) if $debug;

  $db->disconnect();
}
####################################################################################
sub Check_Sensor_Presence()
{
  OW::init("$OWFSServer");
  foreach (@Alert_Sensors)
  {
    print "Sensor alerts: Checking sensor " . $_ . "\n" if $debug;

    if ( OW::get("/$_") )
    {
      print "Sensor alerts: sensor " . $_ . " is present.\n" if $debug
    }
    else
    {
      print "Sensor alerts: sensor " . $_ . " not found!\n";
      print_log "Sensor alerts: Sensor $_ not found!";
    }
  }
  OW::finish();
}
####################################################################################