From d93061259bcc8bd8963bfcdc3a56b2c0db96ccfb Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 7 Jan 2022 14:24:28 +0100 Subject: [PATCH] +bin/heat,+bin/usbrelay --- bin/heat | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bin/usbrelay | 59 +++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100755 bin/heat create mode 100755 bin/usbrelay diff --git a/bin/heat b/bin/heat new file mode 100755 index 0000000..a3ac277 --- /dev/null +++ b/bin/heat @@ -0,0 +1,153 @@ +#! /usr/bin/perl +# * * * * * nice -n20 /root/bin/heat -s +use strict; +use warnings; +$|=1; +sub readfile($) { + my($fname)=@_; + local *F; + if (!open F,$fname) { + warn "$fname: $!"; + return undef; + } + my $F=do { local $/; ; }; + defined $F or die "read $fname: $!"; + close F or die "read-close $fname: $!"; + return $F; +} +sub writefile { + my($fname,$content)=@_; + local *F; + open F,">$fname" or die "$fname: $!"; + print F $content or die "write $fname: $!"; + close F or die "write-close $fname: $!"; +} +sub spawn($) { + my($cmd)=@_; + $cmd.=" >&2"; + system $cmd or return 1; + warn "$cmd: $!"; + return 0; +} +my($trash,$min,$hour)=localtime; +my $minutes=$hour*60+$min; +if (($ARGV[0]||"")=~/^[@]0?(\d+):0?(\d+)$/) { + $minutes=$1*60+$2; + shift; +} +my $schedulefile="/root/heat.schedule"; +my $statefile="/root/heat.state"; +my $resetfile="/root/heat.reset"; +my $usbrelay="/root/bin/usbrelay"; +my $schedule=readfile $schedulefile; +my $finishline; +my %schedule; +while ($schedule=~s/^(0?(\d+):0?(\d+)) ([01s])\n//) { + my $tm=$2*60+$3; + warn "$schedulefile set twice for: $1" if defined $schedule{$tm}; + $schedule{$tm-24*60}="$1 $4\n"; + $schedule{$tm }="$1 $4\n"; + $schedule{$tm+24*60}="$1 $4\n"; +} +warn "$schedulefile garbage: $schedule" if $schedule ne ""; +sub schedulenext($) { + my($now)=@_; + my($bestprev,$prev,$bestnext,$next); + for my $found (keys(%schedule)) { + if ($found<=$now) { + next if defined $bestprev&&$bestprev>$found; + $bestprev=$found; + $prev=$schedule{$found}; + } else { + next if defined $bestnext&&$bestnext<$found; + $bestnext=$found; + $next=$schedule{$found}; + } + } + die "No bestprev" if !defined $bestprev; + die "No bestnext" if !defined $bestnext; + return [$prev,$next]; +} +$finishline=schedulenext $minutes; +my $silent=shift if ($ARGV[0]||"") eq "-s"; +sub info($) { + my($s)=@_; + print $s if !$silent; +} +sub finish() { + info join("",@$finishline) if defined $finishline; + exit 0; +} +my $reset=readfile $resetfile if -e $resetfile; +my($resetminutes,$resetstate); +sub resetread() { + $reset=~/^0?(\d+):0?(\d+) ([01s]|reset)\n$/ or warn "Invalid $resetfile: $reset"; + $resetminutes=$1*60+$2; + $resetstate=($3 eq "reset"?undef:$3); +} +if (defined $reset) { + resetread; + if ($resetminutes==$minutes) { + unlink $resetfile or die "$resetfile: $!"; + $reset=$resetminutes=undef; + } +} +sub finishlinereset() { + $finishline=schedulenext $resetminutes; + splice @$finishline,1,0,$reset; +} +finishlinereset if defined $reset; +my $state=readfile $statefile; +chomp $state; +info $state; +my $newstate=shift; +$newstate=$resetstate if !defined $newstate&&defined $resetstate&&!defined $resetminutes; +sub printminutes($) { + my($m)=@_; + return sprintf "%02d:%02d",int($m/60),$m%60; +} +if ($silent) { + if (!defined $newstate&&!defined $reset) { + my $prev=schedulenext($minutes)->[0]; + $newstate=$prev if $prev=~s{^@[ printminutes $minutes ] (.)\n$}{$1} or $prev=undef; + } + $newstate=$state if !defined $newstate; +} +if (!defined $newstate) { + info "\n"; + finish; +} +die "state!={s|0|1}" if $newstate!~/^[s01]$/; +sub setstate() { + info "->$newstate"; + my $both={"s"=>[0,0],"0"=>[1,0],"1"=>[1,1]}->{$newstate}; + $state eq $newstate or unlink $statefile or warn "$statefile: $!"; + ( spawn "$usbrelay 1 ".$both->[0] + and spawn "$usbrelay 2 ".$both->[1]) + or do { unlink $statefile; die "usbrelay error"; }; + $state eq $newstate or writefile $statefile,"$newstate\n"; + info "\n"; +} +my $newreset=shift; +die "Excessive args: ".join(" ",@ARGV) if @ARGV; +if (!defined $newreset) { + setstate; + if (!$silent&&defined $reset) { + unlink $resetfile or die "$resetfile: $!"; + $finishline=schedulenext $minutes; + } + finish; +} +$reset=$newreset; +if ($reset=~/^\d+$/) { + $resetminutes=$reset+$minutes; + $reset=printminutes($resetminutes)." reset\n"; + setstate; +} else { + $reset.=" $newstate\n"; + resetread; + info "\n"; +} +writefile $resetfile,$reset; +finishlinereset; +finish; diff --git a/bin/usbrelay b/bin/usbrelay new file mode 100755 index 0000000..d45514c --- /dev/null +++ b/bin/usbrelay @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8 -*- +# https://slomkowski.eu/tutorials/eavesdropping-usb-and-writing-driver-in-python/ + +import time +import sys + +import usb.core +import usb.util + +VENDOR_ID = 0x16c0 +DEVICE_ID = 0x05df + +MANUFACTURER_NAME = "www.dcttech.com" +PRODUCT_NAME = "USBRelay2" + + +def check_manufacturer_and_product(dev): + return dev.manufacturer == MANUFACTURER_NAME and dev.product == PRODUCT_NAME + + +def find_device_handle(): + return usb.core.find(idVendor=VENDOR_ID, idProduct=DEVICE_ID, + custom_match=check_manufacturer_and_product) + + +dev_handle = find_device_handle() + +if dev_handle.is_kernel_driver_active(0): + try: + dev_handle.detach_kernel_driver(0) + print("kernel driver detached") + except usb.core.USBError as e: + sys.exit("Could not detach kernel driver: %s" % str(e)) + +requestType = usb.util.build_request_type(usb.util.CTRL_OUT, + usb.util.CTRL_TYPE_CLASS, + usb.util.CTRL_RECIPIENT_INTERFACE) + + +def set_relay(relay_number, enabled: bool): + b1 = 0xff if enabled else 0xfd + dev_handle.ctrl_transfer(requestType, 9, 0x0300, 0, (b1, relay_number, 0, 0, 0, 0, 0, 0)) + + +#while True: +# set_relay(1, True) +# time.sleep(1) +# set_relay(1, False) +# time.sleep(1) +# set_relay(2, True) +# time.sleep(1) +# set_relay(2, False) +# time.sleep(1) + + +if len(sys.argv)!=3 or (sys.argv[1]!="1" and sys.argv[1]!="2") or (sys.argv[2]!="0" and sys.argv[2]!="1"): + sys.exit("usbrelay: {1|2} {0|1}") +set_relay((1 if sys.argv[1]=="1" else 2),(True if sys.argv[2]=="1" else False)) -- 1.8.3.1