Example #1
0
  /**
   * verifies response on availability of data
   *
   * @param response of heat pump
   * @param request request defined for heat pump response
   * @return Map of Strings with name and values
   */
  public Map<String, String> parseRecords(final byte[] response, Request request)
      throws StiebelHeatPumpException {

    Map<String, String> map = new HashMap<String, String>();

    logger.debug("Parse bytes: {}", DataParser.bytesToHex(response));

    if (response.length < 2) {
      logger.error(
          "response does not have a valid length of bytes: {}", DataParser.bytesToHex(response));
      return map;
    }

    // parse response and fill map
    for (RecordDefinition recordDefinition : request.getRecordDefinitions()) {
      try {
        String value = parseRecord(response, recordDefinition);
        logger.debug(
            "Parsed value {} -> {} with pos: {} , len: {}",
            recordDefinition.getName(),
            value,
            recordDefinition.getPosition(),
            recordDefinition.getLength());
        map.put(recordDefinition.getName(), value);
      } catch (StiebelHeatPumpException e) {
        continue;
      }
    }
    return map;
  }
Example #2
0
  /**
   * parses a single record
   *
   * @param response of heat pump
   * @param RecordDefinition that shall be used for parsing the heat pump response
   * @return string value of the parse response
   * @throws StiebelHeatPumpException
   */
  public String parseRecord(byte[] response, RecordDefinition recordDefinition)
      throws StiebelHeatPumpException {
    try {
      if (response.length < 2) {
        logger.error(
            "response does not have a valid length of bytes: {}", DataParser.bytesToHex(response));
        throw new StiebelHeatPumpException();
      }
      ByteBuffer buffer = ByteBuffer.wrap(response);
      short number = 0;
      byte[] bytes = null;

      switch (recordDefinition.getLength()) {
        case 1:
          bytes = new byte[1];
          System.arraycopy(response, recordDefinition.getPosition(), bytes, 0, 1);
          number = Byte.valueOf(buffer.get(recordDefinition.getPosition()));
          break;
        case 2:
          bytes = new byte[2];
          System.arraycopy(response, recordDefinition.getPosition(), bytes, 0, 2);
          number = buffer.getShort(recordDefinition.getPosition());
          break;
      }

      if (recordDefinition.getBitPosition() > 0) {

        int returnValue = getBit(bytes, recordDefinition.getBitPosition());
        return String.valueOf(returnValue);
      }

      if (recordDefinition.getScale() != 1.0) {
        double myDoubleNumber = number * recordDefinition.getScale();
        myDoubleNumber = Math.round(myDoubleNumber * 100.0) / 100.0;
        String returnString = String.format("%s", myDoubleNumber);
        return returnString;
      }

      return String.valueOf(number);
    } catch (Exception e) {
      logger.error(
          "response {} could not be parsed for record definition {} ",
          DataParser.bytesToHex(response),
          recordDefinition.getName());
      throw new StiebelHeatPumpException();
    }
  }
  private Object traverse(Node node)
      throws FlatwormUnsetFieldValueException, FlatwormConfigurationValueException {
    int type = node.getNodeType();
    if (type == Node.ELEMENT_NODE) {
      String nodeName = node.getNodeName();
      if (nodeName.equals("file-format")) {
        FileFormat f = new FileFormat();
        String encoding = Charset.defaultCharset().name();
        if (hasAttributeValueNamed(node, "encoding")) {
          encoding = getAttributeValueNamed(node, "encoding");
        }
        f.setEncoding(encoding);

        List<Object> children = getChildNodes(node);
        for (int i = 0; i < children.size(); i++) {
          if (children.get(i).getClass().equals(Converter.class)) {
            f.addConverter((Converter) children.get(i));
          }
          if (children.get(i).getClass().equals(Record.class)) {
            f.addRecord((Record) children.get(i));
          }
        }
        return f;
      }
      if (nodeName.equals("converter")) {
        Converter c = new Converter();
        c.setConverterClass(getAttributeValueNamed(node, "class"));
        c.setMethod(getAttributeValueNamed(node, "method"));
        c.setReturnType(getAttributeValueNamed(node, "return-type"));
        c.setName(getAttributeValueNamed(node, "name"));
        return c;
      }
      if (nodeName.equals("record")) {
        Record r = new Record();
        r.setName(getAttributeValueNamed(node, "name"));
        Node identChild = getChildElementNodeOfType("record-ident", node);
        if (identChild != null) {
          Node fieldChild = getChildElementNodeOfType("field-ident", identChild);
          Node lengthChild = getChildElementNodeOfType("length-ident", identChild);
          if (lengthChild != null) {
            r.setLengthIdentMin(Integer.parseInt(getAttributeValueNamed(lengthChild, "minlength")));
            r.setLengthIdentMax(Integer.parseInt(getAttributeValueNamed(lengthChild, "maxlength")));
            r.setIdentTypeFlag('L');
          } else if (fieldChild != null) {
            r.setFieldIdentStart(
                Integer.parseInt(getAttributeValueNamed(fieldChild, "field-start")));
            r.setFieldIdentLength(
                Integer.parseInt(getAttributeValueNamed(fieldChild, "field-length")));
            List<Node> matchNodes = getChildElementNodesOfType("match-string", fieldChild);
            for (int j = 0; j < matchNodes.size(); j++) {
              r.addFieldIdentMatchString(getChildTextNodeValue(matchNodes.get(j)));
            }
            r.setIdentTypeFlag('F');
          }
        }
        Node recordChild = getChildElementNodeOfType("record-definition", node);
        r.setRecordDefinition((RecordDefinition) traverse(recordChild));
        return r;
      }
      if (nodeName.equals("record-definition")) {
        RecordDefinition rd = new RecordDefinition();
        List<Object> children = getChildNodes(node);
        for (int i = 0; i < children.size(); i++) {
          Object o = children.get(i);
          if (o.getClass().equals(Bean.class)) {
            rd.addBeanUsed((Bean) o);
          }
          if (o.getClass().equals(Line.class)) {
            rd.addLine((Line) o);
          }
        }
        return rd;
      }
      if (nodeName.equals("bean")) {
        Bean b = new Bean();
        b.setBeanName(getAttributeValueNamed(node, "name"));
        b.setBeanClass(getAttributeValueNamed(node, "class"));
        try {
          b.setBeanObjectClass(Class.forName(b.getBeanClass()));
        } catch (ClassNotFoundException e) {
          throw new FlatwormConfigurationValueException("Unable to load class " + b.getBeanClass());
        }
        return b;
      }
      if (nodeName.equals("line")) {
        Line li = new Line();

        // JBL - Determine if this line is delimited
        // Determine value of quote character, default = "
        // These field is optional
        Node delimit = getAttributeNamed(node, "delimit");
        Node quote = getAttributeNamed(node, "quote");
        if (delimit != null) {
          li.setDelimeter(getAttributeValueNamed(node, "delimit"));
        }
        if (quote != null) {
          li.setQuoteChar(getAttributeValueNamed(node, "quote"));
        }
        List<Object> v = getChildNodes(node);
        for (int i = 0; i < v.size(); i++) {
          Object o = v.get(i);
          if (o instanceof LineElement) {
            li.addElement((LineElement) o);
          }
        }
        return li;
      }
      if (nodeName.equals("segment-element")) {
        SegmentElement segment = new SegmentElement();
        segment.setCardinalityMode(CardinalityMode.LOOSE);
        segment.setName(getAttributeValueNamed(node, "name"));
        segment.setMinCount(Integer.parseInt(getAttributeValueNamed(node, "minCount")));
        segment.setMaxCount(Integer.parseInt(getAttributeValueNamed(node, "maxCount")));
        segment.setBeanRef(getAttributeValueNamed(node, "beanref"));
        segment.setParentBeanRef(getAttributeValueNamed(node, "parent-beanref"));
        segment.setAddMethod(getAttributeValueNamed(node, "addMethod"));
        String segmentMode = getAttributeValueNamed(node, "cardinality-mode");
        if (!StringUtils.isBlank(segmentMode)) {
          if (segmentMode.toLowerCase().startsWith("strict")) {
            segment.setCardinalityMode(CardinalityMode.STRICT);
          } else if (segmentMode.toLowerCase().startsWith("restrict")) {
            segment.setCardinalityMode(CardinalityMode.RESTRICTED);
          }
        }

        Node fieldChild = getChildElementNodeOfType("field-ident", node);
        if (fieldChild != null) {
          segment.setFieldIdentStart(
              Integer.parseInt(getAttributeValueNamed(fieldChild, "field-start")));
          segment.setFieldIdentLength(
              Integer.parseInt(getAttributeValueNamed(fieldChild, "field-length")));
          List<Node> matchNodes = getChildElementNodesOfType("match-string", fieldChild);
          for (int j = 0; j < matchNodes.size(); j++) {
            segment.addFieldIdentMatchString(getChildTextNodeValue((Node) matchNodes.get(j)));
          }
        }
        validateSegmentConfiguration(segment);
        List<Object> v = getChildNodes(node);
        for (int i = 0; i < v.size(); i++) {
          Object o = v.get(i);
          if (o instanceof LineElement) {
            segment.addElement((LineElement) o);
          }
        }
        return segment;
      }
      if (nodeName.equals("record-element")) {
        RecordElement re = new RecordElement();

        Node start = getAttributeNamed(node, "start");
        Node end = getAttributeNamed(node, "end");
        Node length = getAttributeNamed(node, "length");
        Node beanref = getAttributeNamed(node, "beanref");
        Node beanType = getAttributeNamed(node, "type");
        if ((end == null) && (length == null)) {
          FlatwormConfigurationValueException err =
              new FlatwormConfigurationValueException(
                  "Must set either the 'end' or 'length' properties");
          throw err;
        }
        if ((end != null) && (length != null)) {
          FlatwormConfigurationValueException err =
              new FlatwormConfigurationValueException(
                  "Can't specify both the 'end' or 'length' properties");
          throw err;
        }
        if (start != null) {
          re.setFieldStart(Integer.parseInt(start.getNodeValue()));
        }
        if (end != null) {
          re.setFieldEnd(Integer.parseInt(end.getNodeValue()));
        }
        if (length != null) {
          re.setFieldLength(Integer.parseInt(length.getNodeValue()));
        }
        if (beanref != null) {
          re.setBeanRef(beanref.getNodeValue());
        }
        if (beanType != null) {
          re.setType(beanType.getNodeValue());
        }
        List<Node> children = getChildElementNodesOfType("conversion-option", node);
        for (int i = 0; i < children.size(); i++) {
          Node o = (Node) children.get(i);

          String name = getAttributeValueNamed(o, "name");
          String value = getAttributeValueNamed(o, "value");
          ConversionOption co = new ConversionOption(name, value);

          re.addConversionOption(name, co);
        }
        return re;
      }
    }
    return null;
  }
  @Test
  // write new value for P04DHWTemperatureStandardMode use case
  public void testwriteP04DHWTemperatureStandardMode() throws StiebelHeatPumpException {
    List<Request> result =
        Requests.searchIn(
            configuration,
            new Matcher<Request>() {
              @Override
              public boolean matches(Request r) {
                return r.getName().equals("SettingsNominalValues");
              }
            });

    byte[] response =
        new byte[] {
          (byte) 0x01,
          (byte) 0x00,
          (byte) 0xf0,
          (byte) 0x17,
          (byte) 0x00,
          (byte) 0xa2,
          (byte) 0x00,
          (byte) 0xa5,
          (byte) 0x00,
          (byte) 0x64,
          (byte) 0x01,
          (byte) 0xc2,
          (byte) 0x01,
          (byte) 0xe0,
          (byte) 0x00,
          (byte) 0x64,
          (byte) 0x01,
          (byte) 0x01,
          (byte) 0x00,
          (byte) 0x01,
          (byte) 0x5e,
          (byte) 0x01,
          (byte) 0xc2,
          (byte) 0x01,
          (byte) 0x10,
          (byte) 0x03
        };

    response = parser.fixDuplicatedBytes(response);
    Assert.assertEquals(response[3], result.get(0).getRequestByte());
    Assert.assertEquals(response[2], parser.calculateChecksum(response));

    Map<String, String> data = parser.parseRecords(response, result.get(0));

    Assert.assertEquals("45.0", data.get("P04DHWTemperatureStandardMode"));

    Request request = result.get(0);
    RecordDefinition recordDefinition = null;
    for (RecordDefinition record : request.getRecordDefinitions()) {
      if (record.getName().equals("P04DHWTemperatureStandardMode")) {
        recordDefinition = record;
        break;
      }
    }
    byte[] newResponse = parser.composeRecord("45.5", response, recordDefinition);

    // update the checksum
    newResponse[2] = parser.calculateChecksum(newResponse);

    data = parser.parseRecords(newResponse, request);
    Assert.assertEquals("45.5", data.get("P04DHWTemperatureStandardMode"));
  }
  @Test
  @Ignore
  // write new value for bitPosition use case
  public void testwriteSettingsDomesticWaterProgram() throws StiebelHeatPumpException {
    List<Request> result =
        Requests.searchIn(
            configuration,
            new Matcher<Request>() {
              @Override
              public boolean matches(Request r) {
                return r.getName().equals("SettingsDomesticHotWaterProgram");
              }
            });

    byte[] response =
        new byte[] {
          (byte) 0x01,
          (byte) 0x00,
          (byte) 0x1d,
          (byte) 0x0c,
          (byte) 0x08,
          (byte) 0x98,
          (byte) 0x01,
          (byte) 0xf4,
          (byte) 0x7b,
          (byte) 0x00,
          (byte) 0x10,
          (byte) 0x03
        };

    response = parser.fixDuplicatedBytes(response);
    Assert.assertEquals(response[3], result.get(0).getRequestByte());
    Assert.assertEquals(response[2], parser.calculateChecksum(response));

    Map<String, String> data = parser.parseRecords(response, result.get(0));

    Assert.assertEquals("2200", data.get("BP1StartTime"));
    Assert.assertEquals("500", data.get("BP1StopTime"));
    Assert.assertEquals("1", data.get("BP1Monday"));
    Assert.assertEquals("1", data.get("BP1Tuesday"));
    Assert.assertEquals("0", data.get("BP1Wednesday"));
    Assert.assertEquals("1", data.get("BP1Thusday"));
    Assert.assertEquals("1", data.get("BP1Friday"));
    Assert.assertEquals("1", data.get("BP1Saturday"));
    Assert.assertEquals("1", data.get("BP1Sunday"));
    Assert.assertEquals("0", data.get("BP1Enabled"));

    Request request = result.get(0);
    RecordDefinition recordDefinition = null;
    for (RecordDefinition record : request.getRecordDefinitions()) {
      if (record.getName().equals("BP1Wednesday")) {
        recordDefinition = record;
        break;
      }
    }
    byte[] newResponse = parser.composeRecord("1", response, recordDefinition);

    // update the checksum
    newResponse[2] = parser.calculateChecksum(newResponse);

    data = parser.parseRecords(newResponse, request);
    Assert.assertEquals("1", data.get("BP1Wednesday"));
    Assert.assertEquals("2200", data.get("BP1StartTime"));
    Assert.assertEquals("500", data.get("BP1StopTime"));
    Assert.assertEquals("1", data.get("BP1Monday"));
    Assert.assertEquals("1", data.get("BP1Tuesday"));
    Assert.assertEquals("1", data.get("BP1Thusday"));
    Assert.assertEquals("1", data.get("BP1Friday"));
    Assert.assertEquals("1", data.get("BP1Saturday"));
    Assert.assertEquals("1", data.get("BP1Sunday"));
    Assert.assertEquals("0", data.get("BP1Enabled"));
  }
  @Test
  // write new value for short byte value use case
  public void testWriteTime() throws StiebelHeatPumpException {
    List<Request> result =
        Requests.searchIn(
            configuration,
            new Matcher<Request>() {
              @Override
              public boolean matches(Request r) {
                return r.getName() == "Time";
              }
            });

    byte[] response =
        new byte[] {
          (byte) 0x01,
          (byte) 0x00,
          (byte) 0x79,
          (byte) 0xfc,
          (byte) 0x00,
          (byte) 0x02,
          (byte) 0x0a,
          (byte) 0x21,
          (byte) 0x24,
          (byte) 0x0e,
          (byte) 0x00,
          (byte) 0x03,
          (byte) 0x1a,
          (byte) 0x10,
          (byte) 0x03
        };

    response = parser.fixDuplicatedBytes(response);
    Assert.assertEquals(response[3], result.get(0).getRequestByte());
    Assert.assertEquals(response[2], parser.calculateChecksum(response));

    Map<String, String> data = parser.parseRecords(response, result.get(0));

    Assert.assertEquals("2", data.get("WeekDay"));
    Assert.assertEquals("10", data.get("Hours"));
    Assert.assertEquals("33", data.get("Minutes"));
    Assert.assertEquals("36", data.get("Seconds"));
    Assert.assertEquals("14", data.get("Year"));
    Assert.assertEquals("3", data.get("Month"));
    Assert.assertEquals("26", data.get("Day"));

    byte[] resultingBytes =
        new byte[] {
          (byte) 0x01,
          (byte) 0x80,
          (byte) 0xf1,
          (byte) 0xfc,
          (byte) 0x00,
          (byte) 0x02,
          (byte) 0x0a,
          (byte) 0x22,
          (byte) 0x1b,
          (byte) 0x0e,
          (byte) 0x00,
          (byte) 0x03,
          (byte) 0x1a,
          (byte) 0x10,
          (byte) 0x03
        };

    Request request = result.get(0);
    RecordDefinition recordDefinition = null;
    for (RecordDefinition record : request.getRecordDefinitions()) {
      if (record.getName() == "Minutes") {
        recordDefinition = record;
        break;
      }
    }
    byte[] newResponse = parser.composeRecord("34", response, recordDefinition);

    for (RecordDefinition record : request.getRecordDefinitions()) {
      if (record.getName() == "Seconds") {
        recordDefinition = record;
        break;
      }
    }

    Throwable e = null;
    try {
      newResponse = parser.composeRecord("90", newResponse, recordDefinition);
    } catch (Throwable ex) {
      e = ex;
    }
    Assert.assertTrue(e instanceof StiebelHeatPumpException);

    newResponse = parser.composeRecord("27", newResponse, recordDefinition);

    // update the checksum
    newResponse[2] = parser.calculateChecksum(newResponse);

    for (int i = 0; i < newResponse.length; i++) {
      Assert.assertEquals(resultingBytes[i], newResponse[i]);
    }
  }
