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);
}
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);
}
}
}
}
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;
}
}
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);
}
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;
}
}
Aggregations