P5FutureNow FNIP-4xSH einbinden

Hallo in die Runde,

ich nehme es mal vorweg. Ich arbeite mich gerade in HA ein und bin noch ganz am Anfang.

Ich habe bei mir im Haus 4 Futurenow FNIP-4xSH Module zur Jalousiesteuerung verbaut und möchte diese jetzt einbinden.
leider musste ich feststellen das dies ohne große yaml Kenntnisse erstmal schwierig sein wird.

nun meine Frage ob mir da jemand Hilfestellung geben kann? Oder Erfahrungen hat?

SG

Martin

@marhent

morgen Martin, ich hab mir mal die Dokumentation von den Teilen angesehen und dazu noch die ha Doku: https://www.home-assistant.io/integrations/futurenow/

weder in der Dokumentation noch in der Unterstützten Geräte Liste von HA tauchen die Geräte auf.

Die Steuerung ist aut-ark mit integriertem Webserver.

hast du dich den genügend darüber informiert im Netz ob diese Teile nur im Ansatz mit HA kompatibel sind bzw. Ob irgendjemand diese Teile verwendet und über HA eine Steuerung realisiert hatte?

@firewall68

Guten Morgen,

vorab Danke schon mal für deine Mühe.

Ich muss zu meiner Schande gestehen das ich da wohl etwas blauäugig ran gegangen bin. Ich habe die Controller schon etwas länger verbaut und wollte die per AMX ansteuern aber bin nun auf HA gekommen. Hatte angenommen das diese verbreiteter sind.

Gibt es alternativen oder Schnittstellen das ich den eigenen Webserver ansprechen kann?

SG

Martin

@marhent

sieh dir mal das neuestes Video von @simon42 an, vielleicht ist da etwas dabei. bin gerade am anschauen, aber eventuell kannst du per HA "Scrape" etwas auslesen.

ah ok.
habe in der zwischenzeit den Support von P5 kontaktiert und die haben mir gesagt das das eigentlich mit jedem Modul möglich ist.

https://www.dropbox.com/sh/emj5h1vdus0bo0x/AABwJWPJvoNEklQOi2CG8v9ka?dl=0

Zu dem Modul konnte ich auch ein config Ordner runterladen. Jedoch stehe ich wie gesagt mit yaml und HA noch ganz am Anfang. Wenn das Grundsätzlich die richtigen komponenten sind um das ans laufen zu bekommen wäre ich schon mal sehr erleichtert.

nun muss ich nur schauen ob ich das zeitnah umgesetzt bekomme und mir selber draufschaffen kann.

SG

Martin

so jetzt versuche ich nochmal das Thema für mich anzugehen.
wie gesagt scheine ich wohl alles nötige bzgl. der P5 Module vom Hersteller bekommen zu haben, jedoch scheitert es an meinem Yaml Skills etwas.( stehe noch ganz am Anfang und glaube das dies für längere Zeit ohne Hilfe nicht umsetzbar sein wird für mich. böhmische Dörfer!)

hier mal code Auszüge die ich so vom Hersteller für HA bekommen habe ( mehre )

binary_sensor

#FutureNow FNIP-4xSH
import voluptuous as vol
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP
import homeassistant.helpers.config_validation as cv
from threading import Thread
import string
import re
import queue
import socket
import uuid
from datetime import datetime
from time import sleep
import logging

CONF_CHANNELS = "channels"
CONF_MODULES = "modules"
DEFAULT_PORT = 7078
DOMAIN = "fn_blind"

DATA_FN = "fn_blind"

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Required(CONF_MODULES): vol.Schema({cv.string: cv.string}),
                vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)

# A TCP socket client for communication with FutureNow devices

_LOGGER = logging.getLogger(__name__)


