selfcontrol.cz - ovládání RE8USB ze skriptu v jazyce Ruby - Linux

Dokumentace k RE8USB je zde http://www.selfcontrol.cz/navod_re8usb.htm

Že počítáč USB zařízení vidí, otestujeme pomocí

lsusb

Přidám uživatele do skupiny dialout, aby měl přístup k /dev/ttyUSB0 a skript tak nemusel běžet jako root.

adduser xsouku04 dialout

instalace ruby a potřebných knihoven pro ruby

aptitude install ruby
aptitude install ruby-dev ruby-mkrf
gem install serialport
#!/usr/bin/ruby
#encoding: utf-8
 
require 'serialport'
# Příklad ovládání RE8USB
$port= SerialPort.new("/dev/ttyUSB0", 9600,  8, 1, SerialPort::NONE)
$port.read_timeout=5000 # pokud nám nic nepošlou, čekáme maximálně 5 vteřin
# vyhnu se tak nekonečnému "zaseknutí" programu pokud je někde chyba, nebo pokud
# zařízení žádné  události prostě neposílá. 
# Umožní mi to v mezičase  změnit stav relátka - pokud by bylo třeba
# Nastavení níže nebyl potřeba, ale jiné podobné aplikace jej používají, nechávám si jej tedy
# v poznámce.
#$port.sync = true
 
 
def prectiOdpoved()
  buf=""
  begin
    precteny_znak=$port.getc
    if precteny_znak!=nil then buf+=precteny_znak end
  end while precteny_znak!=nil and precteny_znak!="*"
  # odpovědi končí znakem *, nil znamená, že došlo k timeoutu (něco je špatně)
  return buf
end
 
# poznámka pro Rubysty (nic důležitého):
# Pokud bych nechtěl používat globální proměnou $port, mohl bych definovat funkci následovně:
#x = Proc.new do
#end
#x.call
# v tomto případě by byly uvnitř funkce přístupné i neglobální proměnné.
 
 
$port.write("RESET=Ys")   # chceme informaci o sepnutí i rozepnutí kontaktu
puts prectiOdpoved()
$port.write("RUN=1s")  # chceme zasílat informace o změnách
puts prectiOdpoved()
while true do
    jaky_vstup= $port.getc
   if jaky_vstup!=nil # nil znamená, že RE8USB nic neposlalo a uplatnil se timeout
     if jaky_vstup>="1" and jaky_vstup<="8" then
        puts "vstup #{jaky_vstup} sepnut"        
        $port.write("R#{jaky_vstup}=1s") # cvaknu relátkem a rozsvítím diodu
     elsif jaky_vstup>="A" and jaky_vstup<="H"
        puts "vstup #{jaky_vstup.getbyte(0)-64} rozpojen"
        # znak A má v ASCII číslo 64, tedy když odečteme 64 máme z ABCDEFGH obět čísla 12345678
        $port.write("R#{jaky_vstup.getbyte(0)-64}=0s") # cvaknu relátkem a zhasnu diodu
     end
   end
end
 
#Možné logování:
#puts Time.new.strftime("%Y-%m-%d %H:%M:%S")+" posláno:"+co_poslat

Příklad výstupu

ruby serialRead.rb 
L=Y*
running*
vstup 1 sepnut
vstup 1 rozpojen
vstup 3 sepnut
vstup 3 rozpojen
vstup 2 sepnut
vstup 2 rozpojen

Podle obrázku 2a) jsem drátkem propojil vstup IN1 s GND a uvolnil. Poté to stejné IN3 a IN2. Program průběžně vypisoval informace výše a též rozsvítil/zhasnul ledku - vždy při změně stavu bylo slyšet cvaknutí relátka.

Další info na fóru http://forum.odorik.cz/viewtopic.php?f=33&t=3122&start=20#p24768

Seznam rozpojených jističů

gem install sinatra
#!/usr/bin/ruby
#encoding: utf-8
require 'sinatra'
require 'serialport'
# Příklad čtení stavu vstupů z USB30IN
$port= SerialPort.new("/dev/ttyUSB0", 9600,  8, 1, SerialPort::NONE)
$port.read_timeout=5000 # pokud nám nic nepošlou, čekáme maximálně 5 vteřin
set :bind, '0.0.0.0'
set :port, 80
 
 
def prectiOdpoved()
  buf=""
  begin
    precteny_znak=$port.getc
    if precteny_znak!=nil then buf+=precteny_znak end 
  end while precteny_znak!=nil and precteny_znak!="*"
  $port.getc  # cr
  $port.getc  # lf
  # odpovědi končí znakem *, nil znamená, že došlo k timeoutu (něco je špatně)
  return buf 
