def tcpClientTest():
	ipAddress = "192.168.1.107"
	port = 6000
	client = TcpClient(ipAddress, port)
	print("Trying to connect...")
	client.connect()
	print("Connected...")
	while True:
		message = client.read();
		if len(message) > 0:
			header = "Server: "
			print(header + message)
class OTGWBridge:

    def __init__(self, config):
        self.__otgwClient = TcpClient(config['otgw']['host'], int(config['otgw']['port']))
        self.__otgw = OTGW()
        self.__otgw_worker_thread = None
        self.__config = config
        self.__oled = OledController(config['oled']['host'])

    def run(self):
        if self.__otgw_worker_thread:
            raise RuntimeError("Already running")
        self.__otgw_worker_thread = Thread(target=self.__otgw_worker)
        self.__otgw_worker_thread.start()
        self.__oled.start()
        self.__run_mqtt()

    def __run_mqtt(self):
        def on_mqtt_connect(client, userdata, flags, rc):
            # Subscribe to all topics in our namespace when we're connected. Send out
            # a message telling we're online
            log.info("Connected with result code " + str(rc))
            client.subscribe('{}/#'.format(self.__config['mqtt']['set_topic_namespace']))
            client.publish(
                topic=self.__config['mqtt']['value_topic_namespace'],
                payload="online",
                qos=self.__config['mqtt']['qos'],
                retain=self.__config['mqtt']['retain'])

        mqttc = mqtt.Client("otgw", clean_session=False)
        if self.__config['mqtt']['username']:
            mqttc.username_pw_set(self.__config["mqtt"]["username"], self.__config["mqtt"]["password"])
        mqttc.connect(self.__config["mqtt"]["host"], self.__config["mqtt"]["port"])

        def on_disconnect(client, userdata, rc):
            if rc != 0:
                log.warning("Unexpected MQTT disconnection. Will auto-reconnect")

        mqttc.on_connect = on_mqtt_connect
        mqttc.on_message = self.__on_mqtt_message
        mqttc.on_disconnect = on_disconnect
        mqttc.will_set(
            topic=self.__config['mqtt']['value_topic_namespace'],
            payload="offline",
            qos=self.__config['mqtt']['qos'],
            retain=True)

        self.__mqttc = mqttc
        mqttc.loop_forever()

    def __on_mqtt_message(self, client, userdata, msg):
        log.debug("Received message on topic {} with payload {}".format(msg.topic, str(msg.payload)))
        command_generators = {
            "set/otgw/room_setpoint/temporary": lambda _: "TT={:.2f}".format(float(_)),
            "set/otgw/room_setpoint/constant": lambda _: "TC={:.2f}".format(float(_)),
            "set/otgw/control_setpoint/temperature": lambda _: "CS={:.2f}".format(float(_)),
            "set/otgw/outside_temperature": lambda _: "OT={:.2f}".format(float(_)),
            "set/otgw/hot_water/enable": lambda _: "HW={}".format('1' if _ in self.__true_values else '0'),
            "set/otgw/hot_water/temperature": lambda _: "SW={:.2f}".format(float(_)),
            "set/otgw/central_heating/enable": lambda _: "CH={}".format('1' if _ in self.__true_values else '0'),
        }
        # Find the correct command generator from the dict above
        command_generator = command_generators.get(msg.topic)
        if command_generator:
            # Get the command and send it to the OTGW
            command = command_generator(msg.payload)
            self.__otgw.send_command(command)

    __true_values = ('True', 'true', '1', 'y', 'yes')
    __lastThermostatValues = {}

    def __thermostat_first(self, msg):
        if msg.msg in ["dhw_setpoint", "control_setpoint"]:
            if msg.msg in self.__lastThermostatValues and msg.thermostatSrc.value != self.__lastThermostatValues[msg.msg]:
                if msg.msg == "dhw_setpoint":
                    command = "SW=0"
                if msg.msg == "control_setpoint":
                    command = "CS=0"
                self.__otgw.send_command(command)
            self.__lastThermostatValues[msg.msg] = msg.thermostatSrc.value

    def __on_otgw_message(self, message):
        if config["otgw"]["thermostatFirst"]:
            self.__thermostat_first(message)
        # if message.msg:
        #     print(message)
        for msg in self.__otgw_translate_message(message):
            log.debug("Sending message to topic {} value {}".format(msg[1], msg[2]))
            self.__mqttc.publish(
                topic=msg[1],
                payload=msg[2],
                qos=config['mqtt']['qos'],
                retain=config['mqtt']['retain'])

    def __otgw_translate_message(self, message):
        def extractBit(value, number):
            rev = value[::-1]
            try:
                return str(rev[number] == "1")
            except:
                return str(False)
        if message.msg and message.boilerSrc and message.thermostatSrc:
            msg = message.msg
            topic = "{}/{}".format(self.__config['mqtt']['value_topic_namespace'], msg)
            value = message.boilerSrc.value

            if msg == "status":
                #value.
                return iter([
                    (msg, "{}/fault".format(topic), extractBit(value, 0)),
                    (msg, "{}/ch_active".format(topic), extractBit(value, 1)),
                    (msg, "{}/dhw_active".format(topic), extractBit(value, 2)),
                    (msg, "{}/flame".format(topic), extractBit(value, 3)),
                ])
            else:
                return iter([(msg, topic, value)])
        else:
            return iter([])

    def __otgw_worker(self):
        self._worker_running = True

        line_regex = re.compile(r'^.*[\r\n]+')

        buffer = ""
        while self._worker_running:
            buffer += self.__otgwClient.read()
            # Find all the lines in the read data
            while True:
                m = line_regex.match(buffer)
                if not m:
                    break
                line = m.group().rstrip('\r\n')
                # log.info("Line: {}".format(line))
                operation = self.__otgw.processLine(line)
                if operation:
                    try:
                        if isinstance(operation, OTGW.Message):
                            self.__on_otgw_message(message=operation)
                            self.__oled.on_otgw_message(msg=operation)
                        elif isinstance(operation, OTGW.Command):
                            if not operation.processed:
                                log.info("Sending command: '{}'".format(operation.command))
                                self.__otgwClient.write(operation.command)
                                operation.sent = time.time()
                            else:
                                log.info("Processed command: {}".format(operation))
                    except Exception as e:
                        log.warning(str(e))

                # Strip the consumed line from the buffer
                buffer = buffer[m.end():]

        self._worker_thread = None