Re: [mh] One Wire sensors

Rick Steeves <[email protected]>
Newsgroups gmane.comp.misc.misterhouse.user
Message-ID <[email protected]>
I've been using 1-wire sensors with MH for ... a really long time. There 
is indeed code for 1-wire in MH. Look under "ibutton". There's no need 
really to write a new module.

I put something together that was a compilation of the MH iButton code, 
and then tweaked it. (see attached)

I store the data in the Indoor temp rrd (see attached).

Here's my build doc for the sensor housing as well: 
https://www.sinister.net/1wire/1wiretemp.htm

Rick


On 12/26/2020 9:02 AM, Stephen Switzer wrote:
> Several years ago, I ordered a serial to RJ11 adapter from 
> ibutton(something), called the link 12, and a few temperature sensors 
> that look like the standard TO-92 transistor package. I connected it to 
> MH, added one sensor to the network and tried to see if it worked. I had 
> plans to place sensors all around the house.
> 
> However, I hadn't ever seen any response from the serial port and 
> shelved the project. I decided to look at it again yesterday and 
> discovered how it worked... sort of:
> 
> 
> f=First     \=Snif
> n=Next      |=Thru
> r=Reset     l=Level
> b=Byt(NN+)  ^=57600
> j=Bit(N+)   `=38400
> p=BytW/P    ,=19200
> ~=BitW/P    x=BusLo
> d=Aux+      $=Scan
> z=Aux-      *=List
> &=Aux?      h=Help
> (=Extend
> t=Type      "=Iso
> 
> 
> 420008003BE45B10
> !,420008003BE45B10
> 
> I found that at 9600 baud I can press h to see the help, and *, $ will 
> also return data about the sensor that I have on the network. Wow! I 
> finally have something to work with, but I can't figure out where to get 
> the readings from. Pressing p, j or b all give a 1. One time I saw a B3, 
> but it doesn't seem to be repeatable. It's 179 anyway... my server room 
> rack better not be that temperature!!
> 
> So, I continued and looked for some MH code to read the serial port 
> data. I found several examples, but none of them seemed to be for 
> reading the OW data directly from a serial port. All seemed to read a 
> dump from an external program - and all from Windows. I'm running Linux.
> 
> So, I looked a owfs: installed it, configured it the best that I could 
> figure out and poked around the /run/owfs filesystem...
> 
> root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/latesttemp
> 43.1086root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/latesttemp
> 91.3275root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/latesttemp
> 14.4802root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/latesttemp
> 94.4001root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/latesttemp
> 46.0749root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/latesttemp
> 90.8667root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/temperature
> 36.8015root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/temperature
> 1.73821root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/temperature
> 31.6712root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/temperature
> 65.0987root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/temperature
> 27.7991root@avalanche:~# cat /run/owfs/bus.0/10.67C6697351FF/temperature
> 
> Every time I checked values, it was something different. Perhaps this is 
> because I twisted the sensors onto the wires, instead of a more secure 
> connection?
> 
> Either way, I'm getting SOMETHING... so I think it's time to ask: how do 
> YOU gather OW data? Is there a module for MH to tread it directly, or 
> should we use something external?
> 
> Thank you all!
> 
> -- 
> 
> Best regards,
> Steve Switzer
> 
> ---
> Get world-class business I.T. services and a phone system with awesome features that won't challenge your budget!
> http://www.sbsROC.com
> 
> 
> 
> ________________________________________________________
> To unsubscribe from this list, go to: https://lists.sourceforge.net/lists/listinfo/misterhouse-users
> 

-- 
Rick Steeves
https://www.irelandbybicycle.com

It's all fun and games until someone ends up wearing a cone.

________________________________________________________
To unsubscribe from this list, go to: https://lists.sourceforge.net/lists/listinfo/misterhouse-users
RickButton.txt (text/plain, 16.7 KB)
# Category = iButtons

#@ Manage iButton devices

# Rick Steeves
# [email protected]
# My summary of 1-wire functionality mostly by functions for modularity
# Running on Windows 2000/XP
# There are a lot of iButton modules w/i mh that are bits and pieces
# Almost 100% derived from the iButton modules within mh:
# code\public\ibutton_ws_ernie.pl
# code\common\iButton.pl
# code\bruce\iButton_bruce.pl
# and others but organized and working for my specific environment

# To connect to the serial line, you need a serial to 1-wire adaptor
#  1-Wire Serial Adaptor   DS9097U-A  from www.hobby-boards.com
# Defined in mh.private.ini
##mh.ini: iButton_serial_port=COM4  (or whatever com port)

#from iButton.pl. connect/disconnect to the iButton bus
# I'm not using iButton.pl because it periodically also checks the bus, 
# and I don't want it to. So I copied out everything else.

# Updated to send mail when the water detects water. 091231

$v_iButton_connect   = new Voice_Cmd "[Connect,Disconnect] to the iButton bus";
$v_iButton_connect  -> set_info('Use this to free up the serial port or test the iButton start/stop calls');
if ($state = said $v_iButton_connect) {
    print "$state the iButton bus\n";
    if ($state eq 'Connect') { print_log &iButton::connect($config_parms{iButton_serial_port}); }
    else { print_log &iButton::disconnect; }
}

# List all iButton devices on the wire
$v_iButton_list      = new Voice_Cmd "List all the iButton buttons";
$v_iButton_list     -> set_info('Lists the family and ID codes of all the buttons on the bus');
$v_iButton_list     -> set_authority('anyone');
if (said $v_iButton_list) {
    print_log "List of ibuttons:\n" . &iButton::scan_report;
#    print_log "List of ibuttons on 2nd ibutton:\n" . &iButton::scan_report(undef, $config_parms{iButton_2_serial_port})
#        if $config_parms{iButton_2_serial_port};
}

# The  4 Channel Relay   4R3-R1-A from www.hobby-boards.com 
# http://www.hobby-boards.com/catalog/howto_4_channel_relay.php?referer=howto_mini_motion_detector.php
# The first two characters are the device type. 
# In this case '05' is an addressable switch for the DS2405
my $ib_relay1   = new iButton '0500000032073e29';
my $ib_relay2   = new iButton '05000000320484af';
my $ib_relay3   = new iButton '0500000031fa0e06';
my $ib_relay4   = new iButton '0500000031f9ddd5';
# Can be defined instead in items.mht as example: 
# IBUTTON, 0500000032073e29,    ib_relay1

$v_iButton_relay1    = new Voice_Cmd "Turn relay1 [on,off]";
$v_iButton_relay1   -> set_info('Controls Relay 1');
$v_iButton_relay1   -> set_authority('anyone');
$v_iButton_relay2    = new Voice_Cmd "Turn relay2 [on,off]";
$v_iButton_relay2   -> set_info('Controls Relay 2');
$v_iButton_relay2   -> set_authority('anyone');
$v_iButton_relay3    = new Voice_Cmd "Turn relay3 [on,off]";
$v_iButton_relay3   -> set_info('Controls Relay 3');
$v_iButton_relay3   -> set_authority('anyone');
$v_iButton_relay4    = new Voice_Cmd "Turn relay4 [on,off]";
$v_iButton_relay4   -> set_info('Controls Relay 4');
$v_iButton_relay4   -> set_authority('anyone');

if ($state = said $v_iButton_relay1) {
    print_log "Setting iButton relay1 to $state";
    set $ib_relay1 $state;
}
if ($state = said $v_iButton_relay2) {
    print_log "Setting iButton relay2 to $state";
    set $ib_relay2 $state;
}
if ($state = said $v_iButton_relay3) {
    print_log "Setting relay3 to $state";
    set $ib_relay3 $state;
}
if ($state = said $v_iButton_relay4) {
    print_log "Setting relay4 to $state";
    set $ib_relay4 $state;
}

# I have two sets of wireless transmitters for speakers in the house
# hooked to the computer through a "y" splitter to the main computer speakers.
# They're hooked to the relay switch. This way I can effectively turn off the 
# MH speakers throughout the house. Two relays, two channels (L&R).
$v_iButton_Speakers    = new Voice_Cmd "Turn Speakers [on,off]";
$v_iButton_Speakers   -> set_info('Controls Relay 1 and 2');
$v_iButton_Speakers   -> set_authority('anyone');

# I have wireless speakers connected to the first two relays (left and right channels)
if ($state = said $v_iButton_Speakers) {
    print_log "Setting Speakers to $state";
    set $ib_relay1 $state;
    set $ib_relay2 $state; 
    #a general mh value defined in mh_sound
    set $mh_speakers $state;
}

# The iButton Temp/humidity Code
my $object_name = '';
my $itemp = '';  # Temporary temp variable

# I wanted to add temp, humidity, and water monitoring to my crawl space
# 1-wire seemed like a good choice, but the devices I purchased were not as 
# simple to get working as I'd hoped, as I had to write Get_Vwet_2438 in Device.pm to do it!
# For the DS2438 Chip, as used by the MS-TH and MS-THW at http://www.ibuttonlink.com
# The DS2438 is type: 26
# As would be defined in items.mht 
#IBUTTON, 2600000081161fa8,    ib_water
#IBUTTON, 26000000809ad7f3,    ib_temp1
#IBUTTON, 26000000815f600e,    ib_temp2
#IBUTTON, 2600000080bb306a,    ib_temp3
# The first 2 digits are the type, the last two the CRC, and the rest the ID
# in this case the first (ib_water) is the temp/humidity/water sensor, the next two temp/humidity, and the last temp
my $ib_sensor1= new iButton '2600000081161fa8';   	# Sump 2438 Water
	$ib_sensor1->{object_name} = 'Water Sensor'; 
#my $ib_sensor2= new iButton '26000000809ad7f3';  # 
my $ib_sensor2= new iButton '100008013e7bdb5a';
	$ib_sensor2->{object_name} = 'Computer Room';  	# MH 1920
my $ib_sensor3= new iButton '26000000815f600e';  
	$ib_sensor3->{object_name} = 'Crawl Space';	# Crawl Space 2438 Humid
my $ib_sensor4= new iButton '2600000080bb306a';    
	$ib_sensor4->{object_name} = 'Servers';  	# Servers 2438 Temp only
my $ib_sensor5= new iButton '100008013e9ebaa6';
	$ib_sensor5->{object_name} = 'Den';   		# Den 1920
my $ib_sensor6= new iButton '100008013e9a021f';
	$ib_sensor6->{object_name} = 'Library';   	# Library 1920
my $ib_sensor7= new iButton '100008013ebcdff5';
	$ib_sensor7->{object_name} = 'Dining Room';     # Dining 1920
my $ib_sensor8= new iButton '100008013eaf1597';
	$ib_sensor8->{object_name} = 'Bed Room';   	# Bedroom 1920

# The order the sensors are read in - used to determine TempSpare order for RRD
my @ib_sensors = ($ib_sensor1, $ib_sensor6, $ib_sensor3, $ib_sensor2, $ib_sensor5, $ib_sensor4,$ib_sensor7,$ib_sensor8); # the array of sensors
	#	      Sump         Library      Crawl    computer         Den         Servers     BedRoom        Dining Room

my @ib_sensorsRH = ($ib_sensor1, $ib_sensor3);
my @ib_sensorsWet = ($ib_sensor1);

my $ib; # temporary value as things are read of out the array

# Read the temp from one 1-wire device
$v_iButton_readtemp  = new Voice_Cmd "Read temp [1,2,3,4,5,6,7,8]";
$v_iButton_readtemp -> set_info('Read the temperature from a specific button');
$v_iButton_readtemp -> set_authority('anyone');

if ($state = said $v_iButton_readtemp) {
   $ib = $ib_sensors[$state - 1];
   $object_name = $ib->{object_name};
   # Add to detect whether its family is a 2438 or a 1920 ..
   if ($ib->family eq '26') {   
      $itemp = &Read_DS2438Temp($ib);
      print_log "DS2438: $object_name TempF=" . sprintf ("%3.1f",$itemp); 
   } elsif ($ib->family eq '10') {
      $itemp = read_temp $ib;
      print_log "DS1920: $object_name TempF=" . sprintf ("%3.1f",$itemp); 
    }
	speak "app=weather The $object_name temp is " . int($itemp+.5) . " degrees";
}

# Read the temp from all of the 1-wires
# List all iButton temperatures.  Note this can take a while, but there's no proxy support.
$v_iButton_readtemps = new Voice_Cmd "Read all temp";
$v_iButton_readtemps-> set_info('Reads all temperature devices.  Takes a while (.6 s per device)');
$v_iButton_readtemps -> set_authority('anyone');

if (said $v_iButton_readtemps) {
   # print_log "Reading iButton temperatures";
   for $ib (@ib_sensors) {
      $object_name = $ib->{object_name};
      if ($ib->family eq '26') {  # for the DS2438s
         $itemp = &Read_DS2438Temp($ib); 
         print_log "DS2438: $object_name TempF=" . sprintf ("%3.1f",$itemp); 
	  } elsif ($ib->family eq '10') {   # for the DS1920s
         $itemp = read_temp $ib; 
         print_log "DS1920: $object_name TempF=" . sprintf ("%3.1f",$itemp); 
      }
   }
}

# Read the relative humidity (RH) from one 1-wire 2438 device
$v_iButton_readhumDS2438  = new Voice_Cmd "Read humidity [1,2]";
$v_iButton_readhumDS2438 -> set_info('Read the humidity from a specific button');
$v_iButton_readhumDS2438 -> set_authority('anyone');

if ($state = said $v_iButton_readhumDS2438) {
	$ib = $ib_sensorsRH[$state - 1];
	$itemp = &Read_DS2438RH($ib);
	$object_name = $ib->{object_name};
	print_log "DS2438: $object_name RH=" . sprintf ("%3.1f",$itemp); 
	speak "app=weather The $object_name humidity is " . int($itemp+.5) . " percent";
}

# List all iButton humidity.  Note this can take a while, but there's no proxy support.
$v_iButton_readhumsDS2438 = new Voice_Cmd "Read all humidity";
$v_iButton_readhumsDS2438-> set_info('Reads all humidity devices.  Takes a while (.6 s per device)');
$v_iButton_readhumsDS2438 -> set_authority('anyone');

if (said $v_iButton_readhumsDS2438) {
    #print_log "Reading iButton humidities:";
    for $ib (@ib_sensorsRH) { 
		$itemp = &Read_DS2438RH($ib); 
		$object_name = $ib->{object_name};
		print_log "DS2438: $object_name RH=" . sprintf ("%3.1f",$itemp); 
	}
}

# Read the wet-ness (Vwet) from one 1-wire device
$v_iButton_readwetDS2438  = new Voice_Cmd "Read wet [1]";
$v_iButton_readwetDS2438 -> set_info('Read the wetness from a specific button');
$v_iButton_readwetDS2438 -> set_authority('anyone');

# And the MH-THW monitors whether it's wet or not, to warn me if something's wrong with the pump
# command now set elsewhere in the Alarms function (triggers.pl) to run voice command. Easier to adjust than changing the code when I need to
if ($state = said $v_iButton_readwetDS2438) {
    for $ib (@ib_sensorsWet) { 
		$itemp = &Read_DS2438Wet($ib);
		$object_name = $ib->{object_name};
		print_log "DS2438: $object_name Wet: $itemp"; 
		if ($itemp == 0) { 
			# speak "The wire is not wet"; 		
		} elsif ($itemp == 1) { 
			speak "app=weather Warning: $object_name water wire is disconnected";
		} elsif ($itemp == 2) { 
			speak "app=weather Warning: $object_name Water detected"; print_log "Warning: $object_name Water detected";
    		if ($config_parms{mail_home}) {
				&net_mail_send(
				subject => "Water Detected", 
				text    => "$object_name Water Detected",
				to		=> $config_parms{mail_home}
				);
			}
		} elsif ($itemp == -1) { 
			speak "app=weather Warning: $object_name Water Error state reported";
		} else { 
			speak "app=weather Warning: Error on $object_name";
    		if ($config_parms{mail_home}) {
				&net_mail_send(
				subject => "Water Detection Error", 
				text    => "$object_name Error",
				to		=> $config_parms{mail_home}
				);
			}
		}
	}
}



sub Read_DS2438Temp {
	my ($sensor) = @_;
	$object_name = $sensor->{object_name};
	my $DS2438_tempF;
	my $DS2438_tempC;
	$DS2438_tempC = $sensor->Get_Temp_2438;  #read DS2438 temp in Celsius
	if ($DS2438_tempC) {
		$DS2438_tempF = ($DS2438_tempC * 9)/5+32;
		# And return all values from whence we came
		return $DS2438_tempF;
	} else { return undef; }
}

sub Read_DS2438RH {
	my ($sensor) = @_;
	$object_name = $sensor->{object_name};
	my $DS2438_tempC;
	my $DS2438_Vad;
	my $DS2438_Vdd;
	my $RH;

	$DS2438_tempC = $sensor->Get_Temp_2438;  #read DS2438 temp in Celsius
	$DS2438_Vad   = $sensor->Get_Vad_2438;   #read DS2438 Vad
	$DS2438_Vdd   = $sensor->Get_Vdd_2438;   #read DS2438 Vdd
	# for some reason the VaD/Vdd values are sometimes strings. Make sure they're numbers
	#if (($DS2438_Vad) && ($DS2438_Vdd) && ($DS2438_tempC) && ($DS2438_Vad =~ /^[0-9]*$/) && ($DS2438_Vdd =~ /^[0-9]*$/)) {
	#if (($DS2438_Vad) && ($DS2438_Vdd) && ($DS2438_tempC) && (!($DS2438_Vad =~ /\D/)) && (!($DS2438_Vdd =~ /\D/))) {
    if (($DS2438_Vad) && ($DS2438_Vdd) && ($DS2438_tempC) && ($DS2438_Vad =~ /\D/) && ($DS2438_Vdd =~ /\D/)) {
        $RH = ((($DS2438_Vad/$DS2438_Vdd) - 0.16) / 0.0062) * (1.0546 - 0.00216 * $DS2438_tempC);
	# 161006 Fixed for if a negative value is returned
	if ($RH < 0) { $RH = 0; }
    	return $RH;
    } else { 
        print_log "DS2438: $object_name: TempC:$DS2438_tempC Vad: $DS2438_Vad  Vdd: $DS2438_Vdd"; # for debugging
    	return undef;
    }
    # And return all values from whence we came
}

sub Read_DS2438Wet {
	my ($sensor) = @_;
	my $object_name = $sensor->{object_name};
	$itemp  = $sensor->Get_Vwet_2438; #read DS2438 Vwet 
	return $itemp;
}

# Next was getting rrd to work. 
# first, I pulled rrd from ppm
# ppm
# install RRD-Simple
# install rrd.ppm
# and installed RRD from  http://oss.oetiker.ch/rrdtool/

# and populated all of the rrd environment variables in mh.private.ini
#rrd_dir=e:/rrd
#weather_data_csv=$config_parms{data_dir}/rrd/environ.csv
#weather_data_rrd=$config_parms{data_dir}/rrd/environ.rrd
#@ The location where the graphs are to be stored [$config_parms{data_dir}/rrd]
#weather_graph_dir = $config_parms{data_dir}/rrd/graphs
#@ The Footer to be used on all the graphs [Last updated $Time_Date, copyright www.domotix.net]
#weather_graph_footer = Last updated $Time_Date, copyright www.sinister.net
#@ How often in minutes to update the graph [10]
#weather_graph_frequency	= 30
#@ Skip generation graphs for specific periods, blank to generate graphs for all periods
#weather_graph_period_skip = 2month 6month 1year 2year 5year
#@ Skip generation graphs, blank to generate all the graphs, possible values : tempout tempin windspeed winddir raintotal rainrate press humout humin
#weather_graph_skip = windspeed winddir raintotal rainrate
# Web dir for PNG graph file
#html_alias_rrd = $config_parms{data_dir}/rrd/graphs
#weather_rrd_format = PNG     # PNG / GIF (PNG is default)
#  - Sensor name for indoor temperature and humidity graphs
#weather_graph_sensor_names = intemp => Average Indoor Temp, inhumid => Average Indoor Humidity, tempspare1 => Water Sensor, tempspare2 => Computer Room, tempspare3 => Back Crawl Space, humidspare1 => Water Sensor, humidspare2 => Computer Room, humidspare3 => Back Crawl Space
# Values : sensor names = intemp, tempspare1,..., tempspare10, inhumid,
# humidspare1,...,humidspare10

# And activated code/common/weather_rrd_update.pl
# and it created the database

my $temp_avg;
my $humid_avg;
my @old_humid;

$v_iButton_setWeather = new Voice_Cmd "Update iButton Data";
$v_iButton_setWeather-> set_info('Updates the iButton variables');
$v_iButton_setWeather -> set_authority('anyone');

# Done as a voice command so the update interval can be set as a trigger, instead
# of hard-coded
if (said $v_iButton_setWeather || $Startup || $Reload) {
	&setWeather;
}

sub setWeather {
	# updates the %Weather hash for known values from the iButton devices.
	# this way these items can be graphed as the temp values used by weather_rrd_update.pl
	# Get the temp states
	my $new_temp_avg;
	my $new_humid_avg;
	my $sensor;
	my $tempsensor;
	my $humidsensor;
	my $sensorsfound;
	my $counter;
	
	$new_temp_avg = 0;
	$sensor = 0;
	$counter = 0;
	for my $i (0..$#ib_sensors) {
   		$ib = $ib_sensors[$i];
   		$object_name = $ib->{object_name};
		if ($ib->family eq '26') {  # for the DS2438s
        	$itemp = &Read_DS2438Temp($ib);
		} elsif ($ib->family eq '10') {  # for the DS1920s
			$itemp = read_temp $ib;
		} 
		$sensor = $i + 1;
		$tempsensor = 'TempSpare'."$sensor";
		if ($itemp) { # Make this error resistant by not replacing when it's zero
			$Weather{$tempsensor} =  sprintf("%3.2f", $itemp);
			$new_temp_avg += $itemp;
			$counter++;
		} else {
      		#$new_temp_avg += $Weather{$tempsensor};
    	}
	}

	#$new_temp_avg = $new_temp_avg / ($#ib_sensors + 1);
	$new_temp_avg = $new_temp_avg / ($counter);
	$Weather{'TempIndoor'} = sprintf("%3.2f", $new_temp_avg); 

	# Get the humid States
	$new_humid_avg = 0;
	$sensor = 0;
	$sensorsfound = 0;
	for my $i (0..$#ib_sensorsRH) {
   		$ib = $ib_sensorsRH[$i];
   		$object_name = $ib->{object_name};
		$itemp = &Read_DS2438RH($ib);
		$sensor = $i + 1;
		$humidsensor = 'HumidSpare'."$sensor";
		if ($itemp) {
			$Weather{$humidsensor} =  sprintf("%3.2f",$itemp);
			$old_humid[$sensor] = $Weather{$humidsensor};
			$new_humid_avg += $itemp;
			$sensorsfound++;
		} else {
      		#$humid_avg += $Weather{$humidsensor};
      		if ($old_humid[$sensor]) { $Weather{$humidsensor} =  sprintf("%3.2f",$old_humid[$sensor]); }
		}
	}
	if ($sensorsfound) {
		#$humid_avg = $humid_avg / ($#ib_sensorsRH + 1);
		$new_humid_avg = $new_humid_avg / ($sensorsfound);
		$Weather{'HumidIndoor'} = sprintf("%3.2f",$new_humid_avg);
		$humid_avg = $new_humid_avg;
	} else {
		$Weather{'HumidIndoor'} = sprintf("%3.2f",$humid_avg);
	}
}
weather_tempin_1week.png (image/png, 123.7 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.