end
 
get '/' do
#  'Hello world!'
   $port.write("?")   # chceme informaci o sepnutí i rozepnutí kontaktu
   odpoved=prectiOdpoved()
   odpoved[0]=odpoved[31]=""
   vratime="<H2>Seznam rozpojených jističů</H2>"
   (0..30).each do |i| 
      if odpoved[i]=="0"
        vratime+="#{i+1},"
      end 
   end 
  vratime[vratime.length-1]=""
  vratime
end

Banana - malina

malina - Raspberry - napájení - zálohovaný zdroj

Web alarmu

web.rb

#!/usr/bin/ruby
#encoding: utf-8
require 'sinatra'
 
set :bind, '0.0.0.0'
set :port, 80
 
 
use Rack::Auth::Basic, "Restricted Area" do |username, password|
    username == 'prihl_jmeno' and password == 'heslo'
end
 
 
load '/root/selfcontrol/rele_definice.rb'
 
 
get '/' do
   vratime="<H2>Vítejte</H2>\n"
   if lokalni_ip=/^192\.168\.2/.match(request.ip)
     vratime << "Přistupujete z lokální sítě ip"
    else
     vratime << "Přistupujete se vzdálené ip"
    end   
   vratime<<" #{request.ip}<br>\n"
 # obrázky z kamer
   vratime<<" <img src='a.jpg'> <br>\n"
   vratime<<" <img src='b.jpg'> <br>\n"
   vratime<<" <img src='usb.jpg'> <br>\n"
 
   vratime<<"<form action='/' method='POST'>"
 
   vratime<<"<table><tr><th>jméno</th><th>stav</th><th>čas poslední změny</th></tr>\n"
     (Dir["/root/selfcontrol/stav/*"]+Dir["/root/selfcontrol/rele_aktualni_stav/*"]).each{ |f| 
       if File.file?(f) and  File.extname(f)!=".log" then
          vratime << "<tr><td>#{File.basename(f)}</td><td>#{stav=File.read(f)}</td> <td>#{File.mtime(f).strftime('%Y-%m-%d %H:%M:%S')} </td>"
          if f.include?("rele_aktualni_stav") then
                        informace_o_rele=Rele_hash[File.basename(f)]
                        opacny_stav=cislo_rele="" # jinak by promenne neprizili vynoreni z cyklu
                        informace_o_rele.each do |key,value| 
                             if key==:cislo
                               cislo_rele=value
                             elsif key!=stav
                               opacny_stav=key
                             end 
                        end    
 
                        vratime << " <td> <button type='submit' name='operace' value='#{File.basename(f)}_#{opacny_stav}'>#{opacny_stav}</button> </td>  </tr>\n"
 
          else
             vratime << "</tr>\n"
          end   
       end   
     }   
   vratime<<"</table>\n"
#  vratime[vratime.length-1]=""
#  vratime
end
 
get '/a.jpg' do # d-link
  require 'open-uri'
    open('http://192.168.2.194/image.jpg').read
end  
 
get '/b.jpg' do # edimax
  require 'open-uri'
    open('http://192.168.2.150/snapshot.jpg', :http_basic_authentication=>['admin','1234']).read
end 
 
get  '/usb.jpg' do
  `fswebcam -r 640x480 /root/selfcontrol/image.jpg`
   send_file "/root/selfcontrol/image.jpg"
end
 
 
get '/nagios' do
   "0,vsechno OK"  # vracíme stavy 0 OK, 1 - warnink, 2 - critical ,  text bez háčků
end 
 
post "/" do
  rele_cislo,rele_novy_stav=params[:operace].split('_')
  `/root/selfcontrol/rele.rb #{rele_cislo} #{rele_novy_stav}`
  sleep(0.75)
  redirect to('/')
end

ostatní části alarmu

rele_definice.rb

