diff --git a/src/energenie/OpenHEMS.py b/src/energenie/OpenHEMS.py
index 93469a6..65695f2 100644
--- a/src/energenie/OpenHEMS.py
+++ b/src/energenie/OpenHEMS.py
@@ -45,6 +45,7 @@
 PARAM_EMERGENCY       = 0x65
 PARAM_FREQUENCY       = 0x66
 PARAM_GAS_FLOW_RATE   = 0x67
+PARAM_RELATIVE_HUMIDITY=0x68
 PARAM_CURRENT         = 0x69
 PARAM_JOIN            = 0x6A
 PARAM_LIGHT_LEVEL     = 0x6C
@@ -61,50 +62,51 @@
 
 PARAM_TEST            = 0xAA
 
-param_names = {
-	PARAM_ALARM           : "ALARM",
-	PARAM_DEBUG_OUTPUT    : "DEBUG_OUTPUT",
-	PARAM_IDENTIFY        : "IDENTIFY",
-	PARAM_SOURCE_SELECTOR : "SOURCE_SELECTOR",
-	PARAM_WATER_DETECTOR  : "WATER_DETECTOR",
-	PARAM_GLASS_BREAKAGE  : "GLASS_BREAKAGE",
-	PARAM_CLOSURES        : "CLOSURES",
-	PARAM_DOOR_BELL       : "DOOR_BELL",
-	PARAM_ENERGY          : "ENERGY",
-	PARAM_FALL_SENSOR     : "FALL_SENSOR",
-	PARAM_GAS_VOLUME      : "GAS_VOLUME",
-	PARAM_AIR_PRESSURE    : "AIR_PRESSURE",
-	PARAM_ILLUMINANCE     : "ILLUMINANCE",
-	PARAM_LEVEL           : "LEVEL",
-	PARAM_RAINFALL        : "RAINFALL",
-	PARAM_APPARENT_POWER  : "APPARENT_POWER",
-	PARAM_POWER_FACTOR    : "POWER_FACTOR",
-	PARAM_REPORT_PERIOD   : "REPORT_PERIOD",
-	PARAM_SMOKE_DETECTOR  : "SMOKE_DETECTOR",
-	PARAM_TIME_AND_DATE   : "TIME_AND_DATE",
-	PARAM_VIBRATION       : "VIBRATION",
-	PARAM_WATER_VOLUME    : "WATER_VOLUME",
-	PARAM_WIND_SPEED      : "WIND_SPEED",
-	PARAM_GAS_PRESSURE    : "GAS_PRESSURE",
-	PARAM_BATTERY_LEVEL   : "BATTERY_LEVEL",
-	PARAM_CO_DETECTOR     : "CO_DETECTOR",
-	PARAM_DOOR_SENSOR     : "DOOR_SENSOR",
-	PARAM_EMERGENCY       : "EMERGENCY",
-	PARAM_FREQUENCY       : "FREQUENCY",
-	PARAM_GAS_FLOW_RATE   : "GAS_FLOW_RATE",
-	PARAM_CURRENT         : "CURRENT",
-	PARAM_JOIN            : "JOIN",
-	PARAM_LIGHT_LEVEL     : "LIGHT_LEVEL",
-	PARAM_MOTION_DETECTOR : "MOTION_DETECTOR",
-	PARAM_OCCUPANCY       : "OCCUPANCY",
-	PARAM_REAL_POWER      : "REAL_POWER",
-	PARAM_REACTIVE_POWER  : "REACTIVE_POWER",
-	PARAM_ROTATION_SPEED  : "ROTATION_SPEED",
-	PARAM_SWITCH_STATE    : "SWITCH_STATE",
-	PARAM_TEMPERATURE     : "TEMPERATURE",
-	PARAM_VOLTAGE         : "VOLTAGE",
-	PARAM_WATER_FLOW_RATE : "WATER_FLOW_RATE",
-	PARAM_WATER_PRESSURE  : "WATER_PRESSURE"
+param_info = {
+	PARAM_ALARM           : {"n":"ALARM",				"u":""},
+	PARAM_DEBUG_OUTPUT    : {"n":"DEBUG_OUTPUT",		"u":""},
+	PARAM_IDENTIFY        : {"n":"IDENTIFY",			"u":""},
+	PARAM_SOURCE_SELECTOR : {"n":"SOURCE_SELECTOR",		"u":""},
+	PARAM_WATER_DETECTOR  : {"n":"WATER_DETECTOR",		"u":""},
+	PARAM_GLASS_BREAKAGE  : {"n":"GLASS_BREAKAGE",		"u":""},
+	PARAM_CLOSURES        : {"n":"CLOSURES",			"u":""},
+	PARAM_DOOR_BELL       : {"n":"DOOR_BELL",			"u":""},
+	PARAM_ENERGY          : {"n":"ENERGY",				"u":"kWh"},
+	PARAM_FALL_SENSOR     : {"n":"FALL_SENSOR",			"u":""},
+	PARAM_GAS_VOLUME      : {"n":"GAS_VOLUME",			"u":"m3"},
+	PARAM_AIR_PRESSURE    : {"n":"AIR_PRESSURE",		"u":"mbar"},
+	PARAM_ILLUMINANCE     : {"n":"ILLUMINANCE",			"u":"Lux"},
+	PARAM_LEVEL           : {"n":"LEVEL",				"u":""},
+	PARAM_RAINFALL        : {"n":"RAINFALL",			"u":"mm"},
+	PARAM_APPARENT_POWER  : {"n":"APPARENT_POWER",		"u":"VA"},
+	PARAM_POWER_FACTOR    : {"n":"POWER_FACTOR",		"u":""},
+	PARAM_REPORT_PERIOD   : {"n":"REPORT_PERIOD",		"u":"s"},
+	PARAM_SMOKE_DETECTOR  : {"n":"SMOKE_DETECTOR",		"u":""},
+	PARAM_TIME_AND_DATE   : {"n":"TIME_AND_DATE",		"u":"s"},
+	PARAM_VIBRATION       : {"n":"VIBRATION",			"u":""},
+	PARAM_WATER_VOLUME    : {"n":"WATER_VOLUME",		"u":"l"},
+	PARAM_WIND_SPEED      : {"n":"WIND_SPEED",			"u":"m/s"},
+	PARAM_GAS_PRESSURE    : {"n":"GAS_PRESSURE",		"u":"Pa"},
+	PARAM_BATTERY_LEVEL   : {"n":"BATTERY_LEVEL",		"u":"V"},
+	PARAM_CO_DETECTOR     : {"n":"CO_DETECTOR",			"u":""},
+	PARAM_DOOR_SENSOR     : {"n":"DOOR_SENSOR",			"u":""},
+	PARAM_EMERGENCY       : {"n":"EMERGENCY",			"u":""},
+	PARAM_FREQUENCY       : {"n":"FREQUENCY",			"u":"Hz"},
+	PARAM_GAS_FLOW_RATE   : {"n":"GAS_FLOW_RATE",		"u":"m3/hr"},
+	PARAM_RELATIVE_HUMIDITY:{"n":"RELATIVE_HUMIDITY",   "u":"%"},
+	PARAM_CURRENT         : {"n":"CURRENT",				"u":"A"},
+	PARAM_JOIN            : {"n":"JOIN",				"u":""},
+	PARAM_LIGHT_LEVEL     : {"n":"LIGHT_LEVEL",			"u":""},
+	PARAM_MOTION_DETECTOR : {"n":"MOTION_DETECTOR",		"u":""},
+	PARAM_OCCUPANCY       : {"n":"OCCUPANCY",			"u":""},
+	PARAM_REAL_POWER      : {"n":"REAL_POWER",			"u":"W"},
+	PARAM_REACTIVE_POWER  : {"n":"REACTIVE_POWER",		"u":"VAR"},
+	PARAM_ROTATION_SPEED  : {"n":"ROTATION_SPEED",		"u":"RPM"},
+	PARAM_SWITCH_STATE    : {"n":"SWITCH_STATE",		"u":""},
+	PARAM_TEMPERATURE     : {"n":"TEMPERATURE",			"u":"C"},
+	PARAM_VOLTAGE         : {"n":"VOLTAGE",				"u":"V"},
+	PARAM_WATER_FLOW_RATE : {"n":"WATER_FLOW_RATE",		"u":"l/hr"},
+	PARAM_WATER_PRESSURE  : {"n":"WATER_PRESSURE",		"u":"Pa"},
 }
 
 
@@ -185,14 +187,16 @@
 		param = payload[i]
 		wr = ((param & 0x80) == 0x80)
 		paramid = param & 0x7F
-		if param_names.has_key(paramid):
-			paramname = param_names[paramid]
+		if param_info.has_key(paramid):
+			paramname = (param_info[paramid])["n"] # name
+			paramunit = (param_info[paramid])["u"] # unit
 		else:
 			paramname = "UNKNOWN_" + hex(paramid)
+			paramunit = "UNKNOWN_UNIT"
 		i += 1
 
 		# TYPE/LEN
-		typeid = (payload[i] & 0xF0)>>4
+		typeid = payload[i] & 0xF0
 		plen = payload[i] & 0x0F
 		i += 1
 
@@ -203,13 +207,14 @@
 		for x in range(plen):
 			valuebytes.append(payload[i])
 			i += 1
-		value = "TODO" # TODO decode based on type and length
+		value = Value.decode(valuebytes, typeid, plen)
 
 		# store rec
 		recs.append({
 			"wr":         wr,
 			"paramid":    paramid,
 			"paramname":  paramname,
+			"paramunit":  paramunit,
 			"typeid":     typeid,
 			"length":     plen,
 			"valuebytes": valuebytes,
@@ -223,7 +228,6 @@
 	}
 
 
-
 #----- MESSAGE ENCODER --------------------------------------------------------
 #
 # Encodes a message using the OpenHEMS message payload structure
@@ -279,8 +283,9 @@
 		payload.append((typeid<<4) | length)
 
 		# VALUE
-		for i in range(length):
-			payload.append(0) # TODO encoding depends on typeid and length
+		valueenc = Value.encode(value, typeid, length)
+		for b in valueenc:
+			payload.append(b)
 
 	# FOOTER
 	payload.append(0) # NUL
@@ -300,6 +305,88 @@
 	return payload
 
 
+#---- VALUE CODEC -------------------------------------------------------------
+
+class Value():
+	UINT      = 0x00
+	UINT_BP4  = 0x10
+	UINT_BP8  = 0x20
+	UINT_BP12 = 0x30
+	UINT_BP16 = 0x40
+	UINT_BP20 = 0x50
+	UINT_BP24 = 0x60
+	CHAR      = 0x70
+	SINT      = 0x80
+	SINT_BP8  = 0x90
+	SINT_BP16 = 0xA0
+	SINT_BP24 = 0xB0
+	# C0,D0,E0 RESERVED
+	FLOAT     = 0xF0
+
+	@staticmethod
+	def encode(value, typeid, length):
+		return [int(value) for i in range(length)] # TODO
+
+	@staticmethod
+	def decode(valuebytes, typeid, length):
+		if typeid <= Value.UINT_BP24:
+			result = 0
+			# decode unsigned integer first
+			for i in range(length):
+				result <<= 8
+				result += valuebytes[i]
+			# process any fixed binary points
+			if typeid == Value.UINT:
+				return result # no BP adjustment
+			if typeid == Value.UINT_BP4:
+				return (float(result))/(2**4) # 4 bits
+			if typeid == Value.UINT_BP8:
+				return (float(result))/(2**8) # 8 bits
+			if typeid == Value.UINT_BP12:
+				return (float(result))/(2**12) # 12 bits
+			if typeid == Value.UINT_BP16:
+				return (float(result))/(2**16) # 16 bits
+			if typeid == Value.UINT_BP20:
+				return (float(result))/(2**20) # 20 bits
+			if typeid == Value.UINT_BP24:
+				return (float(result))/(2**24) # 24 bits
+
+		elif typeid == Value.CHAR:
+			result = ""
+			for b in range(length):
+				result += chr(b)
+			return result
+
+		elif typeid >= Value.SINT and typeid <= Value.SINT_BP24:
+			# decode unsigned int first
+			result = 0
+			for i in range(length):
+				result <<= 8
+				result += valuebytes[i]
+
+			# turn to signed int based on high bit of MSB
+			# 2's comp is 1's comp plus 1
+			neg = ((valuebytes[0] & 0x80) == 0x80)
+			if neg:
+				onescomp = (~result) & ((2**(length*8))-1)
+				result = -(onescomp + 1)
+
+			# adjust binary point
+			if typeid == Value.SINT:
+				return result # no BP
+			elif typeid == Value.SINT_BP8:
+				return (float(result))/(2**8) # 8 bits
+			elif typeid == Value.SINT_BP16:
+				return (float(result))/(2**16) # 16 bits
+			elif typeid == Value.SINT_BP24:
+				return (float(result))/(2**24) # 24 bits
+			return result
+
+		elif typeid == Value.FLOAT:
+			return "TODO_FLOAT_IEEE_754-2008" #TODO: IEEE 754-2008
+
+		raise ValueError("Unsupported typeid:%" + hex(typeid))
+
 
 #----- CRC CALCULATION --------------------------------------------------------
 
@@ -364,15 +451,19 @@
 	import pprint
 	init(242)
 
+	print("RAW PAYLOAD, UNENCRYPTED")
 	printhex(TEST_PAYLOAD)
 
 	spec = decode(TEST_PAYLOAD, decrypt=False)
+	print("DECODED")
 	pprint.pprint(spec)
 
 	payload = encode(spec, encrypt=True)
+	print("ENCODED ENCRYTED")
 	printhex(payload)
 
 	spec2 = decode(payload, decrypt=True)
+	print("DECODED, DECRYPTED")
 	pprint.pprint(spec2)
 
 # END
diff --git a/src/energenie/radio.py b/src/energenie/radio.py
index 9cfa544..7c768cd 100644
--- a/src/energenie/radio.py
+++ b/src/energenie/radio.py
@@ -228,7 +228,7 @@
     """Check if there is a payload in the FIFO waiting to be processed"""
     irqflags1 = HRF_readreg(ADDR_IRQFLAGS1)
     irqflags2 = HRF_readreg(ADDR_IRQFLAGS2)
-    print("irq1 %s   irq2 %s" % (hex(irqflags1), hex(irqflags2)))
+    #trace("irq1 %s   irq2 %s" % (hex(irqflags1), hex(irqflags2)))
 
     return (irqflags2 & MASK_PAYLOADRDY) == MASK_PAYLOADRDY
 
@@ -240,7 +240,7 @@
 
 def HRF_send_payload(payload):
     trace("send_payload")
-    dumpPayloadAsHex(payload)
+    #dumpPayloadAsHex(payload)
     HRF_writefifo_burst(payload)
     trace("  waiting for sent...")
     HRF_pollreg(ADDR_IRQFLAGS2, MASK_PACKETSENT, MASK_PACKETSENT)
diff --git a/src/monitor.py b/src/monitor.py
index 20a9186..b23b3b0 100644
--- a/src/monitor.py
+++ b/src/monitor.py
@@ -45,35 +45,61 @@
         "mfrid":       ENERGENIE.MFRID,
         "productid":   ENERGENIE.PRODUCTID_C1_MONITOR,
         "encryptPIP":  ENERGENIE.CRYPT_PIP,
-        "sensorid":    0xFFFFFF
+        "sensorid":    0xFFFFFF # energenie broadcast
     },
     "recs": [
         {
-            "wr":      True,
+            "wr":      True, # monitor only will ignore this
             "paramid": OpenHEMS.PARAM_SWITCH_STATE,
-            "typeid":  0x00,
-            "length":  0x01,
-            "value":   0x00
+            "typeid":  OpenHEMS.Value.UINT,
+            "length":  1,
+            "value":   0
         }
     ]
 }
 
 