Example #7
0
  /**
   * composes the new value of a record definition into a updated set command that can be send back
   * to heat pump
   *
   * @param response of heat pump that should be updated with new value
   * @param RecordDefinition that shall be used for compose the new value into the heat pump set
   *     command
   * @param string value to be compose
   * @return byte[] ready to send to heat pump
   * @throws StiebelHeatPumpException
   */
  public byte[] composeRecord(String value, byte[] response, RecordDefinition recordDefinition)
      throws StiebelHeatPumpException {
    short newValue = 0;

    if (recordDefinition.getDataType() != Type.Settings) {
      logger.warn(
          "The record {} can not be set as it is not a setable value!", recordDefinition.getName());
      throw new StiebelHeatPumpException("record is not a setting!");
    }

    double number = Double.parseDouble(value);

    if (number > recordDefinition.getMax() || number < recordDefinition.getMin()) {
      logger.warn(
          "The record {} can not be set to value {} as allowed range is {}<-->{} !",
          recordDefinition.getName(),
          value,
          recordDefinition.getMax(),
          recordDefinition.getMin());
      throw new StiebelHeatPumpException("invalid value !");
    }

    // change response byte to setting command
    response[1] = SET;

    // reverse the scale
    if (recordDefinition.getScale() != 1.0) {
      number = number / recordDefinition.getScale();
      newValue = (short) number;
    }

    // set new bit values in a byte
    if (recordDefinition.getBitPosition() > 0) {

      byte[] abyte = new byte[] {response[recordDefinition.getPosition()]};
      abyte = setBit(abyte, recordDefinition.getBitPosition(), newValue);
      response[recordDefinition.getPosition()] = abyte[0];
      return response;
    }

    // create byte values for single and double byte values
    // and update response
    switch (recordDefinition.getLength()) {
      case 1:
        byte newByteValue = (byte) number;
        response[recordDefinition.getPosition()] = newByteValue;
        break;
      case 2:
        byte[] newByteValues = shortToByte(newValue);
        int position = recordDefinition.getPosition();
        response[position] = newByteValues[1];
        response[position + 1] = newByteValues[0];
        break;
    }

    response[2] = this.calculateChecksum(response);
    response = this.addDuplicatedBytes(response);
    logger.debug(
        "Updated record {} at position {} to value {}.",
        recordDefinition.getName(),
        recordDefinition.getPosition(),
        value);
    return response;
  }