Skocz do zawartości

Raspberry Pi, skrypty i Domoticz


cwietov

Pomocna odpowiedź

Cześć, mam pytanie dotyczące wywoływania skryptów napisanych w Pythonie na Raspberry Pi z poziomu Domoticza. 

Mianowicie, mam listwę LEDową sterowaną skryptami napisanymi w Pythonie. Skrypty wymagają bibliotek NeoPixel. Chciałbym móc wykorzystać owe skrypty z poziomu Domoticza, by móc to wszystko dodatkowo zautomatyzować i stworzyć np. jakieś sceny. Czy istnieje taka możliwość? 

Spędziłem już nad tym X czasu, przejrzałem Internet wydaje się we wszystkie strony i niestety nic nie znalazłem. Zagadnienie wydaje się być banalne.

W tym momencie zrobiłem to na zasadzie przycisku wirtualnego, gdzie w polu aktywacji podaje lokalizację skryptu włączającego LEDy, a w polu wyłączenia skrypt wyłączający. Jednakże to rozwiązanie nie działa i w patrząc na logi widzę, że dostaje błąd "256" (Error: Error executing script command (/home/pi/domoticz/scripts/python/led_blue.py). returned: 256). Internet nie jest niestety zbytnio pomocny w tym temacie. Wydaje się, że nadałem wszelkie możliwe uprawienia. 

Czy jest na to jakaś metoda? Może podchodzę do tego tematu błędnie? Będę wdzięczny za wszelkie wskazówki!  

W załączniku zrzut ekranu przycisku wirtualnego z podaną lokalizacją skryptu (bez skrypty wyłączającego, ale to już analogia).

Przechwytywanie.PNG

Link do komentarza
Share on other sites

@cwietov w tym roku coś podobnego robiłem, ale mam tego skryptu pod ręką 😞 

Idea jest taka że korzystasz z API. Tak jak robisz: piszesz skrypt w Pythonie i nawet zwykły polling się nada - co jakiś czas sprawdzasz co jest wystawione w api dla tego modułu kontrolera RGB. Pamiętam że było kilka modułów do RGB, u mnie działał taki zbudowany na dummy:

image.thumb.png.f8ffec9eccbbabc3e03f7e42f972a6b8.png

Pamiętam że znalezienie liniki do API, gdzie miałeś tego JSONa z nastawami kontrolera nie było takie oczywiste, trzeba było poczytać jakie parametry są używane w danych kontrolerach.

Wiem że to mało precyzyjna odpowiedź, jak niezbyt pomoże to pomyślimy co dalej 🙂 

Edytowano przez Gieneq
Link do komentarza
Share on other sites

(edytowany)

Dzięki za odpowiedź 🙂 

"Moduły" chodzi o moduły Domoticza czy hardware? Trochę nie do końca rozumiem, jak mógłbym się za to zabrać. W sensie z tego co zrozumiałem nie ma opcji tak po prostu wywołania skryptu żeby się wykonał? Czyli, żeby LEDy się właśnie włączyły lub wyłączyły. Póki co kontrola parametrów świecenia w pełnym spectrum, aż tak bardzo mnie nie interesuje. Chce po prostu jakoś wywołać skrypt bo wiem, że jakoś można, tylko właśnie jak najlepiej? 😄 Bo tu niestety dostaje błędy. Jak próbuje wywołać skrypt przez inny skrypt to nie dostaje błędu, ale nic się nie dzieje. Jaki jest najlepszy sposób w Pythonie wywołania skryptu w skrypcie? W sensie żeby napisać skrypt, który będzie wywoływał skrypt włączający LEDy itd. Może tutaj tkwi jakiś problem i tędy droga. 

Edytowano przez cwietov
Link do komentarza
Share on other sites

@cwietov dobra odkopałem maline i mam skrypty, przeklejam cały kod bo może coś cie w nim zainspiruje. Ten pierwszy ma funkcję do pobrania wartości z kontrolera domoticza:

#!/usr/bin/python3
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

from urllib.request import urlopen
from urllib.error import URLError
import threading
import json
import re
import ast
import time

serverIP = "192.168.0.12:8080"
dummy_rgb_id = 22
url = "http://" + serverIP + "/json.htm?type=devices&rid=" + str(dummy_rgb_id)

pin_button = 22

##########################

pin_segment_s1 = 25
pin_segment_s2 = 23
pin_segment_s3 = 24
pin_segment_ss = 7