class MessageThread(Thread):
    # process responses & notifications and pipe data to callback(s)."""

    def __init__(self, fn_client):
        self.fn_client = fn_client
        self.stopped = False
        super(MessageThread, self).__init__()

    def run(self):
        while not self.stopped:
            try:
                # grab a message from queue
                message = self.fn_client.queue.get(True, 15)
                _LOGGER.debug("message thread: " + message)
            except queue.Empty:
                _LOGGER.debug("message thread: no messages")
               # close socket then reconnect if no replies to heartbeat are received
               # catch Exception "transport endpoint is not connected"
                self.fn_client.disconnect()
                self.fn_client.connect ()
                continue

            # make a copy of the current subscribers to keep this thread-safe
            current_subscribers = dict(self.fn_client.subscribers)
            
            #parsing
            while True:
                start = message.find("FN")
                end = message.find("\r")
                if end>start:
                    substring = message[start:end]
                    message =message.replace(message[start:end+1],"")
                    _LOGGER.debug ("FN rep " + substring)
                    command = re.match("FN,(\w+),", substring)
                    if command:
                        command = command.group(1)
                        if command == "LEV":
                            match = re.match ("FN,"+ command + ",(\d+),(\d+)", substring)
                            if match:
                                channel = match.group(1)
                                value = match.group(2)
                                value = int (value)
                                _LOGGER.info (self.fn_client.name + "LEV command received " + channel + ',' + str(value))
                        elif command  == 'OUT':
                            command='OUT,STOP' # this is what subscribers subscribe for
                            match = re.match ("FN,"+ command + ",(\d+),(\d+)", substring)
                            if match:
                                channel = match.group(1)
                                value = match.group(2)
                                value = int (value)
                                _LOGGER.debug (self.fn_client.name + " module OUT, STOP status feedback received")
                        elif command == 'IN':
                            #_LOGGER.debug ("IN status feedback received")
                            match = re.match ("FN,"+ command + ",(\w+),(\d+)", substring)
                            if match:
                                channel = match.group(2)
                                value = match.group(1)
                                if value == 'OFF':
                                    value = 0
                                elif value == 'ON':
                                    value =1
                        # update subscribers
                        if (channel != None) and (value != None) : # Int 0 would result in False if it was if channel and value
                            for subscriber_id in current_subscribers:
                                # msg or op should match what we asked for
                                #_LOGGER.debug ("subscribers ")
                                subscriber = current_subscribers[subscriber_id]
                                if command  == subscriber['command']:
                                    if channel == subscriber['channel']:
                                        _LOGGER.debug ("subscriber notified about change " + ', ' + self.name + ", " + command + ", "+ channel + ", " + str(value))
                                        subscriber['callback'](value)
                                        if subscriber['permanent'] is False: #if subscription was just for a one off event unsubscribe subscriber
                                            self.fn_client.unsubscribe(subscriber_id)
                else:
                    message = message.replace ('>',"")
                    break

            # signals to queue job is done
            self.fn_client.queue.task_done()


class ReceiveThread(Thread):
    # Receive data and push it to the queue

    def __init__(self, fn_client):
        self.fn_client = fn_client
        self.stopped = False
        Thread.__init__(self)

    def run(self):
        while not self.stopped:
            self.fn_client.receive()

class HeartBeatTimer(Thread):
    def __init__(self, fn_client):
        self.fn_client = fn_client
        self.stopped = False
        #self.stopped =Event()
        Thread.__init__(self)

    def run(self):
        #while not self.stopped.wait(3):
        while not self.stopped:
            self.fn_client.heart_beat()
            sleep(3)

class FNSocketClient(object):
    # A tcp client to connect to and maintain connection with the FN socket server 

    def __init__(self, host, port, name):
        self.queue = queue.Queue()
        self.subscribers = {}
        self._socket_recv = 1024 
        self.host = host
        self.port = port
        self.isConnected = False
        self.name = name
        self.connect ()
        
        self.message_thread = MessageThread(self)
        self.receive_thread = ReceiveThread(self)
        self.timer_thread = HeartBeatTimer(self)

        self.receive_thread.start()
        self.message_thread.start()
        self.timer_thread.start()
        
    def connect(self):
        while True:
            try:
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.settimeout(None)
                self.socket.connect((self.host, self.port))
                _LOGGER.debug ('connected to: ' + self.host + str(self.port))
                self.status_query('IN')
                self.status_query("OUT")
                self.isConnected = True
                break
            except Exception as e:
                _LOGGER.debug ('Connection failed')
                sleep(5)
            
    def disconnect (self):
        self.socket.close()
        self.isConnected = False
        _LOGGER.debug ("disconnected")
        
    def heart_beat(self):
        if self.isConnected:
            self.send ("a\r")

    def subscribe(self, command, channel, callback, permanent=False):
        # add subscribers
        subscriber_id = uuid.uuid4()
        self.subscribers[subscriber_id] = {'command': command,
                                           'channel': channel,
                                           'callback': callback,
                                           'permanent': permanent,
                                           'time_created': datetime.now()}

    def subscribe_notify(self, command, channel, callback):
        # subscribe a callback to a notification event
        self.subscribe(command, channel, callback, True)

    def unsubscribe(self, subscriber_id):
        # Unsubscribe a callback from an event
        self.subscribers.pop(subscriber_id)

    def send(self, data):
        # send message
        _LOGGER.debug("send: " + data)
        try:
            self.socket.send(data.encode('ascii'))
        except socket.error as e:
            _LOGGER.error(e)

    def receive(self):
        # receive data from socket
        while self.isConnected :
            try:
                # read data from the buffer
                data = self.socket.recv(self._socket_recv)
            except socket.timeout as e:
                _LOGGER.debug(e)
                sleep(1)
                return
            except socket.error as e:
                # Something else happened
                _LOGGER.error(e)
                return

            else:
                if len(data) == 0:
                    # no more data being transmitted
                    _LOGGER.info('orderly shutdown on server end')
                    return

                result = data.decode('ascii')
                self.queue.put(result)

    def quit(self):
        # stop all threads and close the socket
        self.receive_thread.stopped = True
        self.message_thread.stopped = True
        self.timer_thread.stopped = True

        self.receive_thread.join()
        _LOGGER.info('receive_thread exited')
        self.message_thread.join()
        _LOGGER.info('message_thread exited')
        self.timer_thread.join()
        _LOGGER.info('heartbeat_thread exited')
        self.socket.close()
        _LOGGER.info("socket closed")
        
    def status_query(self, out_in_select):
        #Read the status of digital inputs and outputs
        if out_in_select == 'OUT':
            self.send("FN,SRE\r\n")
            _LOGGER.info("querying output states")
        if out_in_select == 'IN':
            self.send("FN,SRI\r\n")
            _LOGGER.info("querying input states")
    
    def toggle_switch (self, module_address, callback_fn):
        self.send("FN,TOG," + module_address + "\r\n")
        
    def move_up(self, module_address, callback):
        #Moving the blind up
        self.send("FN,UP," + module_address + "\r\n")
        
    def move_down(self, module_address, callback):
        #Moving the blind down
        self.send("FN,DOWN," + module_address + "\r\n")
        
    def stop(self, module_address, callback):
        #Stopping the blind
        self.send("FN,STOP," + module_address + "\r\n")
        
    def go_to_position (self, module_address, pos, callback):
        self.send ("FN,GOTO," + module_address + "," + str(pos) + "\r\n")

