Search in sources :

Example 1 with AckMsg

use of org.openhab.binding.maxcul.internal.messages.AckMsg in project openhab1-addons by openhab.

the class MaxCulMsgHandler method sendAck.

/**
     * Send an ACK response to a message
     * 
     * @param msg
     *            Message we are acking
     */
public void sendAck(BaseMsg msg) {
    AckMsg ackMsg = new AckMsg(msg.msgCount, (byte) 0x0, msg.groupid, this.srcAddr, msg.srcAddrStr, false);
    // all ACKs are sent to waiting device.
    ackMsg.setFastSend(true);
    sendMessage(ackMsg);
}
Also used : AckMsg(org.openhab.binding.maxcul.internal.messages.AckMsg)

Example 2 with AckMsg

use of org.openhab.binding.maxcul.internal.messages.AckMsg in project openhab1-addons by openhab.

the class MaxCulMsgHandler method dataReceived.

@Override
public void dataReceived(String data) {
    logger.debug("MaxCulSender Received " + data);
    if (data.startsWith("Z")) {
        if (listenMode) {
            listenModeHandler(data);
            return;
        }
        /* Check message is destined for us */
        if (BaseMsg.isForUs(data, srcAddr)) {
            boolean passToBinding = true;
            /* Handle Internal Messages */
            MaxCulMsgType msgType = BaseMsg.getMsgType(data);
            if (msgType == MaxCulMsgType.ACK) {
                passToBinding = false;
                AckMsg msg = new AckMsg(data);
                if (pendingAckQueue.containsKey(msg.msgCount) && msg.dstAddrStr.compareTo(srcAddr) == 0) {
                    SenderQueueItem qi = pendingAckQueue.remove(msg.msgCount);
                    /* verify ACK */
                    if ((qi.msg.dstAddrStr.equalsIgnoreCase(msg.srcAddrStr)) && (qi.msg.srcAddrStr.equalsIgnoreCase(msg.dstAddrStr))) {
                        if (msg.getIsNack()) {
                            /* NAK'd! */
                            // TODO resend?
                            logger.error("Message was NAK'd, packet lost");
                        } else {
                            logger.debug("Message " + msg.msgCount + " ACK'd ok!");
                        }
                    }
                } else {
                    logger.info("Got ACK for message " + msg.msgCount + " but it wasn't in the queue");
                }
            }
            if (sequenceRegister.containsKey(new BaseMsg(data).msgCount)) {
                passToBinding = false;
                /*
                     * message found in sequence register, so it will be handled
                     * by the sequence
                     */
                BaseMsg bMsg = new BaseMsg(data);
                logger.debug("Message " + bMsg.msgCount + " is part of sequence. Running next step in sequence.");
                sequenceRegister.get(bMsg.msgCount).runSequencer(bMsg);
                sequenceRegister.remove(bMsg.msgCount);
            }
            if (passToBinding) {
                /* pass data to binding for processing */
                this.mcbmp.maxCulMsgReceived(data, false);
            }
        } else if (BaseMsg.isForUs(data, "000000")) {
            switch(BaseMsg.getMsgType(data)) {
                case PAIR_PING:
                case WALL_THERMOSTAT_CONTROL:
                case THERMOSTAT_STATE:
                case WALL_THERMOSTAT_STATE:
                    this.mcbmp.maxCulMsgReceived(data, true);
                    break;
                default:
                    /* TODO handle other broadcast */
                    logger.debug("Unhandled broadcast message of type " + BaseMsg.getMsgType(data).toString());
                    break;
            }
        } else {
            // Associated devices send messages that tell of their status to
            // the associated
            // device. We need to spy on devices we know about to extract
            // useful data
            boolean passToBinding = false;
            BaseMsg bMsg = new BaseMsg(data);
            for (MaxCulBindingProvider provider : providers) {
                // look up source device configs
                List<MaxCulBindingConfig> configs = provider.getConfigsForRadioAddr(bMsg.srcAddrStr);
                if (!configs.isEmpty()) {
                    // get asssociated devices with source device
                    String serialNum = configs.get(0).getSerialNumber();
                    HashSet<MaxCulBindingConfig> assocDevs = provider.getAssociations(serialNum);
                    if (!assocDevs.isEmpty()) {
                        // message dest
                        for (MaxCulBindingConfig device : assocDevs) {
                            if (device.getDevAddr().equalsIgnoreCase(bMsg.dstAddrStr)) {
                                passToBinding = true;
                                break;
                            }
                        }
                    }
                }
            }
            if (passToBinding && (BaseMsg.getMsgType(data) != MaxCulMsgType.PAIR_PING && BaseMsg.getMsgType(data) != MaxCulMsgType.ACK)) {
                /*
                     * pass data to binding for processing - pretend it is
                     * broadcast so as not to ACK
                     */
                this.mcbmp.maxCulMsgReceived(data, true);
            }
        }
    }
}
Also used : BaseMsg(org.openhab.binding.maxcul.internal.messages.BaseMsg) AckMsg(org.openhab.binding.maxcul.internal.messages.AckMsg) MaxCulBindingProvider(org.openhab.binding.maxcul.MaxCulBindingProvider) LinkedList(java.util.LinkedList) List(java.util.List) MaxCulMsgType(org.openhab.binding.maxcul.internal.messages.MaxCulMsgType) HashSet(java.util.HashSet)