pin_segment_a = 5
pin_segment_b = 21
pin_segment_c = 25
pin_segment_d= 26
pin_segment_e = 19
pin_segment_f = 20
pin_segment_g = 12
pin_segment_dp = 13

value_display = 888

##########################

import board
import neopixel
PIEXELS_COUNT=1
pixels = neopixel.NeoPixel(board.D18, PIEXELS_COUNT, brightness=1.0, auto_write=False)

##########################

def updateColorValues():
    global brightness
    global red
    global green
    global blue

    while True:
        print("Acquiring colour data...")
        try:
            response = urlopen(url)
            # Convert bytes to string type and string type to dict
            string = response.read().decode('utf-8')
            json_obj = json.loads(string)

            brightnessRaw = json_obj['result'][0]['Status']
            paresedBrightness = re.findall(r'\d+', brightnessRaw)
            if len(paresedBrightness) > 0:
                brightness = int(paresedBrightness[0])

            colorRaw = json_obj['result'][0]['Color']
            # print(colorRaw)
            color = ast.literal_eval(colorRaw)
            # print(color)

            red = color['r']
            green = color['g']
            blue = color['b']

            print("Get: {}, {}, {}, brightness {}".format(red, green, blue, brightness))

            pixels.brightness = float(brightness / 100.0)
            pixels.fill((red, green, blue))
            pixels.show()

            time.sleep(0.5)
        except URLError as e:
            print('Meh HTTPError = ' + str(e) + " trying to reconnect in 5 seconds...")
            time.sleep(5)
        except Exception:
            import traceback
            print('generic exception: ' + traceback.format_exc())





if __name__ == "__main__":

    red = 255
    green = 0
    blue = 0
    brightness = 255

    GPIO.setup(pin_segment_s1, GPIO.OUT)
    GPIO.output(pin_segment_s1, GPIO.LOW)
    GPIO.setup(pin_segment_s2, GPIO.OUT)
    GPIO.output(pin_segment_s2, GPIO.HIGH)
    GPIO.setup(pin_segment_s3, GPIO.OUT)
    GPIO.output(pin_segment_s3, GPIO.HIGH)
    GPIO.setup(pin_segment_ss, GPIO.OUT)
    GPIO.output(pin_segment_ss, GPIO.HIGH)

    GPIO.setup(pin_segment_a, GPIO.OUT)
    GPIO.output(pin_segment_a, GPIO.LOW)
    GPIO.setup(pin_segment_b, GPIO.OUT)
    GPIO.output(pin_segment_b, GPIO.LOW)
    GPIO.setup(pin_segment_c, GPIO.OUT)
    GPIO.output(pin_segment_c, GPIO.LOW)
    GPIO.setup(pin_segment_d, GPIO.OUT)
    GPIO.output(pin_segment_d, GPIO.LOW)
    GPIO.setup(pin_segment_e, GPIO.OUT)
    GPIO.output(pin_segment_e, GPIO.LOW)
    GPIO.setup(pin_segment_f, GPIO.OUT)
    GPIO.output(pin_segment_f, GPIO.LOW)
    GPIO.setup(pin_segment_g, GPIO.OUT)
    GPIO.output(pin_segment_g, GPIO.LOW)
    GPIO.setup(pin_segment_dp, GPIO.OUT)
    GPIO.output(pin_segment_dp, GPIO.LOW)

    threadUpdateColours = threading.Thread(target=updateColorValues)
    threadUpdateColours.start()

    while True:
        GPIO.output(pin_segment_s1, GPIO.LOW)
        time.sleep(1)
        GPIO.output(pin_segment_s1, GPIO.HIGH)
        time.sleep(1)


    GPIO.cleanup

i pomiary z Dallasem i przetwornikiem ADS:

#!/usr/bin/python3
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

import Adafruit_ADS1x15
from w1thermsensor import W1ThermSensor

import subprocess
import time
import os
from bs4 import BeautifulSoup
import urllib3

pin_sens_enable = 17
pin_indicator = 27

###################

serverIP = "192.168.0.12:8080"
dummy_core_temp_id = 8
coreTemperatureValue = 10.0

dummy_outside_temp_id = 18
outsideTemperature = 15.0

###################

adc = Adafruit_ADS1x15.ADS1115()
adc_channels = 4
adc_gain = 1
adc_values = [0]*4

sensors_count = 4
sensors = [{"name" : "None", "minValADC" : 1000, "maxValADC" : 50000, "val" : 0} for x in range(sensors_count)]

