private static void initMapping() {
   codeToMeterScaleMapping = new HashMap<MeterType, Map<Integer, MeterScale>>();
   nameToMeterScaleMapping = new HashMap<String, MeterScale>();
   for (MeterScale s : values()) {
     if (!codeToMeterScaleMapping.containsKey(s.getMeterType()))
       codeToMeterScaleMapping.put(s.getMeterType(), new HashMap<Integer, MeterScale>());
     codeToMeterScaleMapping.get(s.getMeterType()).put(s.getScale(), s);
     nameToMeterScaleMapping.put(s.name().toLowerCase(), s);
   }
 }
 /**
  * Gets a SerialMessage with the METER_GET command
  *
  * @return the serial message
  */
 public SerialMessage getMessage(MeterScale meterScale) {
   logger.debug(
       "NODE {}: Creating new message for application command METER_GET",
       this.getNode().getNodeId());
   SerialMessage result =
       new SerialMessage(
           this.getNode().getNodeId(),
           SerialMessageClass.SendData,
           SerialMessageType.Request,
           SerialMessageClass.ApplicationCommandHandler,
           SerialMessagePriority.Get);
   byte[] newPayload = {
     (byte) this.getNode().getNodeId(),
     3,
     (byte) getCommandClass().getKey(),
     (byte) METER_GET,
     (byte) (meterScale.getScale() << 3)
   };
   result.setMessagePayload(newPayload);
   return result;
 }
  /** {@inheritDoc} */
  @Override
  public void handleApplicationCommandRequest(
      SerialMessage serialMessage, int offset, int endpoint) {
    logger.trace("Handle Message Meter Request");
    logger.debug("NODE {}: Received Meter Request", this.getNode().getNodeId());
    int command = serialMessage.getMessagePayloadByte(offset);
    MeterScale scale;
    int meterTypeIndex;

    switch (command) {
      case METER_GET:
      case METER_SUPPORTED_GET:
      case METER_RESET:
        logger.warn("Command {} not implemented.", command);
        return;
      case METER_REPORT:
        logger.trace("Process Meter Report");
        logger.debug("NODE {}: Meter report received", this.getNode().getNodeId());

        if (serialMessage.getMessagePayload().length < offset + 3) {
          logger.error(
              "NODE {}: Buffer too short: length={}, required={}",
              this.getNode().getNodeId(),
              serialMessage.getMessagePayload().length,
              offset + 3);
          return;
        }

        meterTypeIndex = serialMessage.getMessagePayloadByte(offset + 1) & 0x1F;
        if (meterTypeIndex >= MeterType.values().length) {
          logger.warn("NODE {}: Invalid meter type {}", this.getNode().getNodeId(), meterTypeIndex);
          return;
        }

        meterType = MeterType.getMeterType(meterTypeIndex);
        logger.debug(
            "NODE {}: Meter Type = {} ({})",
            this.getNode().getNodeId(),
            meterType.getLabel(),
            meterTypeIndex);

        int scaleIndex = (serialMessage.getMessagePayloadByte(offset + 2) & 0x18) >> 0x03;

        if (this.getVersion() > 2) {
          // In version 3, an extra scale bit is stored in the meter type byte.
          scaleIndex |= ((serialMessage.getMessagePayloadByte(offset + 1) & 0x80) >> 0x05);
        }

        scale = MeterScale.getMeterScale(meterType, scaleIndex);
        if (scale == null) {
          logger.warn("NODE {}: Invalid meter scale {}", this.getNode().getNodeId(), scaleIndex);
          return;
        }

        logger.debug(
            "NODE {}: Meter Scale = {} ({})",
            this.getNode().getNodeId(),
            scale.getUnit(),
            scale.getScale());

        // add scale to the list of supported scales.
        if (!this.meterScales.contains(scale)) {
          this.meterScales.add(scale);
        }

        try {
          BigDecimal value = extractValue(serialMessage.getMessagePayload(), offset + 2);
          logger.debug("NODE {}: Meter Value = {}", this.getNode().getNodeId(), value);

          ZWaveMeterValueEvent zEvent =
              new ZWaveMeterValueEvent(
                  this.getNode().getNodeId(), endpoint, meterType, scale, value);
          this.getController().notifyEventListeners(zEvent);
        } catch (NumberFormatException e) {
          return;
        }

        if (this.getNode().getNodeStage() != NodeStage.DONE) {
          this.getNode().advanceNodeStage(NodeStage.DONE);
        }
        break;
      case METER_SUPPORTED_REPORT:
        logger.trace("Process Meter Supported Report");

        canReset = (serialMessage.getMessagePayloadByte(offset + 1) & 0x80) != 0;
        meterTypeIndex = serialMessage.getMessagePayloadByte(offset + 1) & 0x1F;
        int supportedScales = serialMessage.getMessagePayloadByte(offset + 2);

        // only 4 scales are supported in version 2 of the command.
        if (this.getVersion() == 2) {
          supportedScales &= 0x0F;
        }

        if (meterTypeIndex >= MeterType.values().length) {
          logger.warn("NODE {}: Invalid meter type {}", this.getNode().getNodeId(), meterTypeIndex);
          return;
        }

        meterType = MeterType.getMeterType(meterTypeIndex);
        logger.debug(
            "NODE {}: Identified meter type {} ({})",
            this.getNode().getNodeId(),
            meterType.getLabel(),
            meterTypeIndex);

        for (int i = 0; i < 8; ++i) {
          // scale is supported
          if ((supportedScales & (1 << i)) == (1 << i)) {
            scale = MeterScale.getMeterScale(meterType, i);

            if (scale == null) {
              logger.warn("NODE {}: Invalid meter scale {}", this.getNode().getNodeId(), i);
              continue;
            }

            logger.debug(
                "NODE {}: Meter Scale = {} ({})",
                this.getNode().getNodeId(),
                scale.getUnit(),
                scale.getScale());

            // add scale to the list of supported scales.
            if (!this.meterScales.contains(scale)) this.meterScales.add(scale);
          }
        }

        this.getNode().advanceNodeStage(NodeStage.DYNAMIC);
        break;
      default:
        logger.warn(
            String.format(
                "Unsupported Command 0x%02X for command class %s (0x%02X).",
                command, this.getCommandClass().getLabel(), this.getCommandClass().getKey()));
    }
  }