Example 3 with AckMsg

use of org.openhab.binding.maxcul.internal.messages.AckMsg in project openhab1-addons by openhab.

the class MaxCulMsgHandler method listenModeHandler.

private void listenModeHandler(String data) {
    switch(BaseMsg.getMsgType(data)) {
        case WALL_THERMOSTAT_CONTROL:
            new WallThermostatControlMsg(data).printMessage();
            break;
        case TIME_INFO:
            new TimeInfoMsg(data).printMessage();
            break;
        case SET_TEMPERATURE:
            new SetTemperatureMsg(data).printMessage();
            break;
        case ACK:
            new AckMsg(data).printMessage();
            break;
        case PAIR_PING:
            new PairPingMsg(data).printMessage();
            break;
        case PAIR_PONG:
            new PairPongMsg(data).printMessage();
            break;
        case THERMOSTAT_STATE:
            new ThermostatStateMsg(data).printMessage();
            break;
        case SET_GROUP_ID:
            new SetGroupIdMsg(data).printMessage();
            break;
        case WAKEUP:
            new WakeupMsg(data).printMessage();
            break;
        case WALL_THERMOSTAT_STATE:
            new WallThermostatStateMsg(data).printMessage();
            break;
        case ADD_LINK_PARTNER:
        case CONFIG_TEMPERATURES:
        case CONFIG_VALVE:
        case CONFIG_WEEK_PROFILE:
        case PUSH_BUTTON_STATE:
        case REMOVE_GROUP_ID:
        case REMOVE_LINK_PARTNER:
        case RESET:
        case SET_COMFORT_TEMPERATURE:
        case SET_DISPLAY_ACTUAL_TEMP:
        case SET_ECO_TEMPERATURE:
        case SHUTTER_CONTACT_STATE:
        case UNKNOWN:
        default:
            BaseMsg baseMsg = new BaseMsg(data);
            baseMsg.printMessage();
            break;
    }
}
Also used : WallThermostatStateMsg(org.openhab.binding.maxcul.internal.messages.WallThermostatStateMsg) PairPongMsg(org.openhab.binding.maxcul.internal.messages.PairPongMsg) PairPingMsg(org.openhab.binding.maxcul.internal.messages.PairPingMsg) BaseMsg(org.openhab.binding.maxcul.internal.messages.BaseMsg) SetTemperatureMsg(org.openhab.binding.maxcul.internal.messages.SetTemperatureMsg) ThermostatStateMsg(org.openhab.binding.maxcul.internal.messages.ThermostatStateMsg) WallThermostatStateMsg(org.openhab.binding.maxcul.internal.messages.WallThermostatStateMsg) TimeInfoMsg(org.openhab.binding.maxcul.internal.messages.TimeInfoMsg) AckMsg(org.openhab.binding.maxcul.internal.messages.AckMsg) WallThermostatControlMsg(org.openhab.binding.maxcul.internal.messages.WallThermostatControlMsg) SetGroupIdMsg(org.openhab.binding.maxcul.internal.messages.SetGroupIdMsg) WakeupMsg(org.openhab.binding.maxcul.internal.messages.WakeupMsg)

Example 4 with AckMsg

use of org.openhab.binding.maxcul.internal.messages.AckMsg in project openhab1-addons by openhab.

the class MaxCulMsgHandler method sendNack.

/**
     * Send an NACK response to a message
     * 
     * @param msg
     *            Message we are nacking
     */
