/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.dsmr.internal.messages;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.openhab.binding.dsmr.internal.DSMRMeter;
import org.openhab.binding.dsmr.internal.DSMRMeterType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Factory for constructing OBIS messages from Strings
*
* @author M. Volaart
* @since 1.7.0
*/
public class OBISMsgFactory {
/* logger */
private static final Logger logger = LoggerFactory.getLogger(OBISMsgFactory.class);
/* internal lookup cache */
private final HashMap<OBISIdentifier, List<OBISMsgType>> obisLookupTable;
/**
* Creates a new OBISMsgFactory
*
* @param dsmrMeters
* available DSMR meters (see {@link DSMRMeter}) in the binding
*/
public OBISMsgFactory(List<DSMRMeter> dsmrMeters) {
/*
* Fill a lookup table with OBIS message types based on the specified
* channel - MeterType mapping
*/
obisLookupTable = new HashMap<OBISIdentifier, List<OBISMsgType>>();
// Create a convenience lookup table for a channel based on meter type
Map<DSMRMeterType, Integer> meterChannelMapping = new HashMap<DSMRMeterType, Integer>();
for (DSMRMeter meter : dsmrMeters) {
meterChannelMapping.put(meter.getMeterType(), meter.getChannel());
}
fillLookupTable(meterChannelMapping);
}
/**
* Return OBISMessage from specified string or null if string couldn't be
* parsed correctly or no corresponding OBISMessage was found
*
* @param obisIdString
* String containing the OBIS message identifier
* @param cosemStringValues
* LinkedList of String containing Cosem values
* @return OBISMessage or null if parsing failed
*/
public OBISMessage getMessage(String obisIdString, LinkedList<String> cosemStringValues) {
OBISIdentifier obisId = null;
OBISIdentifier reducedObisId = null;
try {
obisId = new OBISIdentifier(obisIdString);
reducedObisId = obisId.getReducedOBISIdentifier();
} catch (ParseException pe) {
logger.error("Received invalid OBIS identifier: {}", obisIdString);
return null;
}
logger.debug("Received obisIdString {}, obisId: {}, values: {}", obisIdString, obisId, cosemStringValues);
if (obisLookupTable.containsKey(reducedObisId)) {
List<OBISMsgType> compatibleMsgTypes = obisLookupTable.get(reducedObisId);
OBISMessage msg = null;
logger.debug("Found {} compatible message type(s)", compatibleMsgTypes.size());
for (OBISMsgType msgType : compatibleMsgTypes) {
msg = new OBISMessage(msgType);
try {
logger.debug("Parse values for OBIS Message type: {}", msgType);
msg.parseCosemValues(cosemStringValues);
return msg;
} catch (ParseException pe) {
logger.debug("Failed to parse OBIS identifier {}, values: {} for type {} ", obisId,
cosemStringValues, msgType, pe);
}
}
logger.error("Failed to parse OBIS identifier {}, values: {}", obisId, cosemStringValues);
} else {
logger.warn("Received OBIS unknown message: {}", obisId);
}
return null;
}
/**
* This method fills a lookup table with the OBIS message types based on the
* mapping channel - {@link DSMRMeterType}
* <p>
*
* @param mapping
* DSMRMeterType - channel mapping
*/
private void fillLookupTable(Map<DSMRMeterType, Integer> mapping) {
for (OBISMsgType t : OBISMsgType.values()) {
OBISIdentifier obisId = t.obisId;
if (obisId.getGroupB() == null) {
DSMRMeterType meterType = t.meterType;
if (mapping.containsKey(meterType)) {
/*
* OBIS-identifier contains a variable channel Check if the
* configuration contains the mapping for this meter type
* and then make the OBIS-identifier specific
*/
Integer channel = mapping.get(t.meterType);
logger.debug("Change OBIS-identifier {} for meter {} on channel {}", t.obisId, t.meterType,
channel);
obisId = new OBISIdentifier(obisId.getGroupA(), channel, obisId.getGroupC(), obisId.getGroupD(),
obisId.getGroupE(), obisId.getGroupF());
} else {
logger.debug("Mapping does not contain a channel for {}", meterType);
obisId = null;
}
}
if (obisId != null) {
if (!obisLookupTable.containsKey(obisId)) {
obisLookupTable.put(obisId, new LinkedList<OBISMsgType>());
}
obisLookupTable.get(obisId).add(t);
}
}
}
}