+def showMessage(msg):
+    """Show the message in a friendly format"""
+    #pprint.pprint(msg)
+
+    # HEADER
+    header    = msg["header"]
+    mfrid     = header["mfrid"]
+    productid = header["productid"]
+    sensorid  = header["sensorid"]
+    print("mfrid:%s prodid:%s sensorid:%s" % (hex(mfrid), hex(productid), hex(sensorid)))
+
+    # RECORDS
+    for rec in msg["recs"]:
+        wr        = rec["wr"]
+        if wr == True:
+            write = "write"
+        else:
+            write = "read "
+
+        paramid   = rec["paramid"]
+        paramname = rec["paramname"]
+        paramunit = rec["paramunit"]
+        value     = rec["value"]
+        print("%s %s %s = %s" % (write, paramname, paramunit, str(value)))
+
+
 def monitor():
     """Send monitor poke messages and capture any responses"""
 
-    sendMonitorTimer = Timer(3)
-    pollReceiveTimer = Timer(1)
+    sendMonitorTimer = Timer(9)   # every 9 secs
+    #pollReceiveTimer = Timer(0.1) # 10 times per sec
     radio.receiver()
 
     while True:
         # See if there is a payload, and if there is, process it
-        if pollReceiveTimer.check():
-            if radio.isReceiveWaiting():
-                trace("receiving payload")
-                payload = radio.receive()
-                decoded = OpenHEMS.decode(payload)
-                pprint.pprint(decoded)
+        #if pollReceiveTimer.check():
+        if radio.isReceiveWaiting():
+            trace("receiving payload")
+            payload = radio.receive()
+            decoded = OpenHEMS.decode(payload)
+            showMessage(decoded)
 
         # If it is time to send a monitor message, send it
         if sendMonitorTimer.check():