LIGHT = 0
sensors[LIGHT]["name"] = "Light"
sensors[LIGHT]["minValADC"] = 100.0
sensors[LIGHT]["maxValADC"] = 30000.0

HUM1 = 1
sensors[HUM1]["name"] = "Hum1"
sensors[HUM1]["minValADC"] = 20500.0
sensors[HUM1]["maxValADC"] = 9000.0

HUM2 = 2
sensors[HUM2]["name"] = "Hum2"
sensors[HUM2]["minValADC"] = 21500.0
sensors[HUM2]["maxValADC"] = 13000.0

HUM3 = 3
sensors[HUM3]["name"] = "Hum3"

dummy_hum1_id = 19
dummy_hum2_id = 20
dummy_hum3_id = 21
dummy_light_sens_id = 14

http = urllib3.PoolManager()

def rescaleValues():
  for i in range(sensors_count):
    sensor = sensors[i]
    a = 100.0/(sensor["maxValADC"] - sensor["minValADC"])
    b = 100.0 - a * sensor["maxValADC"]
    temp_value = a * adc_values[i] + b
    if temp_value < -100.0:
      temp_value = -100.0
    if temp_value > 100.0:
      temp_value = 100.0
    if temp_value < 0.0:
      temp_value = -temp_value
    sensor["val"] = temp_value

def scanADC():
  for i in range(adc_channels):
    adc_values[i] = adc.read_adc(i, gain=adc_gain)
  rescaleValues()

def measure_core():
  coreTemperature = subprocess.check_output(["/opt/vc/bin/vcgencmd", "measure_temp"])
  return float(coreTemperature.decode().split("=")[1][:-3])

# API: https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s

def sendLightSenor(deviceId, name, value, rawValue):
  trimedValue = round(value, 1)
  print("Sending light sensor... {}: {} / {} to device: {}".format(name, trimedValue, rawValue, deviceId))
  url = "http://" + serverIP + "/json.htm?type=command&param=udevice&idx=" + str(deviceId) + "&svalue=" + str(trimedValue)
  return http.request('GET', url)

def sendHumiditySensor(deviceId, name, value, rawValue):
  trimedValue = round(value, 1)
  print("Sending humidity sensor... {}: {} / {} to device: {}".format(name, trimedValue, rawValue, deviceId))
  url = "http://" + serverIP + "/json.htm?type=command&param=udevice&idx=" + str(deviceId) + "&nvalue=" + str(trimedValue)
  return http.request('GET', url)

def sendTemperature(deviceId, name, value):
  trimedValue = round(value, 1)
  print("Sending temeprature... {}: {} to device: {}".format(name, trimedValue, deviceId))
  url = "http://" + serverIP + "/json.htm?type=command&param=udevice&idx=" + str(deviceId) + "&svalue=" + str(trimedValue)
  return http.request('GET', url)


def send_data(coreTmp):
  print("Sending data:")

  sendLightSenor(dummy_light_sens_id, sensors[LIGHT]["name"], sensors[LIGHT]["val"], adc_values[LIGHT])

  sendHumiditySensor(dummy_hum1_id, sensors[HUM1]["name"], sensors[HUM1]["val"], adc_values[HUM1])
  sendHumiditySensor(dummy_hum2_id, sensors[HUM2]["name"], sensors[HUM2]["val"], adc_values[HUM2])
  sendHumiditySensor(dummy_hum3_id, sensors[HUM3]["name"], sensors[HUM3]["val"], adc_values[HUM3])

  sendTemperature(dummy_core_temp_id, "CoreTemp", coreTemperatureValue)
  sendTemperature(dummy_outside_temp_id, "OutsideTemp", outsideTemperature)

if __name__ == "__main__":
  GPIO.setup(pin_indicator, GPIO.OUT)
  GPIO.setup(pin_sens_enable, GPIO.OUT)

  # do stuff
  GPIO.output(pin_sens_enable, GPIO.HIGH)
  GPIO.output(pin_indicator, GPIO.HIGH)
  time.sleep(2)

  # read sensors
  sensor = W1ThermSensor()
  outsideTemperature = sensor.get_temperature()
  scanADC()
  coreTemperatureValue = measure_core()

  GPIO.output(pin_indicator, GPIO.LOW)
  GPIO.output(pin_sens_enable, GPIO.LOW)


  send_data(coreTemperatureValue)

  time.sleep(5)
  GPIO.cleanup







  # "http://192.168.0.12:8080/json.htm?type=command&param=udevice&idx=19&nvalue=0&svalue=2"