public void sendNack(BaseMsg msg) {
    AckMsg nackMsg = new AckMsg(msg.msgCount, (byte) 0x0, msg.groupid, this.srcAddr, msg.srcAddrStr, false);
    // all NACKs are sent to waiting device.
    nackMsg.setFastSend(true);
    sendMessage(nackMsg);
}
Also used : AckMsg(org.openhab.binding.maxcul.internal.messages.AckMsg)

Example 5 with AckMsg

use of org.openhab.binding.maxcul.internal.messages.AckMsg in project openhab1-addons by openhab.

the class PairingInitialisationSequence method runSequencer.

@Override
public void runSequencer(BaseMsg msg) {
    /*
         * This sequence is taken from observations of activity between the MAX!
         * Cube and a wall thermostat and refined using some experimentation :)
         */
    if (state != PairingInitialisationState.RETX_WAKEUP_ACK) {
        // reset counter - ack received
        pktLostCount = 0;
    }
    logger.debug("Sequence State: " + state);
    switch(state) {
        case INITIAL_PING:
            /* get device type */
            PairPingMsg ppMsg = new PairPingMsg(msg.rawMsg);
            this.deviceType = MaxCulDevice.getDeviceTypeFromInt(ppMsg.type);
            /* Send PONG - assumes PING is checked */
            logger.debug("Sending PONG");
            this.devAddr = msg.srcAddrStr;
            messageHandler.sendPairPong(devAddr, this);
            state = PairingInitialisationState.PONG_ACKED;
            break;
        case PONG_ACKED:
            if (msg.msgType == MaxCulMsgType.ACK) {
                AckMsg ack = new AckMsg(msg.rawMsg);
                if (!ack.getIsNack()) {
                    if (this.deviceType == MaxCulDevice.PUSH_BUTTON) {
                        /* for a push button we're done now */
                        state = PairingInitialisationState.FINISHED;
                    } else {
                        /* send group id information */
                        logger.debug("Sending GROUP_ID");
                        messageHandler.sendSetGroupId(devAddr, group_id, this);
                        state = PairingInitialisationState.GROUP_ID_ACKED;
                    }
                } else {
                    logger.error("PAIR_PONG was nacked. Ending sequence");
                    state = PairingInitialisationState.FINISHED;
                }
            } else {
                logger.error("Received " + msg.msgType + " when expecting ACK");
            }
            break;
        case GROUP_ID_ACKED:
            if (msg.msgType == MaxCulMsgType.ACK) {
                AckMsg ack = new AckMsg(msg.rawMsg);
                if (!ack.getIsNack() && (this.deviceType == MaxCulDevice.RADIATOR_THERMOSTAT || this.deviceType == MaxCulDevice.WALL_THERMOSTAT || this.deviceType == MaxCulDevice.RADIATOR_THERMOSTAT_PLUS)) {
                    // send temps for comfort/eco etc
                    messageHandler.sendConfigTemperatures(devAddr, this, config.getComfortTemp(), config.getEcoTemp(), config.getMaxTemp(), config.getMinTemp(), config.getMeasurementOffset(), config.getWindowOpenTemperature(), config.getWindowOpenDuration());
                    state = PairingInitialisationState.CONFIG_TEMPS_ACKED;
                } else {
                    logger.error("SET_GROUP_ID was nacked. Ending sequence");
                    state = PairingInitialisationState.FINISHED;
                }
            } else {
                logger.error("Received " + msg.msgType + " when expecting ACK");
            }
            break;
        case CONFIG_TEMPS_ACKED:
            if (msg.msgType == MaxCulMsgType.ACK) {
                AckMsg ack = new AckMsg(msg.rawMsg);
                if (!ack.getIsNack()) {
                    /*
                         * associate device with us so we get updates - we pretend
                         * to be the MAX! Cube
                         */
                    messageHandler.sendAddLinkPartner(devAddr, this, msg.dstAddrStr, MaxCulDevice.CUBE);
                    /*
                         * if there are more associations to come then set up
                         * iterator and goto state to transmit more associations
                         */
                    if (associations != null && associations.isEmpty() == false) {
                        assocIter = associations.iterator();
                        state = PairingInitialisationState.SENDING_ASSOCIATIONS;
                    } else {
                        logger.debug("No user configured associations");
                        state = PairingInitialisationState.SENDING_ASSOCIATIONS_ACKED;
                    }
                } else {
                    logger.error("CONFIG_TEMPERATURES was nacked. Ending sequence");
                    state = PairingInitialisationState.FINISHED;
                }
            } else {
                logger.error("Received " + msg.msgType + " when expecting ACK");
            }
            break;
        case SENDING_ASSOCIATIONS:
            if (msg.msgType == MaxCulMsgType.ACK) {
                AckMsg ack = new AckMsg(msg.rawMsg);
                if (!ack.getIsNack()) {
                    if (assocIter.hasNext()) /*
                                                  * this should always be true, but
                                                  * good to check
                                                  */
                    {
                        MaxCulBindingConfig partnerCfg = assocIter.next();
                        messageHandler.sendAddLinkPartner(this.devAddr, this, partnerCfg.getDevAddr(), partnerCfg.getDeviceType());
                        /*
                             * if it's the last association message then wait for
                             * last ACK
                             */
                        if (assocIter.hasNext()) {
                            state = PairingInitialisationState.SENDING_ASSOCIATIONS;
                        } else {
                            state = PairingInitialisationState.SENDING_ASSOCIATIONS_ACKED;
                        }
                    } else {
                        // TODO NOTE: if further states are added then ensure
                        // you go to the right state. I.e. when all associations
                        // are done
                        state = PairingInitialisationState.FINISHED;
                    }
                } else {
                    logger.error("SENDING_ASSOCIATIONS was nacked. Ending sequence");
                    state = PairingInitialisationState.FINISHED;
                }
            } else {
                logger.error("Received " + msg.msgType + " when expecting ACK");
            }
            break;
        case SENDING_ASSOCIATIONS_ACKED:
            state = PairingInitialisationState.FINISHED;
            break;
        case SENDING_WEEK_PROFILE:
            // TODO implement this - but where to get a week profile from.
            // Meaningless at the moment!
            state = PairingInitialisationState.FINISHED;
            break;
        case FINISHED:
            /* done, do nothing */
            break;
        case RETX_WAKEUP_ACK:
            /* here are waiting for an ACK after sending a wakeup message */
            if (msg.msgType == MaxCulMsgType.ACK) {
                AckMsg ack = new AckMsg(msg.rawMsg);
                if (!ack.getIsNack()) {
                    logger.debug("Attempt retransmission - resuming");
                    this.useFast = true;
                    messageHandler.sendMessage(reTxMsg);
                    // resume back to previous state
                    state = reTxState;
                } else {
                    logger.error("WAKEUP for ReTx was nacked. Ending sequence");
                    state = PairingInitialisationState.FINISHED;
                }
            } else {
                logger.error("Received " + msg.msgType + " when expecting ACK");
            }
            break;
        default:
            logger.error("Invalid state for PairingInitialisation Message Sequence!");
            break;
    }
}
Also used : PairPingMsg(org.openhab.binding.maxcul.internal.messages.PairPingMsg) AckMsg(org.openhab.binding.maxcul.internal.messages.AckMsg) MaxCulBindingConfig(org.openhab.binding.maxcul.internal.MaxCulBindingConfig)

