<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.domoticz.com/index.php?action=history&amp;feed=atom&amp;title=Sonoff_-_failsafe_switching</id>
	<title>Sonoff - failsafe switching - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.domoticz.com/index.php?action=history&amp;feed=atom&amp;title=Sonoff_-_failsafe_switching"/>
	<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Sonoff_-_failsafe_switching&amp;action=history"/>
	<updated>2026-09-20T04:09:46Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://wiki.domoticz.com/index.php?title=Sonoff_-_failsafe_switching&amp;diff=11584&amp;oldid=prev</id>
		<title>Philchillbill at 17:59, 27 November 2018</title>
		<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Sonoff_-_failsafe_switching&amp;diff=11584&amp;oldid=prev"/>
		<updated>2018-11-27T17:59:15Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==Failsafe switching of Sonoff relay devices==&lt;br /&gt;
&lt;br /&gt;
If you have flashed a Sonoff relay device with ESPeasy, you can have Domoticz turn the device on/off from a dummy switch using a http:// call to the relevant URL in the action field. For example, for a device at octet 27&lt;br /&gt;
 http://192.168.1.27/control?cmd=gpio,12,1 &lt;br /&gt;
turns the relay on, while ?cmd=gpio,12,0 turns it off again. In the real world, you will regularly encounter missed packets with this approach (it&amp;#039;s as if the Sonoffs aren&amp;#039;t always listening). When this happens, Domoticz and the Sonoff are out of sync - you think/hope you&amp;#039;ve switched something on or off but in fact there was no response from the Sonoff and Domoticz is none the wiser.&lt;br /&gt;
&lt;br /&gt;
One way around this is to use script:// instead of http:// in the dummy-switch action field and have an external script send the http:// command to the Sonoff, poll the Sonoff to ensure that the relay has actually switched, and resend the http:// if needed (repeatedly) in case a discrepancy is found. To check the current state of a Sonoff, we can use &lt;br /&gt;
 http://192.168.1.27/json?view=sensorupdate&amp;amp;tasknr=1 &lt;br /&gt;
and we will then see something along the lines of:&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
 &amp;quot;TaskValues&amp;quot;: [&lt;br /&gt;
 {&amp;quot;ValueNumber&amp;quot;:1,&lt;br /&gt;
 &amp;quot;Name&amp;quot;:&amp;quot;state&amp;quot;,&lt;br /&gt;
 &amp;quot;NrDecimals&amp;quot;:0,&lt;br /&gt;
 &amp;quot;Value&amp;quot;:1&lt;br /&gt;
 }],&lt;br /&gt;
 &amp;quot;TTL&amp;quot;:60000,&lt;br /&gt;
 &amp;quot;TaskEnabled&amp;quot;:&amp;quot;true&amp;quot;,&lt;br /&gt;
 &amp;quot;TaskNumber&amp;quot;:1&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
with the Mega version of ESPeasy, or with e.g. version 120 we get simpler JSON:&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
 &amp;quot;TaskName&amp;quot;: &amp;quot;relay&amp;quot;,&lt;br /&gt;
 &amp;quot;state&amp;quot;: 0.00&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Our script can check for either format automatically. The &amp;#039;&amp;#039;TaskName&amp;#039;&amp;#039; of &amp;#039;relay&amp;#039; has a &amp;#039;&amp;#039;state&amp;#039;&amp;#039; of 0.00, indicating the relay is currently off - the state is 1.00 if it&amp;#039;s on. Our script uses this approach to verify that the Sonoff received a command and will keep resending until the state changes as required. With our script installed, in the on-action / off-action fields of a Domoticz switch, you can use a construct along the lines of&lt;br /&gt;
&lt;br /&gt;
 script://sonoffs.sh 27 12 0&lt;br /&gt;
 script://sonoffs.sh 148 12 1&lt;br /&gt;
&lt;br /&gt;
where the 27 or 148 (say) are the least-significant octet of the IP address of the Sonoff, the 12 is the gpio number to switch, and 0 or 1 is the required state.&lt;br /&gt;
&lt;br /&gt;
=== Setup ===&lt;br /&gt;
&lt;br /&gt;
Our script is written in perl but when using it with Domoticz we will call it from a pre-processor script written in bash. The reason for this is that the perl script has a deliberate (short) sleep-delay built-in before it retries a failed command. As Domoticz waits for scripts to finish before continuing its own execution, this delay would hold up Domoticz and we don&amp;#039;t want that. The bash wrapper-script kicks off execution of the perl script and passes along our command-line parameters, but suppresses output from the perl and - most importantly - makes it run as a separate process (thanks to the final &amp;#039;&amp;amp;&amp;#039;) so that control immediately returns to Domoticz. Perfect.&lt;br /&gt;
&lt;br /&gt;
Create a bash script called &amp;#039;&amp;#039;sonoffs.sh&amp;#039;&amp;#039; with the following content, and put it in your &amp;#039;&amp;#039;/home/pi/domoticz/scripts&amp;#039;&amp;#039; directory (and of course, do a &amp;#039;&amp;#039;chmod +x&amp;#039;&amp;#039;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
/usr/bin/perl /home/pi/domoticz/scripts/sonoffs.pl $1 $2 $3 &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure perl is installed (it very likely is on a linux-based OS) and then install the modules from CPAN that we need:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo cpan install JSON::XS&lt;br /&gt;
 sudo cpan install LWP::UserAgent&lt;br /&gt;
 sudo cpan install URI::Escape&lt;br /&gt;
&lt;br /&gt;
Now create a perl script called &amp;#039;&amp;#039;sonoffs.pl&amp;#039;&amp;#039; with the following content, and put it in your &amp;#039;&amp;#039;/home/pi/domoticz/scripts&amp;#039;&amp;#039; directory (and of course, do a &amp;#039;&amp;#039;chmod +x&amp;#039;&amp;#039;). You will need to edit the $domoticz and $baseUrl variables to match your particular setup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/perl&lt;br /&gt;
use JSON::XS;&lt;br /&gt;
use LWP::UserAgent;&lt;br /&gt;
use URI::Escape;&lt;br /&gt;
&lt;br /&gt;
no warnings &amp;#039;uninitialized&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
# Switches a Sonoff device on/off on behalf of Domoticz and then checks that it actually switched accordingly (in case of packet-loss)&lt;br /&gt;
# Autor: philchillbill, 2018&lt;br /&gt;
&lt;br /&gt;
($octet, $gpio, $value)=@ARGV;&lt;br /&gt;
$tries=0;&lt;br /&gt;
&lt;br /&gt;
$domoticz=&amp;#039;http://192.168.1.12:8080&amp;#039;; # full URL of your Domoticz instance&lt;br /&gt;
$baseUrl=&amp;#039;http://192.168.1.&amp;#039;; # The most significant 3 octets of your local area IP addresses for the Sonoffs&lt;br /&gt;
&lt;br /&gt;
sub postDomoticzLog {&lt;br /&gt;
 my $msg=shift;&lt;br /&gt;
 $message=uri_escape($msg);&lt;br /&gt;
 $msg_url=$domoticz.&amp;#039;/json.htm?type=command&amp;amp;param=addlogmessage&amp;amp;message=&amp;#039;.$message;&lt;br /&gt;
 $ua=LWP::UserAgent-&amp;gt;new; $ua-&amp;gt;timeout(5); $res=$ua-&amp;gt;put($msg_url);&lt;br /&gt;
 unless ($res-&amp;gt;is_success) { warn &amp;quot;oops... &amp;quot;, $res-&amp;gt;status_line };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$ua=LWP::UserAgent-&amp;gt;new; $ua-&amp;gt;timeout(1); $ua-&amp;gt;env_proxy;&lt;br /&gt;
&lt;br /&gt;
# first check we are not clashing with another process handling the same Sonoff device&lt;br /&gt;
while ( -e &amp;quot;/tmp/.busy.$octet&amp;quot; ) {&lt;br /&gt;
 $secs++; sleep 1; $waited=1;&lt;br /&gt;
 if ($secs==30) {&lt;br /&gt;
  unlink (&amp;quot;/tmp/.busy.$octet&amp;quot;) or die $!;&lt;br /&gt;
  &amp;amp;postDomoticzLog(&amp;quot;Early exit of lockfile-wait loop with Sonoff &amp;#039;$octet&amp;#039;&amp;quot;);&lt;br /&gt;
  last;&lt;br /&gt;
 }&lt;br /&gt;
}&lt;br /&gt;
if ($waited) { print &amp;quot;Waited for other process...\n&amp;quot;; sleep 5 };&lt;br /&gt;
 &lt;br /&gt;
# now place our own lockfile to hold off other processes&lt;br /&gt;
open(TMP, &amp;#039;&amp;gt;&amp;#039;, &amp;quot;/tmp/.busy.$octet&amp;quot;) or die $!;&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
do {&lt;br /&gt;
 # First send the command to the Sonoff&lt;br /&gt;
 $url=$baseUrl.$octet.&amp;quot;/control?cmd=gpio,&amp;quot;.$gpio.&amp;quot;,&amp;quot;.$value; # e.g. http://192.168.178.27/control?cmd=gpio,12,0&lt;br /&gt;
 $c=0;&lt;br /&gt;
 do { $c++;&lt;br /&gt;
  $response=$ua-&amp;gt;get($url); &lt;br /&gt;
 } until ( ($response-&amp;gt;is_success) || ($c==5) );&lt;br /&gt;
&lt;br /&gt;
 # Now check if it reacted, using the /json endpoint&lt;br /&gt;
 $url=$baseUrl.$octet.&amp;quot;/json?view=sensorupdate&amp;amp;tasknr=1&amp;quot;; &lt;br /&gt;
 $d=0;&lt;br /&gt;
 do {&lt;br /&gt;
  sleep 1; $d++;&lt;br /&gt;
  $response=$ua-&amp;gt;get($url); &lt;br /&gt;
 } until ( ($response-&amp;gt;is_success) || ($d==10) );&lt;br /&gt;
&lt;br /&gt;
 if ($response-&amp;gt;is_success) {&lt;br /&gt;
  $tasks=$response-&amp;gt;decoded_content; $data=decode_json $tasks;&lt;br /&gt;
  if (exists $$data{state}) { $state=$$data{state} } else { $state=$$data{TaskValues}[0]{Value} }; # Both espeasy R120 / Mega JSON formats&lt;br /&gt;
 }&lt;br /&gt;
 else { &amp;amp;postDomoticzLog(&amp;quot;No response from Sonoff &amp;#039;$octet&amp;#039;&amp;quot;); exit 0 }; &lt;br /&gt;
&lt;br /&gt;
 $ok=( ($value eq &amp;#039;0&amp;#039;) &amp;amp;&amp;amp; ($state==0) ) || ( ($value eq &amp;#039;1&amp;#039;) &amp;amp;&amp;amp; ($state==1) ); $tries++;&lt;br /&gt;
 &lt;br /&gt;
} until ( ($ok) || ($tries==5) );&lt;br /&gt;
&lt;br /&gt;
if ( -e &amp;quot;/tmp/.busy.$octet&amp;quot; ) { unlink (&amp;quot;/tmp/.busy.$octet&amp;quot;) or die $!};&lt;br /&gt;
&lt;br /&gt;
if (!$ok) { &amp;amp;postDomoticzLog(&amp;quot;Error setting Sonoff &amp;#039;$octet&amp;#039; to state &amp;#039;$value&amp;#039;&amp;quot;) };&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;c: $c, d: $d, tries: $tries\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
exit 0;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s it. You can debug things if necessary by running the perl script directly from the linux command line: e.g. &amp;#039;&amp;#039;./sonoffs.pl 27 12 1&amp;#039;&amp;#039; and seeing if any error messages are thrown. Also, if the bash script won&amp;#039;t run from Domoticz, try specifying the full path to the bash file with a triple-slash: &lt;br /&gt;
 script:///home/pi/domoticz/scripts/sonoffs.sh 27 12 0&lt;/div&gt;</summary>
		<author><name>Philchillbill</name></author>
	</entry>
</feed>