#!/usr/bin/ruby
#encoding: utf-8
Rele_hash =  {"svetla"=>{:cislo=>1,"sviti"=>1,"nesviti"=>0},
           "alarm"=>{:cislo=>2,"houka"=>1, "nehouka"=>0},
           "zakaznici"=>{:cislo=>3,"on"=>0,"off"=> 1},
           "obsluha"=>{:cislo=>4,"on"=>0,"off"=> 1},
           "stoly"=>{:cislo=>5,"on"=>0,"off"=> 1},
           "boiler"=>{:cislo=>6,"on"=>1,"off"=> 0},
           "kuchyn"=>{:cislo=>7,"on"=>0,"off"=> 1}, 
           "reklama"=>{:cislo=>8,"sviti"=>0,"nesviti"=>1}}

Jak povolit https v sinatře. - https://gist.github.com/TakahikoKawasaki/40ef0ab011b0a467bedf#file-sinatra-ssl-rb

http://stackoverflow.com/questions/3696558/how-to-make-sinatra-work-over-https-ssl/12373973#12373973?newreg=6cdd8150f38b465ebe6cd010651315bc

Jak udělat aby webbrick poslouchal na všech adresách? :Host ⇒ '0.0.0.0' http://www.parorrey.com/blog/webmaster-tasks/configuring-webrick-to-serve-redmine-over-ssl-using-openssl-certificate/

https://github.com/plamoni/SiriProxy/issues/41 - aptitude install libssl-dev před gem install thin rele.rb

#!/usr/bin/ruby
#encoding: utf-8
 
LOG_DIR="/root/selfcontrol/rele_aktualni_stav/"
LOG_FILE="#{LOG_DIR}rele.log"
 
require 'serialport'
# Příklad ovládání RE8USB
$port= SerialPort.new("/dev/ttyUSB0", 9600,  8, 1, SerialPort::NONE)
$port.read_timeout=5000 # pokud nám nic nepošlou, čekáme maximálně 5 vteřin
# vyhnu se tak nekonečnému "zaseknutí" programu pokud je někde chyba, nebo pokud
# zařízení žádné  události prostě neposílá. 
# Umožní mi to v mezičase  změnit stav relátka - pokud by bylo třeba
# Nastavení níže nebyl potřeba, ale jiné podobné aplikace jej používají, nechávám si jej tedy
# v poznámce.
#$port.sync = true
 
 
 
def prectiOdpoved()
  buf=""
  begin
    precteny_znak=$port.getc
    if precteny_znak!=nil then buf+=precteny_znak end 
  end while precteny_znak!=nil and precteny_znak!="*"
  # odpovědi končí znakem *, nil znamená, že došlo k timeoutu (něco je špatně)
  return buf 
end
 
# poznámka pro Rubysty (nic důležitého):
# Pokud bych nechtěl používat globální proměnou $port, mohl bych definovat funkci následovně:
#x = Proc.new do
#end
#x.call
# v tomto případě by byly uvnitř funkce přístupné i neglobální proměnné.
 
def log(co)
 puts co  
 File.open(LOG_FILE, 'a') { |file| file.puts(co) }
end 
 
load '/root/selfcontrol/rele_definice.rb'
 
rele_jmeno=ARGV[0]
rele_jmeno_noveho_stavu=ARGV[1]
 
if Rele_hash[rele_jmeno].nil?   # chybné jméno relé
  log(Time.new.strftime("%Y-%m-%d %H:%M:%S")+" Nenalezeno jméno relé  \"#{rele_jmeno}\". Očekávaná jména jsou: #{Rele_hash.keys}")
  exit
else
  rele_cislo=Rele_hash[rele_jmeno][:cislo]
end
 
rele_novy_stav= Rele_hash[rele_jmeno][rele_jmeno_noveho_stavu]
if  rele_novy_stav.nil? 
  log(Time.new.strftime("%Y-%m-%d %H:%M:%S")+" Nenalezeno jméno nového stavu v hashi rele_jmeno:#{rele_jmeno} rele_jmeno_noveho_stavu:#{rele_jmeno_noveho_stavu} očekávané stavy jsou: #{Rele_hash[rele_jmeno]}")
  exit
end
 
 
co_poslat="R#{rele_cislo}=#{rele_novy_stav}s"
 