# http://192.168.0.12:8080/json.htm?type=devices&rid=19
# http://192.168.0.12:8080/json.htm?type=devices&rid=22

# blink_thread = threading.Thread(target=cycle_task)
# blink_thread.start()

# while(1):
#   pass

# url = "http://" + serverIP + "/json.htm?type=command&param=udevice&idx=" + str(
#   dummy_light_sens_id) + "&nvalue=0&svalue=" + str(sensors[0]["val"])
# response = http.request('GET', url)
# soup = BeautifulSoup(response.data)

# global green

Czyli 🌶️ patrząc na początek na ten fragment:

serverIP = "192.168.0.12:8080"
dummy_rgb_id = 22
url = "http://" + serverIP + "/json.htm?type=devices&rid=" + str(dummy_rgb_id)

Tu masz adres Domoticza i port z którym się komunikujesz - adres będziesz miał podobny ale inny. Skrypt i serwer Domoticza działają na jednym RPi.

image.thumb.png.f60848e0c666108b30103e4722bbc58b.png

Kolejna linia to id kontrolera - dopisałem dummy bo to jest wirtualny element wykonawczy, czyli taki który operuje na samym kodzie ale nic sie w praktyce nie rusza/świeci/odczytuje itp. Najpierw w panelu robisz dummy hardware a do niego doczepiasz device np taki kontroler RGB. To chyba jest opisane w kursie.

Na koniec jest linijka wynikająca z API Domoticza służąca do dostępu do plików związanych z kontrolerem (mam tu na myśli coś z panelu np. dummy RGB).

import board
import neopixel
PIEXELS_COUNT=1
pixels = neopixel.NeoPixel(board.D18, PIEXELS_COUNT, brightness=1.0, auto_write=False)

##########################

def updateColorValues():
    global brightness
    global red
    global green
    global blue

    while True:
        print("Acquiring colour data...")
        try:
            response = urlopen(url)
            # Convert bytes to string type and string type to dict
            string = response.read().decode('utf-8')
            json_obj = json.loads(string)

            brightnessRaw = json_obj['result'][0]['Status']
            paresedBrightness = re.findall(r'\d+', brightnessRaw)
            if len(paresedBrightness) > 0:
                brightness = int(paresedBrightness[0])

            colorRaw = json_obj['result'][0]['Color']
            # print(colorRaw)
            color = ast.literal_eval(colorRaw)
            # print(color)

            red = color['r']
            green = color['g']
            blue = color['b']

            print("Get: {}, {}, {}, brightness {}".format(red, green, blue, brightness))

            pixels.brightness = float(brightness / 100.0)
            pixels.fill((red, green, blue))
            pixels.show()

            time.sleep(0.5)
        except URLError as e:
            print('Meh HTTPError = ' + str(e) + " trying to reconnect in 5 seconds...")
            time.sleep(5)
        except Exception:
            import traceback
            print('generic exception: ' + traceback.format_exc())

Może to wyglądać na trudne ale ten kod jest bardzo prosty. Na początku obiekt związany z paskiem LED, później pętla i blok przechwytywania wyjątków jakby zerwalo się połaczenie. To wszystko kręci się w osobnym wątku. Wewnątrz pobierane są dane z API - Domoticz wystawia plik JSON z którego odczytujesz sobie aktualny stan kontrolera.

Jest to więc typowy polling - sprawdzasz cyklicznie czy coś się zmieniło. Oczywiście da się to zrobić inaczej, da się nauczyć LUA, napisać skrypt Domoticza, coś w tym wydziergać ale i tak nie jest źle. Tylko to nie jest zabawa niejeden wieczór... ja chyba spędziłem przy tym z kilka godzin, przy czym znałem już dość dobrze Pythona, tematy webowe i konfiguracje sprzętu w Domoticzu 😞 więc cóż, good luck!

 

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dzięki wielkie za tak obszerną odpowiedź wraz z kodem! 🙂 Przysiądę pewnie do tego w weekend i ogarnę co i jak, ale tak na pierwszy rzut oka już widzę, że może być to dla mnie bardzo pomocne i w rzeczy samej rozwiązać mój problem. 

Dzięki raz jeszcze! 🙂 

Link do komentarza
Share on other sites

@cwietov powodzenia 🙂 tk popatrzyłem na gten kod i samo API jednak nie jest takie łatwe, pamiętam że długo szukałem może prostej sprawy ale gdzie jest svalue a gdzie coś innego:

ram=udevice&idx=" + str(deviceId) + "&svalue=" 

 

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.