def setup(hass, base_config):
    # Set up the fn_blind component
    config = base_config[DOMAIN]
    port = config[CONF_PORT]
    modules = config[CONF_MODULES]
    _LOGGER.info(modules.items())
    fn_device = {}
    hass.data[DATA_FN] = {}
    for name, ip_addr in modules.items():
        fn_device[name] = FNSocketClient(ip_addr, 7078, name)
        _LOGGER.info ("name " + name + ", ip address " + ip_addr)
        hass.data[DATA_FN][name] = FNDevice(hass, fn_device[name], name)
    #fn_device = FNSocketClient(host, port)
    
    def cleanup_fn(event):
        #stuff to do before stopping
        for module in modules:
            for name, ip_addr in module.items():
                fn_device[name].quit()

    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, cleanup_fn)
    return True


class FNDevice:
    # The fn_blind  component

    def __init__(self, hass, fn_device, name):
        self.hass = hass
        self.fn_device = fn_device
        self.name = name

    def status_query(self, out_in_select):
        # read the status of digital inputs and outputs
        self.fn_device.status_query(out_in_select)

    def move_up(self, ch_no, callback):
        # moving the blind up
        self.fn_device.move_up(ch_no, callback)
        
    def move_down(self, ch_no, callback):
        # moving the blind down
        self.fn_device.move_down(ch_no, callback)
        
    def stop(self, ch_no, callback):
        # stopping the blind 
        self.fn_device.stop(ch_no, callback)
        
    def toggle_switch (self, ch_no, callback):
        # toggle the blind
        self.fn_device.toggle_switch(ch_no, callback)
        
    def go_to_position (self, ch_no, pos, callback):
        #output goes to a certain position
        self.fn_device.go_to_position  (ch_no, pos, callback)

    def subscribe(self, command, ch_no, callback):
        self.fn_device.subscribe_notify (command, ch_no, callback)

Würde mich riesig freuen und erkenntlich zeigen wenn mich jemand bei dem Thema unterstützen könnte.

Hänge etwas in der Luft ;-)

Hallo @marhent

Ich bin in dem Thema kein Experte und möchte hier nur kurz meine Erfahrung teilen.
Hoffe dass du damit dann ein paar Dinge für dich ausprobieren kannst. :-)

Finde ich aber schonmal mega cool vom Hersteller dir den Code zur Verfügung zu stellen. Bin mir sicher, dass sie dir auch mit ein paar wenigen Worte beschreiben könnten was du machen musst.

Also ich habe das Add-On "wolf_ism8" eingerichtet.
Hier musste ich zuerst den Ordner "custom_components" erstellen (wenn nicht schon vorhanden) und dann einen Unterordner (kann man wohl benennen wie man möchte) erstellen.
Hier kommen dann die Dateien rein (__init__.py, binary_sensor.py, binary_sensor.py, ...).

Damit das ganze auch genutzt werden soll von HA muss ich jetzt noch in der configuration.yml folgendes eintragen:

wolf:
devices:
- HG1

Bei dir kann ich mir vorstellen dass du folgendes eingeben musst.

fn_blind:

Wegen: DOMAIN = "fn_blind"

Ob das korrekt ist? Keine Ahnung
Garantiert muss da noch viel mehr initial gesetzt werden.

Hoffe aber für dich, dass sich jemand findet der hier ein wenig mehr Klarheit schaffen kann :-)

@tower Danke dir für deine Hilfe.

Aber nun nach langer Zeit und durch klasse Support des Herstellers habe ich die Integration all meiner P5 Futurenow Module hinbekommen.

Kann diese nun empfehlen und lege jedem der Neu,-oder umbaut ans Herz.

Nun gehe ich weitere Themen in HA an. Die schon warten und auch spannend sind :-)

SG

Hallo Martin,

Wie kannst du diese Produkte empfehlen und jedem ans Herz legen wenn man für die Integration in HA lange Zeit braucht und sogar nur mit Hilfe des Herstellers voran kommt? Das wäre für mich eher abschreckend.

Ich meine das insbesondere vor dem Hintergrund das es ja auch Produkte wie Shelly 2.5 gibt, die sich mit einfachen Klicks integrieren lassen.

VG