$port.write(co_poslat) # cvaknu relátkem 
File.open("#{LOG_DIR}#{rele_jmeno}", 'w') { |file| file.write(rele_jmeno_noveho_stavu) }
 
log(Time.new.strftime("%Y-%m-%d %H:%M:%S")+" #{rele_jmeno} #{rele_jmeno_noveho_stavu}  posláno: #{co_poslat} ")

cti_stav.rb

#!/usr/bin/ruby
#encoding: utf-8
 
LOG_DIR="/root/selfcontrol/stav/"
LOG_FILE="#{LOG_DIR}stav.log"
 
 
require 'serialport'
# Příklad ovládání RE8USB
$port= SerialPort.new("/dev/ttyUSB0", 9600,  8, 1, SerialPort::NONE)
$port.read_timeout=5000 # pokud nám nic nepošlou, čekáme maximálně 5 vteřin
# vyhnu se tak nekonečnému "zaseknutí" programu pokud je někde chyba, nebo pokud
# zařízení žádné  události prostě neposílá. 
# Umožní mi to v mezičase  změnit stav relátka - pokud by bylo třeba
# Nastavení níže nebyl potřeba, ale jiné podobné aplikace jej používají, nechávám si jej tedy
# v poznámce.
#$port.sync = true
 
 
def log(co)
 puts co  
 File.open(LOG_FILE, 'a') { |file| file.puts(co) }
end 
 
def prectiOdpoved()
  buf=""
  begin
    precteny_znak=$port.getc
    if precteny_znak!=nil then buf+=precteny_znak end 
  end while precteny_znak!=nil and precteny_znak!="*"
  # odpovědi končí znakem *, nil znamená, že došlo k timeoutu (něco je špatně)
  return buf 
end
 
# poznámka pro Rubysty (nic důležitého):
# Pokud bych nechtěl používat globální proměnou $port, mohl bych definovat funkci následovně:
#x = Proc.new do
#end
#x.call
# v tomto případě by byly uvnitř funkce přístupné i neglobální proměnné.
 
 
stav_hash={"3"=>["PIR_stoly","ok"],
           "C"=>["PIR_stoly","POHYB"],
           "7"=>["PIR_vstup","ok"],
           "G"=>["PIR_vstup","POHYB"],
           "1"=>["DVERE_mezi","zavreno"],
           "A"=>["DVERE_mezi","otevreno"],
           "2"=>["OKNO","zavreno"],
           "B"=>["OKNO","otevreno"],
           "6"=>["DVERE_vstup","zavreno"],
           "F"=>["DVERE_vstup","otevreno"],
 
}
 
 
$port.write("RESET=Ys")   # chceme informaci o sepnutí i rozepnutí kontaktu
puts prectiOdpoved()
$port.write("RUN=1s")  # chceme zasílat informace o změnách
puts prectiOdpoved()
while true do
    jaky_vstup= $port.getc
   if jaky_vstup!=nil # nil znamená, že RE8USB nic neposlalo a uplatnil se timeout
     if ! stav_hash[jaky_vstup].nil?
      File.open("#{LOG_DIR}#{stav_hash[jaky_vstup][0]}", 'w') { |file| file.write(stav_hash[jaky_vstup][1]) }
      udalost="#{stav_hash[jaky_vstup][0]}>#{stav_hash[jaky_vstup][1]}"
     else
      udalost=" popis události v hashi nenalezen "
     end  
     if jaky_vstup>="1" and jaky_vstup<="8" then
        log(Time.new.strftime("%Y-%m-%d %H:%M:%S")+" vstup #{jaky_vstup} sepnut #{udalost}")
       #   $port.write("R#{jaky_vstup}=1s") # cvaknu relátkem a rozsvítím diodu
     elsif jaky_vstup>="A" and jaky_vstup<="H"
          log(Time.new.strftime("%Y-%m-%d %H:%M:%S")+" vstup #{jaky_vstup.getbyte(0)-64} rozpojen #{udalost} ")
        # znak A má v ASCII číslo 64, tedy když odečteme 64 máme z ABCDEFGH obět čísla 12345678
      #  $port.write("R#{jaky_vstup.getbyte(0)-64}=0s") # cvaknu relátkem a zhasnu diodu
     end 
   end 
end
 
selfcontrol.txt · Last modified: 2015/12/12 19:38 (external edit)