Aggregations

AckMsg (org.openhab.binding.maxcul.internal.messages.AckMsg)6 BaseMsg (org.openhab.binding.maxcul.internal.messages.BaseMsg)2 PairPingMsg (org.openhab.binding.maxcul.internal.messages.PairPingMsg)2 TimeInfoMsg (org.openhab.binding.maxcul.internal.messages.TimeInfoMsg)2 GregorianCalendar (java.util.GregorianCalendar)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 MaxCulBindingProvider (org.openhab.binding.maxcul.MaxCulBindingProvider)1 MaxCulBindingConfig (org.openhab.binding.maxcul.internal.MaxCulBindingConfig)1 MaxCulMsgType (org.openhab.binding.maxcul.internal.messages.MaxCulMsgType)1 PairPongMsg (org.openhab.binding.maxcul.internal.messages.PairPongMsg)1 SetGroupIdMsg (org.openhab.binding.maxcul.internal.messages.SetGroupIdMsg)1 SetTemperatureMsg (org.openhab.binding.maxcul.internal.messages.SetTemperatureMsg)1 ThermostatStateMsg (org.openhab.binding.maxcul.internal.messages.ThermostatStateMsg)1 WakeupMsg (org.openhab.binding.maxcul.internal.messages.WakeupMsg)1 WallThermostatControlMsg (org.openhab.binding.maxcul.internal.messages.WallThermostatControlMsg)1 WallThermostatStateMsg (org.openhab.binding.maxcul.internal.messages.WallThermostatStateMsg)1