diff --git a/api/go/authn/authnAdmin.go b/api/go/authn/authnAdmin.go
index 855b3aff..2f22ba94 100644
--- a/api/go/authn/authnAdmin.go
+++ b/api/go/authn/authnAdmin.go
@@ -1,6 +1,6 @@
 // Package authn with types and interfaces for using this service with agent 'authn'
 // DO NOT EDIT. This file is auto generated by tdd2api. Any changes will be overwritten.
-// Generated 29 Dec 24 17:28 PST. 
+// Generated 31 Dec 24 22:27 PST. 
 package authn
 
 import "errors"
@@ -23,15 +23,15 @@ const (
     AdminPropNrClients = "nrClients"
     AdminEventAdded = "added"
     AdminEventRemoved = "removed"
-    AdminActionAddConsumer = "addConsumer"
+    AdminActionGetClientProfile = "getClientProfile"
+    AdminActionGetProfiles = "getProfiles"
     AdminActionNewAgentToken = "newAgentToken"
-    AdminActionSetClientPassword = "setClientPassword"
-    AdminActionUpdateClientProfile = "updateClientProfile"
     AdminActionRemoveClient = "removeClient"
     AdminActionAddAgent = "addAgent"
+    AdminActionAddConsumer = "addConsumer"
+    AdminActionUpdateClientProfile = "updateClientProfile"
     AdminActionAddService = "addService"
-    AdminActionGetClientProfile = "getClientProfile"
-    AdminActionGetProfiles = "getProfiles"
+    AdminActionSetClientPassword = "setClientPassword"
 )
 //--- Argument and Response struct for action of Thing 'dtw:authn:admin' ---
 
@@ -239,45 +239,38 @@ func NewHandleAdminAction(svc IAdminService)(func(msg transports.RequestMessage)
         var output any
         var err error
         switch msg.Name {
-            case "updateClientProfile":
-                var args ClientProfile
+            case "addService":
+                args := AdminAddServiceArgs{}
                 err = tputils.DecodeAsObject(msg.Input, &args)
                 if err == nil {
-                  err = svc.UpdateClientProfile(msg.SenderID, args)
+                  output, err = svc.AddService(msg.SenderID, args)
                 } else {
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
-            case "addConsumer":
-                args := AdminAddConsumerArgs{}
+            case "setClientPassword":
+                args := AdminSetClientPasswordArgs{}
                 err = tputils.DecodeAsObject(msg.Input, &args)
                 if err == nil {
-                  err = svc.AddConsumer(msg.SenderID, args)
+                  err = svc.SetClientPassword(msg.SenderID, args)
                 } else {
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
-            case "newAgentToken":
-                var args string
+            case "updateClientProfile":
+                var args ClientProfile
                 err = tputils.DecodeAsObject(msg.Input, &args)
                 if err == nil {
-                  output, err = svc.NewAgentToken(msg.SenderID, args)
+                  err = svc.UpdateClientProfile(msg.SenderID, args)
                 } else {
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
-            case "setClientPassword":
-                args := AdminSetClientPasswordArgs{}
+            case "newAgentToken":
+                var args string
                 err = tputils.DecodeAsObject(msg.Input, &args)
                 if err == nil {
-                  err = svc.SetClientPassword(msg.SenderID, args)
-                } else {
-                  err = errors.New("bad function argument: "+err.Error())
-                }
-                break
-            case "getProfiles":
-                if err == nil {
-                  output, err = svc.GetProfiles(msg.SenderID)
+                  output, err = svc.NewAgentToken(msg.SenderID, args)
                 } else {
                   err = errors.New("bad function argument: "+err.Error())
                 }
@@ -300,11 +293,11 @@ func NewHandleAdminAction(svc IAdminService)(func(msg transports.RequestMessage)
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
-            case "addService":
-                args := AdminAddServiceArgs{}
+            case "addConsumer":
+                args := AdminAddConsumerArgs{}
                 err = tputils.DecodeAsObject(msg.Input, &args)
                 if err == nil {
-                  output, err = svc.AddService(msg.SenderID, args)
+                  err = svc.AddConsumer(msg.SenderID, args)
                 } else {
                   err = errors.New("bad function argument: "+err.Error())
                 }
@@ -318,6 +311,13 @@ func NewHandleAdminAction(svc IAdminService)(func(msg transports.RequestMessage)
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
+            case "getProfiles":
+                if err == nil {
+                  output, err = svc.GetProfiles(msg.SenderID)
+                } else {
+                  err = errors.New("bad function argument: "+err.Error())
+                }
+                break
             default:
             	err = errors.New("Unknown Method '"+msg.Name+"' of service '"+msg.ThingID+"'")
         }
diff --git a/api/go/authn/authnUser.go b/api/go/authn/authnUser.go
index cb2e059d..7dbe24c0 100644
--- a/api/go/authn/authnUser.go
+++ b/api/go/authn/authnUser.go
@@ -1,6 +1,6 @@
 // Package authn with types and interfaces for using this service with agent 'authn'
 // DO NOT EDIT. This file is auto generated by tdd2api. Any changes will be overwritten.
-// Generated 29 Dec 24 17:28 PST. 
+// Generated 31 Dec 24 22:27 PST. 
 package authn
 
 import "errors"
@@ -215,6 +215,15 @@ func NewHandleUserAction(svc IUserService)(func(msg transports.RequestMessage) t
         var output any
         var err error
         switch msg.Name {
+            case "refreshToken":
+                args := UserRefreshTokenArgs{}
+                err = tputils.DecodeAsObject(msg.Input, &args)
+                if err == nil {
+                  output, err = svc.RefreshToken(msg.SenderID, args)
+                } else {
+                  err = errors.New("bad function argument: "+err.Error())
+                }
+                break
             case "updateName":
                 var args string
                 err = tputils.DecodeAsObject(msg.Input, &args)
@@ -265,15 +274,6 @@ func NewHandleUserAction(svc IUserService)(func(msg transports.RequestMessage) t
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
-            case "refreshToken":
-                args := UserRefreshTokenArgs{}
-                err = tputils.DecodeAsObject(msg.Input, &args)
-                if err == nil {
-                  output, err = svc.RefreshToken(msg.SenderID, args)
-                } else {
-                  err = errors.New("bad function argument: "+err.Error())
-                }
-                break
             default:
             	err = errors.New("Unknown Method '"+msg.Name+"' of service '"+msg.ThingID+"'")
         }
diff --git a/api/go/authz/authzAdmin.go b/api/go/authz/authzAdmin.go
index 9a804abb..e69254c4 100644
--- a/api/go/authz/authzAdmin.go
+++ b/api/go/authz/authzAdmin.go
@@ -1,6 +1,6 @@
 // Package authz with types and interfaces for using this service with agent 'authz'
 // DO NOT EDIT. This file is auto generated by tdd2api. Any changes will be overwritten.
-// Generated 29 Dec 24 17:28 PST. 
+// Generated 31 Dec 24 22:27 PST. 
 package authz
 
 import "errors"
@@ -20,8 +20,8 @@ const AdminDThingID = "dtw:authz:admin"
 
 // Thing names
 const (
-    AdminActionGetClientRole = "getClientRole"
     AdminActionSetClientRole = "setClientRole"
+    AdminActionGetClientRole = "getClientRole"
 )
 //--- Argument and Response struct for action of Thing 'dtw:authz:admin' ---
 
diff --git a/api/go/authz/authzUser.go b/api/go/authz/authzUser.go
index a523b593..63f9bf10 100644
--- a/api/go/authz/authzUser.go
+++ b/api/go/authz/authzUser.go
@@ -1,6 +1,6 @@
 // Package authz with types and interfaces for using this service with agent 'authz'
 // DO NOT EDIT. This file is auto generated by tdd2api. Any changes will be overwritten.
-// Generated 29 Dec 24 17:28 PST. 
+// Generated 31 Dec 24 22:27 PST. 
 package authz
 
 import "errors"
diff --git a/api/go/digitwin/digitwinDirectory.go b/api/go/digitwin/digitwinDirectory.go
index 35c84a4d..d6a0e091 100644
--- a/api/go/digitwin/digitwinDirectory.go
+++ b/api/go/digitwin/digitwinDirectory.go
@@ -1,6 +1,6 @@
 // Package digitwin with types and interfaces for using this service with agent 'digitwin'
 // DO NOT EDIT. This file is auto generated by tdd2api. Any changes will be overwritten.
-// Generated 29 Dec 24 17:28 PST. 
+// Generated 31 Dec 24 22:27 PST. 
 package digitwin
 
 import "errors"
@@ -22,10 +22,10 @@ const DirectoryDThingID = "dtw:digitwin:directory"
 const (
     DirectoryEventThingUpdated = "thingUpdated"
     DirectoryEventThingRemoved = "thingRemoved"
-    DirectoryActionReadAllTDs = "readAllTDs"
-    DirectoryActionRemoveTD = "removeTD"
     DirectoryActionUpdateTD = "updateTD"
     DirectoryActionReadTD = "readTD"
+    DirectoryActionReadAllTDs = "readAllTDs"
+    DirectoryActionRemoveTD = "removeTD"
 )
 //--- Argument and Response struct for action of Thing 'dtw:digitwin:directory' ---
 
@@ -122,6 +122,15 @@ func NewHandleDirectoryAction(svc IDirectoryService)(func(msg transports.Request
         var output any
         var err error
         switch msg.Name {
+            case "readTD":
+                var args string
+                err = tputils.DecodeAsObject(msg.Input, &args)
+                if err == nil {
+                  output, err = svc.ReadTD(msg.SenderID, args)
+                } else {
+                  err = errors.New("bad function argument: "+err.Error())
+                }
+                break
             case "readAllTDs":
                 args := DirectoryReadAllTDsArgs{}
                 err = tputils.DecodeAsObject(msg.Input, &args)
@@ -149,15 +158,6 @@ func NewHandleDirectoryAction(svc IDirectoryService)(func(msg transports.Request
                   err = errors.New("bad function argument: "+err.Error())
                 }
                 break
-            case "readTD":
-                var args string
-                err = tputils.DecodeAsObject(msg.Input, &args)
-                if err == nil {
-                  output, err = svc.ReadTD(msg.SenderID, args)
-                } else {
-                  err = errors.New("bad function argument: "+err.Error())
-                }
-                break
             default:
             	err = errors.New("Unknown Method '"+msg.Name+"' of service '"+msg.ThingID+"'")
         }
diff --git a/api/go/digitwin/digitwinValues.go b/api/go/digitwin/digitwinValues.go
index 80a53f51..e2641d0e 100644
--- a/api/go/digitwin/digitwinValues.go
+++ b/api/go/digitwin/digitwinValues.go
@@ -1,6 +1,6 @@
 // Package digitwin with types and interfaces for using this service with agent 'digitwin'
 // DO NOT EDIT. This file is auto generated by tdd2api. Any changes will be overwritten.
-// Generated 29 Dec 24 17:28 PST. 
+// Generated 31 Dec 24 22:27 PST. 
 package digitwin
 
 import "errors"
@@ -97,6 +97,11 @@ type ActionStatus struct {
 // Property or event value
 type ThingValue struct {
     
+    // Created with Updated time
+    //
+    // Time the value was last updated
+    Created string `json:"created,omitempty"`
+    
     // Data with Payload
     //
     // Data in format as described by the thing's property affordance
@@ -107,20 +112,10 @@ type ThingValue struct {
     // Name of the property holding the value
     Name string `json:"name,omitempty"`
     
-    // RequestID with Message ID
-    //
-    // link to property write or action that caused the value to change
-    RequestID string `json:"requestID,omitempty"`
-    
-    // SenderID with Sender ID
-    //
-    // ID of the sender updating the value
-    SenderID string `json:"senderID,omitempty"`
-    
-    // Updated with Updated time
+    // ThingID with Thing ID
     //
-    // Time the value was last updated
-    Updated string `json:"updated,omitempty"`
+    // Digital twin Thing ID
+    ThingID string `json:"thingID,omitempty"`
 }
 
 //--- Argument and Response struct for action of Thing 'dtw:digitwin:values' ---
@@ -318,4 +313,4 @@ func NewHandleValuesAction(svc IValuesService)(func(msg transports.RequestMessag
 }
 
 // ValuesTD contains the raw TD of this service for publication to the Hub
-const ValuesTD = `{"actions":{"queryAction":{"@type":"hiveot:function","description":"Read the current action status of a Thing","title":"Action status","idempotent":true,"input":{"readOnly":false,"type":"object","properties":{"name":{"title":"Action Name","description":"The action name to query","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"ID of the Thing to query","readOnly":false,"type":"string"}},"required":["thingID","name"]},"output":{"title":"Action value","description":"The latest action value","readOnly":false,"type":"ActionStatus"},"safe":true},"readAllEvents":{"@type":"hiveot:function","description":"Read the latest known event values of a Thing","title":"Read all event values","idempotent":true,"input":{"title":"Thing ID","description":"ID of the Thing to read","readOnly":false,"type":"string"},"output":{"title":"Event values","description":"List with the most recent event value objects","readOnly":false,"type":"array","items":{"title":"Event value","readOnly":false,"type":"ThingValue"}},"safe":true},"readAllProperties":{"@type":"hiveot:function","description":"Read the latest known property values","title":"Read all properties","idempotent":true,"input":{"title":"Thing ID","description":"Digital twin ID of the Thing to read","readOnly":false,"type":"string"},"output":{"title":"Property values","description":"List of ThingValue objects","readOnly":false,"type":"array","items":{"title":"Property Value","readOnly":false,"type":"ThingValue"}},"safe":true},"readEvent":{"@type":"hiveot:function","description":"Read the latest event value of a Thing","title":"Read event value","idempotent":true,"input":{"readOnly":false,"type":"object","properties":{"name":{"title":"Event name","description":"Name of the event to read the latest values","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"ID of the Thing to read","readOnly":false,"type":"string"}},"required":["thingID","name"]},"output":{"title":"Event value","description":"Most recent event value","readOnly":false,"type":"ThingValue"},"safe":true},"readProperty":{"@type":"hiveot:function","description":"Read the latest property value","title":"Read property value","idempotent":true,"input":{"readOnly":false,"type":"object","properties":{"name":{"title":"Property name","description":"The property name whose value to read","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"ID of the Thing to read","readOnly":false,"type":"string"}},"required":["thingID","name"]},"output":{"title":"Property value","description":"Most recent property value","readOnly":false,"type":"ThingValue"},"safe":true}},"@context":["https://www.w3.org/2022/wot/td/v1.1",{"ht":"https://www.hiveot.net/vocab/v0.1"}],"@type":"Service","created":"2024-10-04T17:00:00.000Z","deny":["none"],"description":"Last known property, event and action values","events":{"progress":{"description":"Progress notification of a property write or thing action request","title":"Progress","data":{"readOnly":false,"type":"object","properties":{"data":{"title":"Data","description":"Input value in format as described by the thing's property affordance","readOnly":false,"type":"any"},"id":{"title":"Thing ID","description":"Thing ID of thing whose value is updated","readOnly":false,"type":"string"},"messageType":{"title":"Message Type","description":"Type of change request","enum":["action","property"],"readOnly":false,"type":"string"},"name":{"title":"Property name","description":"Name of the property or action the notification applies to","readOnly":false,"type":"string"},"requestID":{"title":"Message ID","description":"link to action or property write that triggered the update","readOnly":false,"type":"string"},"senderID":{"title":"Sender ID","description":"ID of the sender of the request","readOnly":false,"type":"string"},"status":{"title":"Progress status","description":"The new status of the update progress.","readOnly":false,"type":"string"},"statusInfo":{"title":"Additional status information","readOnly":false,"type":"string"}}}}},"id":"values","modified":"2024-10-04T17:00:00.000Z","properties":null,"schemaDefinitions":{"ActionStatus":{"title":"Action Status","description":"Status of the last action","readOnly":false,"type":"object","properties":{"agentID":{"title":"Agent ID","description":"The agent handling the action","readOnly":false,"type":"string"},"error":{"title":"Error","description":"Action error info when failed","readOnly":false,"type":"string"},"input":{"title":"Action input","description":"Action input value","readOnly":false,"type":"any"},"name":{"title":"Action name","description":"name of the action or property","readOnly":false,"type":"string"},"output":{"title":"Action output","readOnly":false,"type":"any"},"requestID":{"title":"Request ID","description":"The action request identifier","readOnly":false,"type":"string"},"senderID":{"title":"Consumer ID","readOnly":false,"type":"string"},"status":{"title":"Action status","description":"Status of the action's progress","readOnly":false,"type":"string"},"thingID":{"title":"Action Thing","description":"Digital twin ThingID the action applies to","readOnly":false,"type":"string"},"timeEnded":{"title":"End Time","description":"Time the action has completed or failed","readOnly":false,"type":"dateTime"},"timeRequested":{"title":"Creation Time","description":"Time the action was initially requested","readOnly":false,"type":"dateTime"},"timeUpdated":{"title":"Updated time","description":"Time the action status was last updated","readOnly":false,"type":"dateTime"}}},"ThingValue":{"title":"Thing Value","description":"Property or event value","readOnly":false,"type":"object","properties":{"data":{"title":"Payload","description":"Data in format as described by the thing's property affordance","readOnly":false,"type":"any"},"name":{"title":"Name","description":"Name of the property holding the value","readOnly":false,"type":"string"},"requestID":{"title":"Message ID","description":"link to property write or action that caused the value to change","readOnly":false,"type":"string"},"senderID":{"title":"Sender ID","description":"ID of the sender updating the value","readOnly":false,"type":"string"},"updated":{"title":"Updated time","description":"Time the value was last updated","readOnly":false,"type":"dateTime"}}}},"security":["bearer"],"securityDefinitions":{"bearer":{"description":"HTTP protocol authentication","scheme":"bearer","name":"authentication","alg":"es256","format":"jwt","in":"header"}},"title":"DigiTwin Values","support":"https://www.github.com/hiveot/hub"}`
\ No newline at end of file
+const ValuesTD = `{"actions":{"queryAction":{"@type":"hiveot:function","description":"Read the current action status of a Thing","title":"Action status","idempotent":true,"input":{"readOnly":false,"type":"object","properties":{"name":{"title":"Action Name","description":"The action name to query","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"ID of the Thing to query","readOnly":false,"type":"string"}},"required":["thingID","name"]},"output":{"title":"Action value","description":"The latest action value","readOnly":false,"type":"ActionStatus"},"safe":true},"readAllEvents":{"@type":"hiveot:function","description":"Read the latest known event values of a Thing","title":"Read all event values","idempotent":true,"input":{"title":"Thing ID","description":"ID of the Thing to read","readOnly":false,"type":"string"},"output":{"title":"Event values","description":"List with the most recent event value objects","readOnly":false,"type":"array","items":{"title":"Event value","readOnly":false,"type":"ThingValue"}},"safe":true},"readAllProperties":{"@type":"hiveot:function","description":"Read the latest known property values","title":"Read all properties","idempotent":true,"input":{"title":"Thing ID","description":"Digital twin ID of the Thing to read","readOnly":false,"type":"string"},"output":{"title":"Property values","description":"List of ThingValue objects","readOnly":false,"type":"array","items":{"title":"Property Value","readOnly":false,"type":"ThingValue"}},"safe":true},"readEvent":{"@type":"hiveot:function","description":"Read the latest event value of a Thing","title":"Read event value","idempotent":true,"input":{"readOnly":false,"type":"object","properties":{"name":{"title":"Event name","description":"Name of the event to read the latest values","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"ID of the Thing to read","readOnly":false,"type":"string"}},"required":["thingID","name"]},"output":{"title":"Event value","description":"Most recent event value","readOnly":false,"type":"ThingValue"},"safe":true},"readProperty":{"@type":"hiveot:function","description":"Read the latest property value","title":"Read property value","idempotent":true,"input":{"readOnly":false,"type":"object","properties":{"name":{"title":"Property name","description":"The property name whose value to read","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"ID of the Thing to read","readOnly":false,"type":"string"}},"required":["thingID","name"]},"output":{"title":"Property value","description":"Most recent property value","readOnly":false,"type":"ThingValue"},"safe":true}},"@context":["https://www.w3.org/2022/wot/td/v1.1",{"ht":"https://www.hiveot.net/vocab/v0.1"}],"@type":"Service","created":"2024-10-04T17:00:00.000Z","deny":["none"],"description":"Last known property, event and action values","events":{"progress":{"description":"Progress notification of a property write or thing action request","title":"Progress","data":{"readOnly":false,"type":"object","properties":{"data":{"title":"Data","description":"Input value in format as described by the thing's property affordance","readOnly":false,"type":"any"},"id":{"title":"Thing ID","description":"Thing ID of thing whose value is updated","readOnly":false,"type":"string"},"messageType":{"title":"Message Type","description":"Type of change request","enum":["action","property"],"readOnly":false,"type":"string"},"name":{"title":"Property name","description":"Name of the property or action the notification applies to","readOnly":false,"type":"string"},"requestID":{"title":"Message ID","description":"link to action or property write that triggered the update","readOnly":false,"type":"string"},"senderID":{"title":"Sender ID","description":"ID of the sender of the request","readOnly":false,"type":"string"},"status":{"title":"Progress status","description":"The new status of the update progress.","readOnly":false,"type":"string"},"statusInfo":{"title":"Additional status information","readOnly":false,"type":"string"}}}}},"id":"values","modified":"2024-10-04T17:00:00.000Z","properties":null,"schemaDefinitions":{"ActionStatus":{"title":"Action Status","description":"Status of the last action","readOnly":false,"type":"object","properties":{"agentID":{"title":"Agent ID","description":"The agent handling the action","readOnly":false,"type":"string"},"error":{"title":"Error","description":"Action error info when failed","readOnly":false,"type":"string"},"input":{"title":"Action input","description":"Action input value","readOnly":false,"type":"any"},"name":{"title":"Action name","description":"name of the action or property","readOnly":false,"type":"string"},"output":{"title":"Action output","readOnly":false,"type":"any"},"requestID":{"title":"Request ID","description":"The action request identifier","readOnly":false,"type":"string"},"senderID":{"title":"Consumer ID","readOnly":false,"type":"string"},"status":{"title":"Action status","description":"Status of the action's progress","readOnly":false,"type":"string"},"thingID":{"title":"Action Thing","description":"Digital twin ThingID the action applies to","readOnly":false,"type":"string"},"timeEnded":{"title":"End Time","description":"Time the action has completed or failed","readOnly":false,"type":"dateTime"},"timeRequested":{"title":"Creation Time","description":"Time the action was initially requested","readOnly":false,"type":"dateTime"},"timeUpdated":{"title":"Updated time","description":"Time the action status was last updated","readOnly":false,"type":"dateTime"}}},"ThingValue":{"title":"Thing Value","description":"Property or event value","readOnly":false,"type":"object","properties":{"created":{"title":"Updated time","description":"Time the value was last updated","readOnly":false,"type":"dateTime"},"data":{"title":"Payload","description":"Data in format as described by the thing's property affordance","readOnly":false,"type":"any"},"name":{"title":"Name","description":"Name of the property holding the value","readOnly":false,"type":"string"},"thingID":{"title":"Thing ID","description":"Digital twin Thing ID","readOnly":false,"type":"string"}}}},"security":["bearer"],"securityDefinitions":{"bearer":{"description":"HTTP protocol authentication","scheme":"bearer","name":"authentication","alg":"es256","format":"jwt","in":"header"}},"title":"DigiTwin Values","support":"https://www.github.com/hiveot/hub"}`
\ No newline at end of file
diff --git a/api/go/vocab/vocab.go b/api/go/vocab/vocab.go
index 12712c00..e72e0fc4 100644
--- a/api/go/vocab/vocab.go
+++ b/api/go/vocab/vocab.go
@@ -4,7 +4,7 @@ package vocab
 
 // type: ActionStatusStatus
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-constants.yaml
 // description: Request progress status constants
 const (
@@ -17,7 +17,7 @@ const (
 
 // type: WoTVocab
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/wot-vocab.yaml
 // description: WoT vocabulary definition. See https://www.w3.org/TR/2020/WD-wot-thing-description11-20201124/#sec-core-vocabulary-definition
 const (
@@ -109,7 +109,7 @@ const (
 
 // type: ActionClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-action-classes.yaml
 // namespace: ht
 const (
@@ -145,33 +145,33 @@ var ActionClassesMap = map[string]struct {
 } {
   ActionMediaVolume: {Symbol: "", Title: "Volume", Description: "Set volume level"},
   ActionMediaVolumeIncrease: {Symbol: "", Title: "Increase volume", Description: "Increase volume"},
-  ActionDimmerDecrement: {Symbol: "", Title: "Lower dimmer", Description: ""},
-  ActionThingStop: {Symbol: "", Title: "Stop", Description: "Stop a running task"},
-  ActionMediaPause: {Symbol: "", Title: "Pause", Description: "Pause playback"},
+  ActionDimmerSet: {Symbol: "", Title: "Set dimmer", Description: "Action to set the dimmer value"},
+  ActionThingStart: {Symbol: "", Title: "Start", Description: "Start running a task"},
+  ActionMediaNext: {Symbol: "", Title: "Next", Description: "Next track or station"},
+  ActionMediaUnmute: {Symbol: "", Title: "Unmute", Description: "Unmute audio"},
   ActionMediaPrevious: {Symbol: "", Title: "Previous", Description: "Previous track or station"},
-  ActionMediaVolumeDecrease: {Symbol: "", Title: "Decrease volume", Description: "Decrease volume"},
-  ActionDimmer: {Symbol: "", Title: "Dimmer", Description: "General dimmer action"},
+  ActionDimmerDecrement: {Symbol: "", Title: "Lower dimmer", Description: ""},
   ActionDimmerIncrement: {Symbol: "", Title: "Increase dimmer", Description: ""},
+  ActionSwitch: {Symbol: "", Title: "Switch", Description: "General switch action"},
   ActionSwitchOnOff: {Symbol: "", Title: "Set On/Off switch", Description: "Action to set the switch on/off state"},
+  ActionMedia: {Symbol: "", Title: "Media control", Description: "Commands to control media recording and playback"},
+  ActionMediaPause: {Symbol: "", Title: "Pause", Description: "Pause playback"},
   ActionThingDisable: {Symbol: "", Title: "Disable", Description: "Action to disable a thing"},
-  ActionValveOpen: {Symbol: "", Title: "Open valve", Description: "Action to open the valve"},
-  ActionMediaNext: {Symbol: "", Title: "Next", Description: "Next track or station"},
-  ActionSwitch: {Symbol: "", Title: "Switch", Description: "General switch action"},
+  ActionValveClose: {Symbol: "", Title: "Close valve", Description: "Action to close the valve"},
+  ActionMediaPlay: {Symbol: "", Title: "Play", Description: "Start or continue playback"},
   ActionSwitchToggle: {Symbol: "", Title: "Toggle switch", Description: "Action to toggle the switch"},
+  ActionDimmer: {Symbol: "", Title: "Dimmer", Description: "General dimmer action"},
   ActionThingEnable: {Symbol: "", Title: "Enable", Description: "Action to enable a thing"},
-  ActionThingStart: {Symbol: "", Title: "Start", Description: "Start running a task"},
-  ActionValveClose: {Symbol: "", Title: "Close valve", Description: "Action to close the valve"},
+  ActionThingStop: {Symbol: "", Title: "Stop", Description: "Stop a running task"},
+  ActionValveOpen: {Symbol: "", Title: "Open valve", Description: "Action to open the valve"},
   ActionMediaMute: {Symbol: "", Title: "Mute", Description: "Mute audio"},
-  ActionMediaPlay: {Symbol: "", Title: "Play", Description: "Start or continue playback"},
-  ActionMediaUnmute: {Symbol: "", Title: "Unmute", Description: "Unmute audio"},
-  ActionDimmerSet: {Symbol: "", Title: "Set dimmer", Description: "Action to set the dimmer value"},
-  ActionMedia: {Symbol: "", Title: "Media control", Description: "Commands to control media recording and playback"},
+  ActionMediaVolumeDecrease: {Symbol: "", Title: "Decrease volume", Description: "Decrease volume"},
 }
 
 
 // type: PropertyClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-property-classes.yaml
 // namespace: ht
 const (
@@ -262,92 +262,92 @@ const (
 var PropertyClassesMap = map[string]struct {
    Symbol string; Title string; Description string
 } {
-  PropNetLatency: {Symbol: "", Title: "Network latency", Description: "Delay between hub and client"},
-  PropAlarmMotion: {Symbol: "", Title: "Motion", Description: "Motion detected"},
-  PropDeviceStatus: {Symbol: "", Title: "Status", Description: "Device status; alive, awake, dead, sleeping"},
-  PropElectricEnergy: {Symbol: "", Title: "Energy", Description: "Electrical energy consumed"},
-  PropLocationStreet: {Symbol: "", Title: "Street", Description: "Street address"},
-  PropStatusStartedStopped: {Symbol: "", Title: "Started/Stopped", Description: "Started or stopped status"},
-  PropElectricVoltage: {Symbol: "", Title: "Voltage", Description: "Electrical voltage potential"},
-  PropLocationCity: {Symbol: "", Title: "City", Description: "City name"},
-  PropNetSubnet: {Symbol: "", Title: "Subnet", Description: "Network subnet address. Example: 192.168.0.0"},
-  PropMediaTrack: {Symbol: "", Title: "Track", Description: "Selected A/V track"},
-  PropNet: {Symbol: "", Title: "Network properties", Description: "General network properties"},
+  PropMediaMuted: {Symbol: "", Title: "Muted", Description: "Audio is muted"},
   PropNetIP4: {Symbol: "", Title: "IP4 address", Description: "Device IP4 address"},
-  PropSwitchOnOff: {Symbol: "", Title: "On/Off switch", Description: ""},
-  PropMediaPlaying: {Symbol: "", Title: "Playing", Description: "Media is playing"},
-  PropSwitchDimmer: {Symbol: "", Title: "Dimmer value", Description: ""},
-  PropAlarmStatus: {Symbol: "", Title: "Alarm state", Description: "Current alarm status"},
   PropDeviceModel: {Symbol: "", Title: "Model", Description: "Device model"},
-  PropEnvFuelLevel: {Symbol: "", Title: "Fuel level", Description: ""},
-  PropEnvTemperature: {Symbol: "", Title: "Temperature", Description: ""},
-  PropEnv: {Symbol: "", Title: "Environmental property", Description: "Property of environmental sensor"},
-  PropNetSignalstrength: {Symbol: "", Title: "Signal strength", Description: "Wireless signal strength"},
-  PropNetPort: {Symbol: "", Title: "Port", Description: "Network port"},
-  PropSwitch: {Symbol: "", Title: "Switch status", Description: ""},
-  PropSwitchLocked: {Symbol: "", Title: "Lock", Description: "Electric lock status"},
-  PropDeviceFirmwareVersion: {Symbol: "", Title: "Firmware version", Description: ""},
   PropEnvFuelFlowrate: {Symbol: "", Title: "Fuel flow rate", Description: ""},
-  PropEnvVibration: {Symbol: "", Title: "Vibration", Description: ""},
-  PropNetMask: {Symbol: "", Title: "Netmask", Description: "Network mask. Example: 255.255.255.0 or 24/8"},
-  PropEnvWaterLevel: {Symbol: "", Title: "Water level", Description: ""},
-  PropDeviceMake: {Symbol: "", Title: "Make", Description: "Device manufacturer"},
-  PropEnvAcceleration: {Symbol: "", Title: "Acceleration", Description: ""},
-  PropEnvBarometer: {Symbol: "", Title: "Atmospheric pressure", Description: "Barometric pressure of the atmosphere"},
+  PropEnvHumidex: {Symbol: "", Title: "Humidex", Description: ""},
+  PropLocationStreet: {Symbol: "", Title: "Street", Description: "Street address"},
+  PropMedia: {Symbol: "", Title: "Media commands", Description: "Control of media equipment"},
+  PropMediaVolume: {Symbol: "", Title: "Volume", Description: "Media volume setting"},
+  PropNetPort: {Symbol: "", Title: "Port", Description: "Network port"},
+  PropDeviceBattery: {Symbol: "", Title: "Battery level", Description: "Device battery level"},
   PropEnvPressure: {Symbol: "", Title: "Pressure", Description: ""},
   PropEnvWindHeading: {Symbol: "", Title: "Wind heading", Description: ""},
+  PropLocation: {Symbol: "", Title: "Location", Description: "General location information"},
+  PropStatusOpenClosed: {Symbol: "", Title: "Open/Closed status", Description: ""},
+  PropSwitchLight: {Symbol: "", Title: "Light switch", Description: ""},
+  PropEnvFuelLevel: {Symbol: "", Title: "Fuel level", Description: ""},
+  PropEnvWaterFlowrate: {Symbol: "", Title: "Water flow rate", Description: ""},
   PropLocationZipcode: {Symbol: "", Title: "Zip code", Description: "Location ZIP code"},
-  PropNetHostname: {Symbol: "", Title: "Hostname", Description: "Hostname of the client"},
+  PropNetSubnet: {Symbol: "", Title: "Subnet", Description: "Network subnet address. Example: 192.168.0.0"},
+  PropEnvDewpoint: {Symbol: "", Title: "Dew point", Description: "Dew point temperature"},
+  PropNetConnection: {Symbol: "", Title: "Connection", Description: "Connection status, connected, connecting, retrying, disconnected,..."},
+  PropSwitchLocked: {Symbol: "", Title: "Lock", Description: "Electric lock status"},
   PropElectricOverload: {Symbol: "", Title: "Overload protection", Description: "Cut load on overload"},
-  PropEnvCO2: {Symbol: "", Title: "Carbon dioxide level", Description: "Carbon dioxide level"},
+  PropLocationName: {Symbol: "", Title: "Location name", Description: "Name of the location"},
+  PropNetMAC: {Symbol: "", Title: "MAC", Description: "Hardware MAC address"},
   PropEnvHumidity: {Symbol: "", Title: "Humidity", Description: ""},
-  PropEnvLuminance: {Symbol: "", Title: "Luminance", Description: ""},
-  PropDeviceEnabledDisabled: {Symbol: "", Title: "Enabled/Disabled", Description: "Enabled or disabled state"},
-  PropEnvWindSpeed: {Symbol: "", Title: "Wind speed", Description: ""},
-  PropLocationLatitude: {Symbol: "", Title: "Latitude", Description: "Latitude geographic coordinate"},
-  PropStatusYesNo: {Symbol: "", Title: "Yes/No", Description: "Status with yes or no value"},
-  PropMediaMuted: {Symbol: "", Title: "Muted", Description: "Audio is muted"},
-  PropNetAddress: {Symbol: "", Title: "Address", Description: "Network address"},
+  PropStatusOnOff: {Symbol: "", Title: "On/off status", Description: ""},
+  PropDeviceDescription: {Symbol: "", Title: "Description", Description: "Device product description"},
+  PropDeviceHardwareVersion: {Symbol: "", Title: "Hardware version", Description: ""},
+  PropElectricCurrent: {Symbol: "", Title: "Current", Description: "Electrical current"},
+  PropEnvCO: {Symbol: "", Title: "Carbon monoxide level", Description: "Carbon monoxide level"},
+  PropEnv: {Symbol: "", Title: "Environmental property", Description: "Property of environmental sensor"},
   PropEnvCpuload: {Symbol: "", Title: "CPU load level", Description: "Device CPU load level"},
-  PropEnvUV: {Symbol: "", Title: "UV", Description: ""},
-  PropEnvVolume: {Symbol: "", Title: "Volume", Description: ""},
+  PropLocationLongitude: {Symbol: "", Title: "Longitude", Description: "Longitude geographic coordinate"},
+  PropNetSignalstrength: {Symbol: "", Title: "Signal strength", Description: "Wireless signal strength"},
   PropMediaPaused: {Symbol: "", Title: "Paused", Description: "Media is paused"},
-  PropSwitchLight: {Symbol: "", Title: "Light switch", Description: ""},
+  PropMediaTrack: {Symbol: "", Title: "Track", Description: "Selected A/V track"},
+  PropNetHostname: {Symbol: "", Title: "Hostname", Description: "Hostname of the client"},
   PropDeviceTitle: {Symbol: "", Title: "Title", Description: "Device friendly title"},
-  PropElectricCurrent: {Symbol: "", Title: "Current", Description: "Electrical current"},
-  PropEnvCO: {Symbol: "", Title: "Carbon monoxide level", Description: "Carbon monoxide level"},
-  PropLocationName: {Symbol: "", Title: "Location name", Description: "Name of the location"},
-  PropDeviceDescription: {Symbol: "", Title: "Description", Description: "Device product description"},
-  PropEnvAirquality: {Symbol: "", Title: "Air quality", Description: "Air quality level"},
-  PropEnvHumidex: {Symbol: "", Title: "Humidex", Description: ""},
-  PropStatusOnOff: {Symbol: "", Title: "On/off status", Description: ""},
-  PropDevice: {Symbol: "", Title: "Device attributes", Description: "Attributes describing a device"},
-  PropEnvTimezone: {Symbol: "", Title: "Timezone", Description: ""},
+  PropElectricPower: {Symbol: "", Title: "Power", Description: "Electrical power being consumed"},
+  PropElectricVoltage: {Symbol: "", Title: "Voltage", Description: "Electrical voltage potential"},
+  PropEnvVolume: {Symbol: "", Title: "Volume", Description: ""},
+  PropEnvTemperature: {Symbol: "", Title: "Temperature", Description: ""},
   PropNetGateway: {Symbol: "", Title: "Gateway", Description: "Network gateway address"},
-  PropEnvDewpoint: {Symbol: "", Title: "Dew point", Description: "Dew point temperature"},
-  PropEnvWaterFlowrate: {Symbol: "", Title: "Water flow rate", Description: ""},
-  PropLocationLongitude: {Symbol: "", Title: "Longitude", Description: "Longitude geographic coordinate"},
-  PropNetConnection: {Symbol: "", Title: "Connection", Description: "Connection status, connected, connecting, retrying, disconnected,..."},
-  PropDevicePollinterval: {Symbol: "", Title: "Polling interval", Description: "Interval to poll for updates"},
-  PropDeviceSoftwareVersion: {Symbol: "", Title: "Software version", Description: ""},
+  PropNetLatency: {Symbol: "", Title: "Network latency", Description: "Delay between hub and client"},
+  PropStatusStartedStopped: {Symbol: "", Title: "Started/Stopped", Description: "Started or stopped status"},
   PropElectric: {Symbol: "", Title: "Electrical properties", Description: "General group of electrical properties"},
-  PropElectricPower: {Symbol: "", Title: "Power", Description: "Electrical power being consumed"},
+  PropEnvCO2: {Symbol: "", Title: "Carbon dioxide level", Description: "Carbon dioxide level"},
+  PropLocationCity: {Symbol: "", Title: "City", Description: "City name"},
+  PropMediaPlaying: {Symbol: "", Title: "Playing", Description: "Media is playing"},
+  PropEnvUV: {Symbol: "", Title: "UV", Description: ""},
+  PropEnvWaterLevel: {Symbol: "", Title: "Water level", Description: ""},
   PropNetIP6: {Symbol: "", Title: "IP6 address", Description: "Device IP6 address"},
-  PropStatusOpenClosed: {Symbol: "", Title: "Open/Closed status", Description: ""},
-  PropMediaVolume: {Symbol: "", Title: "Volume", Description: "Media volume setting"},
-  PropMediaStation: {Symbol: "", Title: "Station", Description: "Selected radio station"},
+  PropSwitchOnOff: {Symbol: "", Title: "On/Off switch", Description: ""},
+  PropAlarmStatus: {Symbol: "", Title: "Alarm state", Description: "Current alarm status"},
+  PropAlarmMotion: {Symbol: "", Title: "Motion", Description: "Motion detected"},
+  PropDeviceEnabledDisabled: {Symbol: "", Title: "Enabled/Disabled", Description: "Enabled or disabled state"},
+  PropDeviceFirmwareVersion: {Symbol: "", Title: "Firmware version", Description: ""},
+  PropNetMask: {Symbol: "", Title: "Netmask", Description: "Network mask. Example: 255.255.255.0 or 24/8"},
+  PropDevicePollinterval: {Symbol: "", Title: "Polling interval", Description: "Interval to poll for updates"},
+  PropDeviceSoftwareVersion: {Symbol: "", Title: "Software version", Description: ""},
+  PropEnvLuminance: {Symbol: "", Title: "Luminance", Description: ""},
+  PropNetAddress: {Symbol: "", Title: "Address", Description: "Network address"},
+  PropSwitchDimmer: {Symbol: "", Title: "Dimmer value", Description: ""},
+  PropDevice: {Symbol: "", Title: "Device attributes", Description: "Attributes describing a device"},
+  PropDeviceMake: {Symbol: "", Title: "Make", Description: "Device manufacturer"},
+  PropEnvVibration: {Symbol: "", Title: "Vibration", Description: ""},
+  PropStatusYesNo: {Symbol: "", Title: "Yes/No", Description: "Status with yes or no value"},
+  PropEnvBarometer: {Symbol: "", Title: "Atmospheric pressure", Description: "Barometric pressure of the atmosphere"},
+  PropNet: {Symbol: "", Title: "Network properties", Description: "General network properties"},
   PropNetDomainname: {Symbol: "", Title: "Domain name", Description: "Domainname of the client"},
-  PropNetMAC: {Symbol: "", Title: "MAC", Description: "Hardware MAC address"},
-  PropDeviceBattery: {Symbol: "", Title: "Battery level", Description: "Device battery level"},
-  PropDeviceHardwareVersion: {Symbol: "", Title: "Hardware version", Description: ""},
-  PropLocation: {Symbol: "", Title: "Location", Description: "General location information"},
-  PropMedia: {Symbol: "", Title: "Media commands", Description: "Control of media equipment"},
+  PropElectricEnergy: {Symbol: "", Title: "Energy", Description: "Electrical energy consumed"},
+  PropEnvAirquality: {Symbol: "", Title: "Air quality", Description: "Air quality level"},
+  PropEnvWindSpeed: {Symbol: "", Title: "Wind speed", Description: ""},
+  PropMediaStation: {Symbol: "", Title: "Station", Description: "Selected radio station"},
+  PropSwitch: {Symbol: "", Title: "Switch status", Description: ""},
+  PropDeviceStatus: {Symbol: "", Title: "Status", Description: "Device status; alive, awake, dead, sleeping"},
+  PropEnvAcceleration: {Symbol: "", Title: "Acceleration", Description: ""},
+  PropEnvTimezone: {Symbol: "", Title: "Timezone", Description: ""},
+  PropLocationLatitude: {Symbol: "", Title: "Latitude", Description: "Latitude geographic coordinate"},
 }
 
 
 // type: ThingClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-thing-classes.yaml
 // namespace: ht
 const (
@@ -454,108 +454,108 @@ const (
 var ThingClassesMap = map[string]struct {
    Symbol string; Title string; Description string
 } {
-  ThingComputerVoipPhone: {Symbol: "", Title: "VoIP Phone", Description: "Voice over IP phone"},
-  ThingControlKeypad: {Symbol: "", Title: "Keypad", Description: "Multi-key pad for command input"},
-  ThingNetGatewayZwave: {Symbol: "", Title: "ZWave gateway", Description: "Gateway providing access to ZWave devices"},
-  ThingSensorSmoke: {Symbol: "", Title: "Smoke detector", Description: ""},
-  ThingSensorWaterLeak: {Symbol: "", Title: "Water leak detector", Description: "Dedicated water leak detector"},
-  ThingActuatorLight: {Symbol: "", Title: "Light", Description: "Smart LED or other light"},
-  ThingApplianceDishwasher: {Symbol: "", Title: "Dishwasher", Description: "Dishwasher"},
-  ThingMediaMicrophone: {Symbol: "", Title: "Microphone", Description: "Microphone for capturing audio"},
-  ThingMediaSpeaker: {Symbol: "", Title: "Connected speakers", Description: "Network connected speakers"},
-  ThingMediaTV: {Symbol: "", Title: "TV", Description: "Network connected television"},
-  ThingMeterWind: {Symbol: "", Title: "Wind", Description: "Dedicated wind meter"},
-  ThingNetLora: {Symbol: "", Title: "LoRa network device", Description: "Generic Long Range network protocol device"},
-  ThingActuatorLock: {Symbol: "", Title: "Lock", Description: "Electronic door lock"},
-  ThingNetWifi: {Symbol: "", Title: "Wifi device", Description: "Generic wifi device"},
-  ThingSensorMulti: {Symbol: "", Title: "Multi sensor", Description: "Sense multiple inputs"},
+  ThingSensorSecurity: {Symbol: "", Title: "Security", Description: "Generic security sensor"},
+  ThingSensorSound: {Symbol: "", Title: "Sound detector", Description: ""},
   ThingActuatorValve: {Symbol: "", Title: "Valve", Description: "Electric powered valve for fluids or gas"},
-  ThingMediaRadio: {Symbol: "", Title: "Radio", Description: "AM or FM radio receiver"},
-  ThingMeterWaterLevel: {Symbol: "", Title: "Water level", Description: "Dedicated water level meter"},
-  ThingNetGatewayOnewire: {Symbol: "", Title: "1-Wire gateway", Description: "Gateway providing access to 1-wire devices"},
+  ThingComputerPC: {Symbol: "", Title: "PC/Laptop", Description: "Personal computer/laptop"},
+  ThingMedia: {Symbol: "", Title: "A/V media", Description: "Generic device for audio/video media record or playback"},
   ThingSensorInput: {Symbol: "", Title: "Input sensor", Description: "General purpose electrical input sensor"},
-  ThingMeterFuelFlow: {Symbol: "", Title: "Fuel flow rate", Description: "Dedicated fuel flow rate metering device"},
-  ThingComputer: {Symbol: "", Title: "Computing Device", Description: "General purpose computing device"},
-  ThingComputerTablet: {Symbol: "", Title: "Tablet", Description: "Tablet computer"},
-  ThingControlClimate: {Symbol: "", Title: "Climate control", Description: "Device for controlling climate of a space"},
-  ThingControlIrrigation: {Symbol: "", Title: "Irrigation control", Description: "Device for control of an irrigation system"},
-  ThingDeviceBatteryMonitor: {Symbol: "", Title: "Battery Monitor", Description: "Battery monitor and charge controller"},
-  ThingMeterElectricCurrent: {Symbol: "", Title: "Electric current", Description: "Electrical current meter"},
-  ThingMeterElectricPower: {Symbol: "", Title: "Electrical Power", Description: "Electrical power meter"},
-  ThingSensorSecurityDoorWindow: {Symbol: "", Title: "Door/Window sensor", Description: "Dedicated door/window opening security sensor"},
+  ThingMeterWind: {Symbol: "", Title: "Wind", Description: "Dedicated wind meter"},
+  ThingSensorEnvironment: {Symbol: "", Title: "Environmental sensor", Description: "Environmental sensor with one or more features such as temperature, humidity, etc"},
   ThingActuatorRanged: {Symbol: "", Title: "Ranged actuator", Description: "Generic ranged actuator with a set point"},
+  ThingControlIrrigation: {Symbol: "", Title: "Irrigation control", Description: "Device for control of an irrigation system"},
+  ThingControlKeypad: {Symbol: "", Title: "Keypad", Description: "Multi-key pad for command input"},
+  ThingMediaAmplifier: {Symbol: "", Title: "Audio amplifier", Description: "Audio amplifier with volume controls"},
+  ThingMeterWaterConsumption: {Symbol: "", Title: "Water consumption meter", Description: "Water consumption meter"},
+  ThingNetGatewayZigbee: {Symbol: "", Title: "Zigbee gateway", Description: "Gateway providing access to Zigbee devices"},
+  ThingSensorSecurityMotion: {Symbol: "", Title: "Motion sensor", Description: "Dedicated security sensor detecting motion"},
+  ThingSensorSmoke: {Symbol: "", Title: "Smoke detector", Description: ""},
+  ThingApplianceFridge: {Symbol: "", Title: "Fridge", Description: "Refrigerator appliance"},
+  ThingComputerVoipPhone: {Symbol: "", Title: "VoIP Phone", Description: "Voice over IP phone"},
+  ThingControlThermostat: {Symbol: "", Title: "Thermostat", Description: "Thermostat HVAC control"},
+  ThingMeterFuelFlow: {Symbol: "", Title: "Fuel flow rate", Description: "Dedicated fuel flow rate metering device"},
+  ThingApplianceWasher: {Symbol: "", Title: "Washer", Description: "Clothing washer"},
+  ThingMediaCamera: {Symbol: "", Title: "Camera", Description: "Video camera"},
+  ThingMediaRadio: {Symbol: "", Title: "Radio", Description: "AM or FM radio receiver"},
+  ThingMeter: {Symbol: "", Title: "Meter", Description: "General metering device"},
+  ThingActuator: {Symbol: "", Title: "Actuator", Description: "Generic actuator"},
+  ThingActuatorValveWater: {Symbol: "", Title: "Water valve", Description: "Electric powered water valve"},
   ThingActuatorValveFuel: {Symbol: "", Title: "Fuel valve", Description: "Electric powered fuel valve"},
-  ThingComputerCellphone: {Symbol: "", Title: "Cell Phone", Description: "Cellular phone"},
-  ThingComputerEmbedded: {Symbol: "", Title: "Embedded System", Description: "Embedded computing device"},
-  ThingNetGatewayCoap: {Symbol: "", Title: "CoAP gateway", Description: "Gateway providing access to CoAP devices"},
+  ThingApplianceFreezer: {Symbol: "", Title: "Freezer", Description: "Refrigerator freezer"},
+  ThingControlPushbutton: {Symbol: "", Title: "Momentary switch", Description: "Momentary push button control input"},
+  ThingDeviceTime: {Symbol: "", Title: "Clock", Description: "Time tracking device such as clocks and time chips"},
+  ThingNetWifiAp: {Symbol: "", Title: "Wifi access point", Description: "Wireless access point for IP networks"},
+  ThingSensorSecurityGlass: {Symbol: "", Title: "Glass sensor", Description: "Dedicated sensor for detecting breaking of glass"},
   ThingActuatorDimmer: {Symbol: "", Title: "Dimmer", Description: "Light dimmer"},
-  ThingActuatorOutput: {Symbol: "", Title: "Output", Description: "General purpose electrical output signal"},
-  ThingMedia: {Symbol: "", Title: "A/V media", Description: "Generic device for audio/video media record or playback"},
-  ThingMeterElectric: {Symbol: "", Title: "", Description: ""},
-  ThingNetBluetooth: {Symbol: "", Title: "Bluetooth", Description: "Bluetooth radio"},
-  ThingActuatorMotor: {Symbol: "", Title: "Motor", Description: "Motor driven actuator, such as garage door, blinds, tv lifts"},
-  ThingActuatorValveWater: {Symbol: "", Title: "Water valve", Description: "Electric powered water valve"},
+  ThingApplianceDishwasher: {Symbol: "", Title: "Dishwasher", Description: "Dishwasher"},
+  ThingComputerEmbedded: {Symbol: "", Title: "Embedded System", Description: "Embedded computing device"},
   ThingControlDimmer: {Symbol: "", Title: "Dimmer", Description: "Light dimmer input device"},
-  ThingControlJoystick: {Symbol: "", Title: "Joystick", Description: "Flight control stick"},
-  ThingControlPushbutton: {Symbol: "", Title: "Momentary switch", Description: "Momentary push button control input"},
-  ThingMediaCamera: {Symbol: "", Title: "Camera", Description: "Video camera"},
-  ThingControlSwitch: {Symbol: "", Title: "Input switch", Description: "On or off switch input control"},
-  ThingMeterElectricVoltage: {Symbol: "", Title: "Voltage", Description: "Electrical voltage meter"},
-  ThingMeterWaterFlow: {Symbol: "", Title: "Water flow", Description: "Dedicated water flow-rate meter"},
-  ThingNetGatewayInsteon: {Symbol: "", Title: "Insteon gateway", Description: "Gateway providing access to Insteon devices"},
-  ThingSensor: {Symbol: "", Title: "Sensor", Description: "Generic sensor device"},
-  ThingSensorSecurityMotion: {Symbol: "", Title: "Motion sensor", Description: "Dedicated security sensor detecting motion"},
+  ThingMeterWaterLevel: {Symbol: "", Title: "Water level", Description: "Dedicated water level meter"},
+  ThingNetBluetooth: {Symbol: "", Title: "Bluetooth", Description: "Bluetooth radio"},
   ThingSensorScale: {Symbol: "", Title: "Scale", Description: "Electronic weigh scale"},
-  ThingComputerPC: {Symbol: "", Title: "PC/Laptop", Description: "Personal computer/laptop"},
-  ThingControlToggle: {Symbol: "", Title: "Toggle switch", Description: "Toggle switch input control"},
-  ThingDeviceIndicator: {Symbol: "", Title: "Indicator", Description: "Visual or audio indicator device"},
-  ThingSensorSecurityGlass: {Symbol: "", Title: "Glass sensor", Description: "Dedicated sensor for detecting breaking of glass"},
-  ThingSensorSound: {Symbol: "", Title: "Sound detector", Description: ""},
-  ThingNetLoraGateway: {Symbol: "", Title: "LoRaWAN gateway", Description: "Gateway providing access to LoRa devices"},
-  ThingActuatorAlarm: {Symbol: "", Title: "Alarm", Description: "Siren or light alarm"},
   ThingActuatorBeacon: {Symbol: "", Title: "Beacon", Description: "Location beacon"},
-  ThingControlPool: {Symbol: "", Title: "Pool control", Description: "Device for controlling pool settings"},
-  ThingDevice: {Symbol: "", Title: "Device", Description: "Device of unknown purpose"},
-  ThingMediaReceiver: {Symbol: "", Title: "Receiver", Description: "Audio/video receiver and player"},
-  ThingMeter: {Symbol: "", Title: "Meter", Description: "General metering device"},
-  ThingNetSwitch: {Symbol: "", Title: "Network switch", Description: "Network switch to connect computer devices to the network"},
-  ThingControlThermostat: {Symbol: "", Title: "Thermostat", Description: "Thermostat HVAC control"},
+  ThingComputerCellphone: {Symbol: "", Title: "Cell Phone", Description: "Cellular phone"},
+  ThingMeterElectricPower: {Symbol: "", Title: "Electrical Power", Description: "Electrical power meter"},
   ThingMeterWater: {Symbol: "", Title: "Water metering device", Description: "General water metering device"},
-  ThingSensorEnvironment: {Symbol: "", Title: "Environmental sensor", Description: "Environmental sensor with one or more features such as temperature, humidity, etc"},
+  ThingNetWifi: {Symbol: "", Title: "Wifi device", Description: "Generic wifi device"},
+  ThingSensorWaterLeak: {Symbol: "", Title: "Water leak detector", Description: "Dedicated water leak detector"},
+  ThingService: {Symbol: "", Title: "Service", Description: "General service for processing data and offering features of interest"},
+  ThingActuatorLight: {Symbol: "", Title: "Light", Description: "Smart LED or other light"},
+  ThingActuatorOutput: {Symbol: "", Title: "Output", Description: "General purpose electrical output signal"},
+  ThingComputerPotsPhone: {Symbol: "", Title: "Land Line", Description: "Plain Old Telephone System, aka landline"},
+  ThingMeterElectric: {Symbol: "", Title: "", Description: ""},
+  ThingComputerTablet: {Symbol: "", Title: "Tablet", Description: "Tablet computer"},
+  ThingMeterElectricVoltage: {Symbol: "", Title: "Voltage", Description: "Electrical voltage meter"},
   ThingSensorThermometer: {Symbol: "", Title: "Thermometer", Description: "Environmental thermometer"},
-  ThingApplianceFridge: {Symbol: "", Title: "Fridge", Description: "Refrigerator appliance"},
+  ThingActuatorLock: {Symbol: "", Title: "Lock", Description: "Electronic door lock"},
+  ThingControlToggle: {Symbol: "", Title: "Toggle switch", Description: "Toggle switch input control"},
+  ThingMeterWaterFlow: {Symbol: "", Title: "Water flow", Description: "Dedicated water flow-rate meter"},
+  ThingNetSwitch: {Symbol: "", Title: "Network switch", Description: "Network switch to connect computer devices to the network"},
+  ThingNetRouter: {Symbol: "", Title: "Network router", Description: "IP ThingNetwork router providing access to other IP networks"},
+  ThingNetLoraGateway: {Symbol: "", Title: "LoRaWAN gateway", Description: "Gateway providing access to LoRa devices"},
   ThingControl: {Symbol: "", Title: "Input controller", Description: "Generic input controller"},
-  ThingMeterFuel: {Symbol: "", Title: "Fuel metering device", Description: "General fuel metering device"},
-  ThingMeterWaterConsumption: {Symbol: "", Title: "Water consumption meter", Description: "Water consumption meter"},
-  ThingNetGatewayZigbee: {Symbol: "", Title: "Zigbee gateway", Description: "Gateway providing access to Zigbee devices"},
-  ThingSensorSecurity: {Symbol: "", Title: "Security", Description: "Generic security sensor"},
-  ThingService: {Symbol: "", Title: "Service", Description: "General service for processing data and offering features of interest"},
-  ThingActuatorRelay: {Symbol: "", Title: "Relay", Description: "Generic relay electrical switch"},
-  ThingActuatorSwitch: {Symbol: "", Title: "Switch", Description: "An electric powered on/off switch for powering circuits"},
+  ThingDeviceBatteryMonitor: {Symbol: "", Title: "Battery Monitor", Description: "Battery monitor and charge controller"},
+  ThingNetGatewayCoap: {Symbol: "", Title: "CoAP gateway", Description: "Gateway providing access to CoAP devices"},
+  ThingNetGatewayOnewire: {Symbol: "", Title: "1-Wire gateway", Description: "Gateway providing access to 1-wire devices"},
+  ThingNetGatewayZwave: {Symbol: "", Title: "ZWave gateway", Description: "Gateway providing access to ZWave devices"},
   ThingApplianceDryer: {Symbol: "", Title: "Dryer", Description: "Clothing dryer"},
-  ThingComputerSatPhone: {Symbol: "", Title: "Satellite phone", Description: ""},
-  ThingNetRouter: {Symbol: "", Title: "Network router", Description: "IP ThingNetwork router providing access to other IP networks"},
-  ThingNetWifiAp: {Symbol: "", Title: "Wifi access point", Description: "Wireless access point for IP networks"},
-  ThingNetLoraP2P: {Symbol: "", Title: "LoRa P2P", Description: "LoRa Peer-to-peer network device"},
-  ThingDeviceTime: {Symbol: "", Title: "Clock", Description: "Time tracking device such as clocks and time chips"},
+  ThingControlJoystick: {Symbol: "", Title: "Joystick", Description: "Flight control stick"},
+  ThingDeviceIndicator: {Symbol: "", Title: "Indicator", Description: "Visual or audio indicator device"},
   ThingNetGateway: {Symbol: "", Title: "Gateway", Description: "Generic gateway device providing access to other devices"},
+  ThingNetLoraP2P: {Symbol: "", Title: "LoRa P2P", Description: "LoRa Peer-to-peer network device"},
+  ThingMediaMicrophone: {Symbol: "", Title: "Microphone", Description: "Microphone for capturing audio"},
   ThingMediaPlayer: {Symbol: "", Title: "Media player", Description: "CD/DVD/Blueray/USB player of recorded media"},
-  ThingActuator: {Symbol: "", Title: "Actuator", Description: "Generic actuator"},
-  ThingAppliance: {Symbol: "", Title: "Appliance", Description: "Appliance to accomplish a particular task for occupant use"},
-  ThingApplianceFreezer: {Symbol: "", Title: "Freezer", Description: "Refrigerator freezer"},
-  ThingApplianceWasher: {Symbol: "", Title: "Washer", Description: "Clothing washer"},
+  ThingMediaSpeaker: {Symbol: "", Title: "Connected speakers", Description: "Network connected speakers"},
+  ThingMeterFuel: {Symbol: "", Title: "Fuel metering device", Description: "General fuel metering device"},
+  ThingMediaReceiver: {Symbol: "", Title: "Receiver", Description: "Audio/video receiver and player"},
+  ThingMediaTV: {Symbol: "", Title: "TV", Description: "Network connected television"},
+  ThingMeterFuelLevel: {Symbol: "", Title: "Fuel level", Description: "Dedicated fuel level metering device"},
+  ThingNetGatewayInsteon: {Symbol: "", Title: "Insteon gateway", Description: "Gateway providing access to Insteon devices"},
+  ThingActuatorAlarm: {Symbol: "", Title: "Alarm", Description: "Siren or light alarm"},
+  ThingActuatorMotor: {Symbol: "", Title: "Motor", Description: "Motor driven actuator, such as garage door, blinds, tv lifts"},
+  ThingControlClimate: {Symbol: "", Title: "Climate control", Description: "Device for controlling climate of a space"},
+  ThingControlPool: {Symbol: "", Title: "Pool control", Description: "Device for controlling pool settings"},
+  ThingNetLora: {Symbol: "", Title: "LoRa network device", Description: "Generic Long Range network protocol device"},
+  ThingSensorMulti: {Symbol: "", Title: "Multi sensor", Description: "Sense multiple inputs"},
+  ThingMeterElectricCurrent: {Symbol: "", Title: "Electric current", Description: "Electrical current meter"},
+  ThingSensorSecurityDoorWindow: {Symbol: "", Title: "Door/Window sensor", Description: "Dedicated door/window opening security sensor"},
+  ThingActuatorSwitch: {Symbol: "", Title: "Switch", Description: "An electric powered on/off switch for powering circuits"},
   ThingComputerMemory: {Symbol: "", Title: "Memory", Description: "Stand-alone memory device such as eeprom or iButtons"},
-  ThingComputerPotsPhone: {Symbol: "", Title: "Land Line", Description: "Plain Old Telephone System, aka landline"},
-  ThingMediaAmplifier: {Symbol: "", Title: "Audio amplifier", Description: "Audio amplifier with volume controls"},
+  ThingComputerSatPhone: {Symbol: "", Title: "Satellite phone", Description: ""},
+  ThingDevice: {Symbol: "", Title: "Device", Description: "Device of unknown purpose"},
   ThingMeterElectricEnergy: {Symbol: "", Title: "Electric energy", Description: "Electrical energy meter"},
-  ThingMeterFuelLevel: {Symbol: "", Title: "Fuel level", Description: "Dedicated fuel level metering device"},
   ThingNet: {Symbol: "", Title: "Network device", Description: "Generic network device"},
+  ThingSensor: {Symbol: "", Title: "Sensor", Description: "Generic sensor device"},
+  ThingActuatorRelay: {Symbol: "", Title: "Relay", Description: "Generic relay electrical switch"},
+  ThingAppliance: {Symbol: "", Title: "Appliance", Description: "Appliance to accomplish a particular task for occupant use"},
+  ThingComputer: {Symbol: "", Title: "Computing Device", Description: "General purpose computing device"},
+  ThingControlSwitch: {Symbol: "", Title: "Input switch", Description: "On or off switch input control"},
 }
 
 
 // type: UnitClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-unit-classes.yaml
 // namespace: ht
 const (
@@ -597,35 +597,35 @@ const (
 var UnitClassesMap = map[string]struct {
    Symbol string; Title string; Description string
 } {
-  UnitPound: {Symbol: "lbs", Title: "Pound", Description: "Imperial unit of weight. Equivalent to 0.453592 Kg. 1 Kg is 2.205 lbs"},
-  UnitWatt: {Symbol: "W", Title: "Watt", Description: "SI unit of power. Equal to 1 joule per second; or work performed when a current of 1 ampere flows across an electric potential of one volt."},
-  UnitFoot: {Symbol: "ft", Title: "Foot", Description: "Imperial unit of distance. 1 foot equals 0.3048 meters"},
-  UnitLumen: {Symbol: "lm", Title: "Lumen", Description: "SI unit luminous flux. Measure of perceived power of visible light. 1lm = 1 cd steradian"},
-  UnitMilliSecond: {Symbol: "ms", Title: "millisecond", Description: "Unit of time in milli-seconds. Equal to 1/1000 of a second."},
+  UnitMilesPerHour: {Symbol: "mph", Title: "Miles per hour", Description: "Speed in miles per hour"},
+  UnitMillibar: {Symbol: "mbar", Title: "millibar", Description: "Metric unit of pressure. 1/1000th of a bar. Equal to 100 pascals. Amount of force it takes to move an object weighing a gram, one centimeter in one second."},
   UnitPercent: {Symbol: "%", Title: "Percent", Description: "Fractions of 100"},
+  UnitPound: {Symbol: "lbs", Title: "Pound", Description: "Imperial unit of weight. Equivalent to 0.453592 Kg. 1 Kg is 2.205 lbs"},
+  UnitCelcius: {Symbol: "°C", Title: "Celcius", Description: "Temperature in Celcius"},
   UnitLiter: {Symbol: "l", Title: "Liter", Description: "SI unit of volume equivalent to 1 cubic decimeter."},
+  UnitMeter: {Symbol: "m", Title: "Meter", Description: "Distance in meters. 1m=c/299792458"},
+  UnitPpm: {Symbol: "ppm", Title: "PPM", Description: "Parts per million"},
+  UnitPSI: {Symbol: "PSI", Title: "PSI", Description: "Unit of pressure. Pounds of force per square inch. 1PSI equals 6984 Pascals."},
+  UnitFahrenheit: {Symbol: "F", Title: "Fahrenheit", Description: "Temperature in Fahrenheit"},
+  UnitMilliSecond: {Symbol: "ms", Title: "millisecond", Description: "Unit of time in milli-seconds. Equal to 1/1000 of a second."},
+  UnitPascal: {Symbol: "Pa", Title: "Pascal", Description: "SI unit of pressure. Equal to 1 newton of force applied over 1 square meter."},
+  UnitCount: {Symbol: "(N)", Title: "Count", Description: ""},
   UnitMercury: {Symbol: "Hg", Title: "Mercury", Description: "Unit of atmospheric pressure in the United States. 1 Hg equals 33.8639 mbar."},
+  UnitFoot: {Symbol: "ft", Title: "Foot", Description: "Imperial unit of distance. 1 foot equals 0.3048 meters"},
+  UnitKelvin: {Symbol: "K", Title: "Kelvin", Description: "SI unit of thermodynamic temperature. 0 K represents absolute zero, the absence of all heat. 0 C equals +273.15K"},
   UnitKilogram: {Symbol: "kg", Title: "Kilogram", Description: ""},
-  UnitMeter: {Symbol: "m", Title: "Meter", Description: "Distance in meters. 1m=c/299792458"},
+  UnitRadian: {Symbol: "", Title: "Radian", Description: "Angle in 0-2pi"},
+  UnitWatt: {Symbol: "W", Title: "Watt", Description: "SI unit of power. Equal to 1 joule per second; or work performed when a current of 1 ampere flows across an electric potential of one volt."},
+  UnitCandela: {Symbol: "cd", Title: "Candela", Description: "SI unit of luminous intensity in a given direction. Roughly the same brightness as the common candle."},
+  UnitDegree: {Symbol: "degree", Title: "Degree", Description: "Angle in 0-360 degrees"},
+  UnitLumen: {Symbol: "lm", Title: "Lumen", Description: "SI unit luminous flux. Measure of perceived power of visible light. 1lm = 1 cd steradian"},
   UnitMole: {Symbol: "mol", Title: "Mole", Description: "SI unit of measurement for amount of substance. Eg, molecules."},
-  UnitSecond: {Symbol: "s", Title: "Second", Description: "SI unit of time based on caesium frequency"},
   UnitVolt: {Symbol: "V", Title: "Volt", Description: "SI unit of electric potential; Energy consumption of 1 joule per electric charge of one coulomb"},
-  UnitFahrenheit: {Symbol: "F", Title: "Fahrenheit", Description: "Temperature in Fahrenheit"},
-  UnitGallon: {Symbol: "gl", Title: "Gallon", Description: "Unit of volume. 1 Imperial gallon is 4.54609 liters. 1 US liquid gallon is 3.78541 liters. 1 US dry gallon is 4.405 liters. "},
-  UnitCelcius: {Symbol: "°C", Title: "Celcius", Description: "Temperature in Celcius"},
-  UnitPpm: {Symbol: "ppm", Title: "PPM", Description: "Parts per million"},
   UnitKilometerPerHour: {Symbol: "kph", Title: "Km per hour", Description: "Speed in kilometers per hour"},
   UnitKilowattHour: {Symbol: "kWh", Title: "Kilowatt-hour", Description: "non-SI unit of energy equivalent to 3.6 megajoules."},
-  UnitMillibar: {Symbol: "mbar", Title: "millibar", Description: "Metric unit of pressure. 1/1000th of a bar. Equal to 100 pascals. Amount of force it takes to move an object weighing a gram, one centimeter in one second."},
-  UnitRadian: {Symbol: "", Title: "Radian", Description: "Angle in 0-2pi"},
-  UnitCandela: {Symbol: "cd", Title: "Candela", Description: "SI unit of luminous intensity in a given direction. Roughly the same brightness as the common candle."},
-  UnitKelvin: {Symbol: "K", Title: "Kelvin", Description: "SI unit of thermodynamic temperature. 0 K represents absolute zero, the absence of all heat. 0 C equals +273.15K"},
-  UnitPascal: {Symbol: "Pa", Title: "Pascal", Description: "SI unit of pressure. Equal to 1 newton of force applied over 1 square meter."},
-  UnitCount: {Symbol: "(N)", Title: "Count", Description: ""},
-  UnitDegree: {Symbol: "degree", Title: "Degree", Description: "Angle in 0-360 degrees"},
-  UnitPSI: {Symbol: "PSI", Title: "PSI", Description: "Unit of pressure. Pounds of force per square inch. 1PSI equals 6984 Pascals."},
   UnitLux: {Symbol: "lx", Title: "Lux", Description: "SI unit illuminance. Equal to 1 lumen per square meter."},
-  UnitMilesPerHour: {Symbol: "mph", Title: "Miles per hour", Description: "Speed in miles per hour"},
-  UnitAmpere: {Symbol: "A", Title: "Ampere", Description: "Electrical current in Amperes based on the elementary charge flow per second"},
   UnitMeterPerSecond: {Symbol: "m/s", Title: "Meters per second", Description: "SI unit of speed in meters per second"},
+  UnitSecond: {Symbol: "s", Title: "Second", Description: "SI unit of time based on caesium frequency"},
+  UnitAmpere: {Symbol: "A", Title: "Ampere", Description: "Electrical current in Amperes based on the elementary charge flow per second"},
+  UnitGallon: {Symbol: "gl", Title: "Gallon", Description: "Unit of volume. 1 Imperial gallon is 4.54609 liters. 1 US liquid gallon is 3.78541 liters. 1 US dry gallon is 4.405 liters. "},
 }
diff --git a/api/js/vocab/vocab.js b/api/js/vocab/vocab.js
index 4a580629..b3593a0a 100644
--- a/api/js/vocab/vocab.js
+++ b/api/js/vocab/vocab.js
@@ -3,7 +3,7 @@
 
 // type: ActionStatusStatus
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-constants.yaml
 // description: Request progress status constants
 export const RequestCompleted = "completed"
@@ -14,7 +14,7 @@ export const RequestPending = "pending"
 
 // type: WoTVocab
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/wot-vocab.yaml
 // description: WoT vocabulary definition. See https://www.w3.org/TR/2020/WD-wot-thing-description11-20201124/#sec-core-vocabulary-definition
 export const HTOpLogin = "login"
@@ -104,7 +104,7 @@ export const WoTVersion = "version"
 
 // type: ActionClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-action-classes.yaml
 // namespace: ht
 export const ActionDimmer = "hiveot:action:dimmer";
@@ -134,35 +134,35 @@ export const ActionValveOpen = "hiveot:action:valve:open";
 
 // ActionClassesMap maps @type to symbol, title and description
 export const ActionClassesMap = {
-  "hiveot:action:media:previous": {Symbol: "", Title: "Previous", Description: "Previous track or station"},
+  "hiveot:action:media:pause": {Symbol: "", Title: "Pause", Description: "Pause playback"},
+  "hiveot:action:media:unmute": {Symbol: "", Title: "Unmute", Description: "Unmute audio"},
+  "hiveot:action:media:volume": {Symbol: "", Title: "Volume", Description: "Set volume level"},
+  "hiveot:action:dimmer:increment": {Symbol: "", Title: "Increase dimmer", Description: ""},
+  "hiveot:action:switch": {Symbol: "", Title: "Switch", Description: "General switch action"},
+  "hiveot:action:thing:disable": {Symbol: "", Title: "Disable", Description: "Action to disable a thing"},
   "hiveot:action:media:volume:decrease": {Symbol: "", Title: "Decrease volume", Description: "Decrease volume"},
-  "hiveot:action:dimmer:decrement": {Symbol: "", Title: "Lower dimmer", Description: ""},
+  "hiveot:action:dimmer:set": {Symbol: "", Title: "Set dimmer", Description: "Action to set the dimmer value"},
   "hiveot:action:switch:onoff": {Symbol: "", Title: "Set On/Off switch", Description: "Action to set the switch on/off state"},
+  "hiveot:action:valve:open": {Symbol: "", Title: "Open valve", Description: "Action to open the valve"},
+  "hiveot:action:media:next": {Symbol: "", Title: "Next", Description: "Next track or station"},
   "hiveot:action:thing:enable": {Symbol: "", Title: "Enable", Description: "Action to enable a thing"},
   "hiveot:action:thing:start": {Symbol: "", Title: "Start", Description: "Start running a task"},
+  "hiveot:action:thing:stop": {Symbol: "", Title: "Stop", Description: "Stop a running task"},
+  "hiveot:action:switch:toggle": {Symbol: "", Title: "Toggle switch", Description: "Action to toggle the switch"},
+  "hiveot:action:media": {Symbol: "", Title: "Media control", Description: "Commands to control media recording and playback"},
   "hiveot:action:media:mute": {Symbol: "", Title: "Mute", Description: "Mute audio"},
-  "hiveot:action:media:unmute": {Symbol: "", Title: "Unmute", Description: "Unmute audio"},
-  "hiveot:action:media:volume": {Symbol: "", Title: "Volume", Description: "Set volume level"},
+  "hiveot:action:media:play": {Symbol: "", Title: "Play", Description: "Start or continue playback"},
+  "hiveot:action:media:previous": {Symbol: "", Title: "Previous", Description: "Previous track or station"},
   "hiveot:action:media:volume:increase": {Symbol: "", Title: "Increase volume", Description: "Increase volume"},
   "hiveot:action:dimmer": {Symbol: "", Title: "Dimmer", Description: "General dimmer action"},
-  "hiveot:action:dimmer:set": {Symbol: "", Title: "Set dimmer", Description: "Action to set the dimmer value"},
-  "hiveot:action:thing:stop": {Symbol: "", Title: "Stop", Description: "Stop a running task"},
+  "hiveot:action:dimmer:decrement": {Symbol: "", Title: "Lower dimmer", Description: ""},
   "hiveot:action:valve:close": {Symbol: "", Title: "Close valve", Description: "Action to close the valve"},
-  "hiveot:action:valve:open": {Symbol: "", Title: "Open valve", Description: "Action to open the valve"},
-  "hiveot:action:media": {Symbol: "", Title: "Media control", Description: "Commands to control media recording and playback"},
-  "hiveot:action:media:next": {Symbol: "", Title: "Next", Description: "Next track or station"},
-  "hiveot:action:media:pause": {Symbol: "", Title: "Pause", Description: "Pause playback"},
-  "hiveot:action:media:play": {Symbol: "", Title: "Play", Description: "Start or continue playback"},
-  "hiveot:action:dimmer:increment": {Symbol: "", Title: "Increase dimmer", Description: ""},
-  "hiveot:action:switch": {Symbol: "", Title: "Switch", Description: "General switch action"},
-  "hiveot:action:switch:toggle": {Symbol: "", Title: "Toggle switch", Description: "Action to toggle the switch"},
-  "hiveot:action:thing:disable": {Symbol: "", Title: "Disable", Description: "Action to disable a thing"},
 }
 
 
 // type: PropertyClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-property-classes.yaml
 // namespace: ht
 export const PropAlarmMotion = "hiveot:prop:alarm:motion";
@@ -249,92 +249,92 @@ export const PropSwitchOnOff = "hiveot:prop:switch:onoff";
 
 // PropertyClassesMap maps @type to symbol, title and description
 export const PropertyClassesMap = {
-  "hiveot:prop:electric": {Symbol: "", Title: "Electrical properties", Description: "General group of electrical properties"},
-  "hiveot:prop:env:humidity": {Symbol: "", Title: "Humidity", Description: ""},
-  "hiveot:prop:media:muted": {Symbol: "", Title: "Muted", Description: "Audio is muted"},
-  "hiveot:prop:media:track": {Symbol: "", Title: "Track", Description: "Selected A/V track"},
-  "hiveot:prop:net:address": {Symbol: "", Title: "Address", Description: "Network address"},
-  "hiveot:prop:status:onoff": {Symbol: "", Title: "On/off status", Description: ""},
-  "hiveot:prop:switch:locked": {Symbol: "", Title: "Lock", Description: "Electric lock status"},
-  "hiveot:prop:env:uv": {Symbol: "", Title: "UV", Description: ""},
-  "hiveot:prop:media:playing": {Symbol: "", Title: "Playing", Description: "Media is playing"},
-  "hiveot:prop:switch:dimmer": {Symbol: "", Title: "Dimmer value", Description: ""},
-  "hiveot:prop:media": {Symbol: "", Title: "Media commands", Description: "Control of media equipment"},
+  "hiveot:prop:location:latitude": {Symbol: "", Title: "Latitude", Description: "Latitude geographic coordinate"},
+  "hiveot:prop:media:station": {Symbol: "", Title: "Station", Description: "Selected radio station"},
   "hiveot:prop:net:hostname": {Symbol: "", Title: "Hostname", Description: "Hostname of the client"},
-  "hiveot:prop:alarm:motion": {Symbol: "", Title: "Motion", Description: "Motion detected"},
-  "hiveot:prop:env:fuel:flowrate": {Symbol: "", Title: "Fuel flow rate", Description: ""},
   "hiveot:prop:net:mac": {Symbol: "", Title: "MAC", Description: "Hardware MAC address"},
-  "hiveot:prop:status:openclosed": {Symbol: "", Title: "Open/Closed status", Description: ""},
-  "hiveot:prop:device:model": {Symbol: "", Title: "Model", Description: "Device model"},
-  "hiveot:prop:env:airquality": {Symbol: "", Title: "Air quality", Description: "Air quality level"},
+  "hiveot:prop:net:mask": {Symbol: "", Title: "Netmask", Description: "Network mask. Example: 255.255.255.0 or 24/8"},
+  "hiveot:prop:env": {Symbol: "", Title: "Environmental property", Description: "Property of environmental sensor"},
+  "hiveot:prop:env:uv": {Symbol: "", Title: "UV", Description: ""},
+  "hiveot:prop:net:connection": {Symbol: "", Title: "Connection", Description: "Connection status, connected, connecting, retrying, disconnected,..."},
+  "hiveot:prop:switch:locked": {Symbol: "", Title: "Lock", Description: "Electric lock status"},
+  "hiveot:prop:env:co2": {Symbol: "", Title: "Carbon dioxide level", Description: "Carbon dioxide level"},
+  "hiveot:prop:electric:current": {Symbol: "", Title: "Current", Description: "Electrical current"},
+  "hiveot:prop:env:humidity": {Symbol: "", Title: "Humidity", Description: ""},
   "hiveot:prop:location:city": {Symbol: "", Title: "City", Description: "City name"},
+  "hiveot:prop:location:longitude": {Symbol: "", Title: "Longitude", Description: "Longitude geographic coordinate"},
+  "hiveot:prop:status:onoff": {Symbol: "", Title: "On/off status", Description: ""},
+  "hiveot:prop:status:openclosed": {Symbol: "", Title: "Open/Closed status", Description: ""},
+  "hiveot:prop:device:title": {Symbol: "", Title: "Title", Description: "Device friendly title"},
+  "hiveot:prop:device:status": {Symbol: "", Title: "Status", Description: "Device status; alive, awake, dead, sleeping"},
+  "hiveot:prop:device:pollinterval": {Symbol: "", Title: "Polling interval", Description: "Interval to poll for updates"},
+  "hiveot:prop:env:co": {Symbol: "", Title: "Carbon monoxide level", Description: "Carbon monoxide level"},
+  "hiveot:prop:env:wind:heading": {Symbol: "", Title: "Wind heading", Description: ""},
+  "hiveot:prop:device:description": {Symbol: "", Title: "Description", Description: "Device product description"},
+  "hiveot:prop:location:zipcode": {Symbol: "", Title: "Zip code", Description: "Location ZIP code"},
+  "hiveot:prop:media:muted": {Symbol: "", Title: "Muted", Description: "Audio is muted"},
+  "hiveot:prop:media:volume": {Symbol: "", Title: "Volume", Description: "Media volume setting"},
   "hiveot:prop:device:make": {Symbol: "", Title: "Make", Description: "Device manufacturer"},
   "hiveot:prop:env:fuel:level": {Symbol: "", Title: "Fuel level", Description: ""},
-  "hiveot:prop:media:volume": {Symbol: "", Title: "Volume", Description: "Media volume setting"},
-  "hiveot:prop:net": {Symbol: "", Title: "Network properties", Description: "General network properties"},
-  "hiveot:prop:net:subnet": {Symbol: "", Title: "Subnet", Description: "Network subnet address. Example: 192.168.0.0"},
-  "hiveot:prop:device:pollinterval": {Symbol: "", Title: "Polling interval", Description: "Interval to poll for updates"},
+  "hiveot:prop:location": {Symbol: "", Title: "Location", Description: "General location information"},
+  "hiveot:prop:media:track": {Symbol: "", Title: "Track", Description: "Selected A/V track"},
+  "hiveot:prop:net:latency": {Symbol: "", Title: "Network latency", Description: "Delay between hub and client"},
+  "hiveot:prop:status:started-stopped": {Symbol: "", Title: "Started/Stopped", Description: "Started or stopped status"},
+  "hiveot:prop:device:model": {Symbol: "", Title: "Model", Description: "Device model"},
+  "hiveot:prop:alarm:motion": {Symbol: "", Title: "Motion", Description: "Motion detected"},
+  "hiveot:prop:device:firmwareversion": {Symbol: "", Title: "Firmware version", Description: ""},
+  "hiveot:prop:device:hardwareversion": {Symbol: "", Title: "Hardware version", Description: ""},
   "hiveot:prop:device:softwareversion": {Symbol: "", Title: "Software version", Description: ""},
-  "hiveot:prop:electric:current": {Symbol: "", Title: "Current", Description: "Electrical current"},
+  "hiveot:prop:electric": {Symbol: "", Title: "Electrical properties", Description: "General group of electrical properties"},
+  "hiveot:prop:electric:energy": {Symbol: "", Title: "Energy", Description: "Electrical energy consumed"},
+  "hiveot:prop:status:yes-no": {Symbol: "", Title: "Yes/No", Description: "Status with yes or no value"},
+  "hiveot:prop:alarm:status": {Symbol: "", Title: "Alarm state", Description: "Current alarm status"},
+  "hiveot:prop:switch:onoff": {Symbol: "", Title: "On/Off switch", Description: ""},
+  "hiveot:prop:env:fuel:flowrate": {Symbol: "", Title: "Fuel flow rate", Description: ""},
   "hiveot:prop:env:temperature": {Symbol: "", Title: "Temperature", Description: ""},
   "hiveot:prop:env:water:flowrate": {Symbol: "", Title: "Water flow rate", Description: ""},
-  "hiveot:prop:env:wind:heading": {Symbol: "", Title: "Wind heading", Description: ""},
-  "hiveot:prop:media:paused": {Symbol: "", Title: "Paused", Description: "Media is paused"},
-  "hiveot:prop:device:description": {Symbol: "", Title: "Description", Description: "Device product description"},
-  "hiveot:prop:device:hardwareversion": {Symbol: "", Title: "Hardware version", Description: ""},
-  "hiveot:prop:electric:poer": {Symbol: "", Title: "Power", Description: "Electrical power being consumed"},
-  "hiveot:prop:env:vibration": {Symbol: "", Title: "Vibration", Description: ""},
-  "hiveot:prop:switch:light": {Symbol: "", Title: "Light switch", Description: ""},
-  "hiveot:prop:device": {Symbol: "", Title: "Device attributes", Description: "Attributes describing a device"},
-  "hiveot:prop:env:pressure": {Symbol: "", Title: "Pressure", Description: ""},
-  "hiveot:prop:env:timezone": {Symbol: "", Title: "Timezone", Description: ""},
-  "hiveot:prop:location:street": {Symbol: "", Title: "Street", Description: "Street address"},
-  "hiveot:prop:device:title": {Symbol: "", Title: "Title", Description: "Device friendly title"},
+  "hiveot:prop:media:playing": {Symbol: "", Title: "Playing", Description: "Media is playing"},
   "hiveot:prop:net:domainname": {Symbol: "", Title: "Domain name", Description: "Domainname of the client"},
-  "hiveot:prop:switch:onoff": {Symbol: "", Title: "On/Off switch", Description: ""},
-  "hiveot:prop:location:zipcode": {Symbol: "", Title: "Zip code", Description: "Location ZIP code"},
-  "hiveot:prop:alarm:status": {Symbol: "", Title: "Alarm state", Description: "Current alarm status"},
-  "hiveot:prop:electric:voltage": {Symbol: "", Title: "Voltage", Description: "Electrical voltage potential"},
-  "hiveot:prop:env": {Symbol: "", Title: "Environmental property", Description: "Property of environmental sensor"},
-  "hiveot:prop:env:co": {Symbol: "", Title: "Carbon monoxide level", Description: "Carbon monoxide level"},
+  "hiveot:prop:net:gateway": {Symbol: "", Title: "Gateway", Description: "Network gateway address"},
+  "hiveot:prop:net:port": {Symbol: "", Title: "Port", Description: "Network port"},
   "hiveot:prop:env:dewpoint": {Symbol: "", Title: "Dew point", Description: "Dew point temperature"},
+  "hiveot:prop:switch:dimmer": {Symbol: "", Title: "Dimmer value", Description: ""},
+  "hiveot:prop:electric:overload": {Symbol: "", Title: "Overload protection", Description: "Cut load on overload"},
+  "hiveot:prop:env:luminance": {Symbol: "", Title: "Luminance", Description: ""},
   "hiveot:prop:env:water:level": {Symbol: "", Title: "Water level", Description: ""},
-  "hiveot:prop:location:name": {Symbol: "", Title: "Location name", Description: "Name of the location"},
-  "hiveot:prop:net:ip4": {Symbol: "", Title: "IP4 address", Description: "Device IP4 address"},
-  "hiveot:prop:net:ip6": {Symbol: "", Title: "IP6 address", Description: "Device IP6 address"},
-  "hiveot:prop:net:latency": {Symbol: "", Title: "Network latency", Description: "Delay between hub and client"},
-  "hiveot:prop:device:firmwareversion": {Symbol: "", Title: "Firmware version", Description: ""},
-  "hiveot:prop:electric:energy": {Symbol: "", Title: "Energy", Description: "Electrical energy consumed"},
+  "hiveot:prop:net:subnet": {Symbol: "", Title: "Subnet", Description: "Network subnet address. Example: 192.168.0.0"},
+  "hiveot:prop:device:enabled-disabled": {Symbol: "", Title: "Enabled/Disabled", Description: "Enabled or disabled state"},
   "hiveot:prop:env:barometer": {Symbol: "", Title: "Atmospheric pressure", Description: "Barometric pressure of the atmosphere"},
+  "hiveot:prop:env:humidex": {Symbol: "", Title: "Humidex", Description: ""},
+  "hiveot:prop:env:pressure": {Symbol: "", Title: "Pressure", Description: ""},
+  "hiveot:prop:env:vibration": {Symbol: "", Title: "Vibration", Description: ""},
   "hiveot:prop:env:wind:speed": {Symbol: "", Title: "Wind speed", Description: ""},
-  "hiveot:prop:location:longitude": {Symbol: "", Title: "Longitude", Description: "Longitude geographic coordinate"},
-  "hiveot:prop:status:started-stopped": {Symbol: "", Title: "Started/Stopped", Description: "Started or stopped status"},
-  "hiveot:prop:switch": {Symbol: "", Title: "Switch status", Description: ""},
+  "hiveot:prop:location:street": {Symbol: "", Title: "Street", Description: "Street address"},
+  "hiveot:prop:net:ip4": {Symbol: "", Title: "IP4 address", Description: "Device IP4 address"},
   "hiveot:prop:device:battery": {Symbol: "", Title: "Battery level", Description: "Device battery level"},
-  "hiveot:prop:electric:overload": {Symbol: "", Title: "Overload protection", Description: "Cut load on overload"},
-  "hiveot:prop:env:cpuload": {Symbol: "", Title: "CPU load level", Description: "Device CPU load level"},
-  "hiveot:prop:media:station": {Symbol: "", Title: "Station", Description: "Selected radio station"},
-  "hiveot:prop:net:gateway": {Symbol: "", Title: "Gateway", Description: "Network gateway address"},
-  "hiveot:prop:net:mask": {Symbol: "", Title: "Netmask", Description: "Network mask. Example: 255.255.255.0 or 24/8"},
-  "hiveot:prop:status:yes-no": {Symbol: "", Title: "Yes/No", Description: "Status with yes or no value"},
-  "hiveot:prop:device:enabled-disabled": {Symbol: "", Title: "Enabled/Disabled", Description: "Enabled or disabled state"},
-  "hiveot:prop:env:co2": {Symbol: "", Title: "Carbon dioxide level", Description: "Carbon dioxide level"},
-  "hiveot:prop:env:humidex": {Symbol: "", Title: "Humidex", Description: ""},
-  "hiveot:prop:net:port": {Symbol: "", Title: "Port", Description: "Network port"},
-  "hiveot:prop:device:status": {Symbol: "", Title: "Status", Description: "Device status; alive, awake, dead, sleeping"},
-  "hiveot:prop:net:connection": {Symbol: "", Title: "Connection", Description: "Connection status, connected, connecting, retrying, disconnected,..."},
+  "hiveot:prop:electric:poer": {Symbol: "", Title: "Power", Description: "Electrical power being consumed"},
   "hiveot:prop:env:acceleration": {Symbol: "", Title: "Acceleration", Description: ""},
-  "hiveot:prop:env:luminance": {Symbol: "", Title: "Luminance", Description: ""},
+  "hiveot:prop:env:cpuload": {Symbol: "", Title: "CPU load level", Description: "Device CPU load level"},
   "hiveot:prop:env:volume": {Symbol: "", Title: "Volume", Description: ""},
-  "hiveot:prop:location": {Symbol: "", Title: "Location", Description: "General location information"},
-  "hiveot:prop:location:latitude": {Symbol: "", Title: "Latitude", Description: "Latitude geographic coordinate"},
+  "hiveot:prop:location:name": {Symbol: "", Title: "Location name", Description: "Name of the location"},
+  "hiveot:prop:device": {Symbol: "", Title: "Device attributes", Description: "Attributes describing a device"},
+  "hiveot:prop:env:airquality": {Symbol: "", Title: "Air quality", Description: "Air quality level"},
+  "hiveot:prop:media:paused": {Symbol: "", Title: "Paused", Description: "Media is paused"},
   "hiveot:prop:net:signalstrength": {Symbol: "", Title: "Signal strength", Description: "Wireless signal strength"},
+  "hiveot:prop:electric:voltage": {Symbol: "", Title: "Voltage", Description: "Electrical voltage potential"},
+  "hiveot:prop:net:ip6": {Symbol: "", Title: "IP6 address", Description: "Device IP6 address"},
+  "hiveot:prop:switch": {Symbol: "", Title: "Switch status", Description: ""},
+  "hiveot:prop:switch:light": {Symbol: "", Title: "Light switch", Description: ""},
+  "hiveot:prop:env:timezone": {Symbol: "", Title: "Timezone", Description: ""},
+  "hiveot:prop:net:address": {Symbol: "", Title: "Address", Description: "Network address"},
+  "hiveot:prop:net": {Symbol: "", Title: "Network properties", Description: "General network properties"},
+  "hiveot:prop:media": {Symbol: "", Title: "Media commands", Description: "Control of media equipment"},
 }
 
 
 // type: ThingClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-thing-classes.yaml
 // namespace: ht
 export const ThingActuator = "hiveot:thing:actuator";
@@ -437,108 +437,108 @@ export const ThingService = "hiveot:thing:service";
 
 // ThingClassesMap maps @type to symbol, title and description
 export const ThingClassesMap = {
-  "hiveot:thing:media:tv": {Symbol: "", Title: "TV", Description: "Network connected television"},
-  "hiveot:thing:meter:water": {Symbol: "", Title: "Water metering device", Description: "General water metering device"},
-  "hiveot:thing:net:gateway:zigbee": {Symbol: "", Title: "Zigbee gateway", Description: "Gateway providing access to Zigbee devices"},
+  "hiveot:thing:computer": {Symbol: "", Title: "Computing Device", Description: "General purpose computing device"},
+  "hiveot:thing:device:battery:monitor": {Symbol: "", Title: "Battery Monitor", Description: "Battery monitor and charge controller"},
+  "hiveot:thing:media:camera": {Symbol: "", Title: "Camera", Description: "Video camera"},
+  "hiveot:thing:media:radio": {Symbol: "", Title: "Radio", Description: "AM or FM radio receiver"},
+  "hiveot:thing:actuator:switch": {Symbol: "", Title: "Switch", Description: "An electric powered on/off switch for powering circuits"},
+  "hiveot:thing:actuator:valve": {Symbol: "", Title: "Valve", Description: "Electric powered valve for fluids or gas"},
+  "hiveot:thing:actuator:valve:fuel": {Symbol: "", Title: "Fuel valve", Description: "Electric powered fuel valve"},
+  "hiveot:thing:appliance:dishwasher": {Symbol: "", Title: "Dishwasher", Description: "Dishwasher"},
+  "hiveot:thing:net:gateway:onewire": {Symbol: "", Title: "1-Wire gateway", Description: "Gateway providing access to 1-wire devices"},
+  "hiveot:thing:sensor:security:glass": {Symbol: "", Title: "Glass sensor", Description: "Dedicated sensor for detecting breaking of glass"},
+  "hiveot:thing:sensor:scale": {Symbol: "", Title: "Scale", Description: "Electronic weigh scale"},
+  "hiveot:thing:net:wifi": {Symbol: "", Title: "Wifi device", Description: "Generic wifi device"},
+  "hiveot:thing:net:lora": {Symbol: "", Title: "LoRa network device", Description: "Generic Long Range network protocol device"},
   "hiveot:thing:sensor:thermometer": {Symbol: "", Title: "Thermometer", Description: "Environmental thermometer"},
+  "hiveot:thing:actuator:beacon": {Symbol: "", Title: "Beacon", Description: "Location beacon"},
+  "hiveot:thing:meter:electric:power": {Symbol: "", Title: "Electrical Power", Description: "Electrical power meter"},
   "hiveot:thing:meter:water:level": {Symbol: "", Title: "Water level", Description: "Dedicated water level meter"},
   "hiveot:thing:net:bluetooth": {Symbol: "", Title: "Bluetooth", Description: "Bluetooth radio"},
-  "hiveot:thing:sensor:input": {Symbol: "", Title: "Input sensor", Description: "General purpose electrical input sensor"},
+  "hiveot:thing:media": {Symbol: "", Title: "A/V media", Description: "Generic device for audio/video media record or playback"},
+  "hiveot:thing:net:gateway:coap": {Symbol: "", Title: "CoAP gateway", Description: "Gateway providing access to CoAP devices"},
   "hiveot:thing:actuator": {Symbol: "", Title: "Actuator", Description: "Generic actuator"},
-  "hiveot:thing:appliance:freezer": {Symbol: "", Title: "Freezer", Description: "Refrigerator freezer"},
-  "hiveot:thing:control:toggle": {Symbol: "", Title: "Toggle switch", Description: "Toggle switch input control"},
-  "hiveot:thing:media:speaker": {Symbol: "", Title: "Connected speakers", Description: "Network connected speakers"},
-  "hiveot:thing:sensor:security:motion": {Symbol: "", Title: "Motion sensor", Description: "Dedicated security sensor detecting motion"},
-  "hiveot:thing:sensor:water:leak": {Symbol: "", Title: "Water leak detector", Description: "Dedicated water leak detector"},
-  "hiveot:thing:actuator:beacon": {Symbol: "", Title: "Beacon", Description: "Location beacon"},
-  "hiveot:thing:appliance:dishwasher": {Symbol: "", Title: "Dishwasher", Description: "Dishwasher"},
-  "hiveot:thing:device:time": {Symbol: "", Title: "Clock", Description: "Time tracking device such as clocks and time chips"},
-  "hiveot:thing:sensor:security:glass": {Symbol: "", Title: "Glass sensor", Description: "Dedicated sensor for detecting breaking of glass"},
-  "hiveot:thing:meter:electric:current": {Symbol: "", Title: "Electric current", Description: "Electrical current meter"},
-  "hiveot:thing:meter:fuel:flow": {Symbol: "", Title: "Fuel flow rate", Description: "Dedicated fuel flow rate metering device"},
-  "hiveot:thing:meter:water:flow": {Symbol: "", Title: "Water flow", Description: "Dedicated water flow-rate meter"},
-  "hiveot:thing:net:switch": {Symbol: "", Title: "Network switch", Description: "Network switch to connect computer devices to the network"},
   "hiveot:thing:control:keypad": {Symbol: "", Title: "Keypad", Description: "Multi-key pad for command input"},
+  "hiveot:thing:device": {Symbol: "", Title: "Device", Description: "Device of unknown purpose"},
+  "hiveot:thing:device:time": {Symbol: "", Title: "Clock", Description: "Time tracking device such as clocks and time chips"},
+  "hiveot:thing:actuator:output": {Symbol: "", Title: "Output", Description: "General purpose electrical output signal"},
+  "hiveot:thing:media:amplifier": {Symbol: "", Title: "Audio amplifier", Description: "Audio amplifier with volume controls"},
+  "hiveot:thing:sensor:input": {Symbol: "", Title: "Input sensor", Description: "General purpose electrical input sensor"},
+  "hiveot:thing:net:gateway:zigbee": {Symbol: "", Title: "Zigbee gateway", Description: "Gateway providing access to Zigbee devices"},
+  "hiveot:thing:control:pushbutton": {Symbol: "", Title: "Momentary switch", Description: "Momentary push button control input"},
   "hiveot:thing:control:thermostat": {Symbol: "", Title: "Thermostat", Description: "Thermostat HVAC control"},
-  "hiveot:thing:media:player": {Symbol: "", Title: "Media player", Description: "CD/DVD/Blueray/USB player of recorded media"},
-  "hiveot:thing:media:radio": {Symbol: "", Title: "Radio", Description: "AM or FM radio receiver"},
-  "hiveot:thing:appliance:fridge": {Symbol: "", Title: "Fridge", Description: "Refrigerator appliance"},
-  "hiveot:thing:net:gateway": {Symbol: "", Title: "Gateway", Description: "Generic gateway device providing access to other devices"},
-  "hiveot:thing:sensor:security": {Symbol: "", Title: "Security", Description: "Generic security sensor"},
-  "hiveot:thing:sensor:smoke": {Symbol: "", Title: "Smoke detector", Description: ""},
-  "hiveot:thing:appliance:dryer": {Symbol: "", Title: "Dryer", Description: "Clothing dryer"},
-  "hiveot:thing:control": {Symbol: "", Title: "Input controller", Description: "Generic input controller"},
-  "hiveot:thing:media:camera": {Symbol: "", Title: "Camera", Description: "Video camera"},
-  "hiveot:thing:net:lora": {Symbol: "", Title: "LoRa network device", Description: "Generic Long Range network protocol device"},
-  "hiveot:thing:actuator:valve:fuel": {Symbol: "", Title: "Fuel valve", Description: "Electric powered fuel valve"},
-  "hiveot:thing:computer:embedded": {Symbol: "", Title: "Embedded System", Description: "Embedded computing device"},
-  "hiveot:thing:meter:fuel:level": {Symbol: "", Title: "Fuel level", Description: "Dedicated fuel level metering device"},
-  "hiveot:thing:net:lora:p2p": {Symbol: "", Title: "LoRa P2P", Description: "LoRa Peer-to-peer network device"},
-  "hiveot:thing:actuator:alarm": {Symbol: "", Title: "Alarm", Description: "Siren or light alarm"},
-  "hiveot:thing:actuator:motor": {Symbol: "", Title: "Motor", Description: "Motor driven actuator, such as garage door, blinds, tv lifts"},
-  "hiveot:thing:actuator:relay": {Symbol: "", Title: "Relay", Description: "Generic relay electrical switch"},
-  "hiveot:thing:actuator:switch": {Symbol: "", Title: "Switch", Description: "An electric powered on/off switch for powering circuits"},
+  "hiveot:thing:media:microphone": {Symbol: "", Title: "Microphone", Description: "Microphone for capturing audio"},
+  "hiveot:thing:media:tv": {Symbol: "", Title: "TV", Description: "Network connected television"},
+  "hiveot:thing:sensor:environment": {Symbol: "", Title: "Environmental sensor", Description: "Environmental sensor with one or more features such as temperature, humidity, etc"},
+  "hiveot:thing:sensor:water:leak": {Symbol: "", Title: "Water leak detector", Description: "Dedicated water leak detector"},
+  "hiveot:thing:actuator:valve:water": {Symbol: "", Title: "Water valve", Description: "Electric powered water valve"},
+  "hiveot:thing:computer:potsphone": {Symbol: "", Title: "Land Line", Description: "Plain Old Telephone System, aka landline"},
+  "hiveot:thing:computer:satphone": {Symbol: "", Title: "Satellite phone", Description: ""},
+  "hiveot:thing:control:climate": {Symbol: "", Title: "Climate control", Description: "Device for controlling climate of a space"},
+  "hiveot:thing:actuator:ranged": {Symbol: "", Title: "Ranged actuator", Description: "Generic ranged actuator with a set point"},
+  "hiveot:thing:computer:memory": {Symbol: "", Title: "Memory", Description: "Stand-alone memory device such as eeprom or iButtons"},
+  "hiveot:thing:device:indicator": {Symbol: "", Title: "Indicator", Description: "Visual or audio indicator device"},
+  "hiveot:thing:service": {Symbol: "", Title: "Service", Description: "General service for processing data and offering features of interest"},
+  "hiveot:thing:meter:water:flow": {Symbol: "", Title: "Water flow", Description: "Dedicated water flow-rate meter"},
   "hiveot:thing:sensor:sound": {Symbol: "", Title: "Sound detector", Description: ""},
-  "hiveot:thing:sensor": {Symbol: "", Title: "Sensor", Description: "Generic sensor device"},
-  "hiveot:thing:actuator:output": {Symbol: "", Title: "Output", Description: "General purpose electrical output signal"},
-  "hiveot:thing:actuator:valve": {Symbol: "", Title: "Valve", Description: "Electric powered valve for fluids or gas"},
-  "hiveot:thing:computer:cellphone": {Symbol: "", Title: "Cell Phone", Description: "Cellular phone"},
-  "hiveot:thing:meter:water:consumption": {Symbol: "", Title: "Water consumption meter", Description: "Water consumption meter"},
-  "hiveot:thing:sensor:security:doorwindow": {Symbol: "", Title: "Door/Window sensor", Description: "Dedicated door/window opening security sensor"},
+  "hiveot:thing:actuator:alarm": {Symbol: "", Title: "Alarm", Description: "Siren or light alarm"},
   "hiveot:thing:actuator:dimmer": {Symbol: "", Title: "Dimmer", Description: "Light dimmer"},
-  "hiveot:thing:computer:voipphone": {Symbol: "", Title: "VoIP Phone", Description: "Voice over IP phone"},
+  "hiveot:thing:meter:electric:current": {Symbol: "", Title: "Electric current", Description: "Electrical current meter"},
+  "hiveot:thing:meter:water:consumption": {Symbol: "", Title: "Water consumption meter", Description: "Water consumption meter"},
+  "hiveot:thing:meter:fuel:flow": {Symbol: "", Title: "Fuel flow rate", Description: "Dedicated fuel flow rate metering device"},
+  "hiveot:thing:net:lora:p2p": {Symbol: "", Title: "LoRa P2P", Description: "LoRa Peer-to-peer network device"},
+  "hiveot:thing:control": {Symbol: "", Title: "Input controller", Description: "Generic input controller"},
+  "hiveot:thing:control:switch": {Symbol: "", Title: "Input switch", Description: "On or off switch input control"},
+  "hiveot:thing:media:player": {Symbol: "", Title: "Media player", Description: "CD/DVD/Blueray/USB player of recorded media"},
   "hiveot:thing:meter:fuel": {Symbol: "", Title: "Fuel metering device", Description: "General fuel metering device"},
   "hiveot:thing:net:gateway:insteon": {Symbol: "", Title: "Insteon gateway", Description: "Gateway providing access to Insteon devices"},
+  "hiveot:thing:sensor:multi": {Symbol: "", Title: "Multi sensor", Description: "Sense multiple inputs"},
   "hiveot:thing:actuator:light": {Symbol: "", Title: "Light", Description: "Smart LED or other light"},
-  "hiveot:thing:net:gateway:coap": {Symbol: "", Title: "CoAP gateway", Description: "Gateway providing access to CoAP devices"},
-  "hiveot:thing:meter:wind": {Symbol: "", Title: "Wind", Description: "Dedicated wind meter"},
-  "hiveot:thing:net": {Symbol: "", Title: "Network device", Description: "Generic network device"},
-  "hiveot:thing:net:gateway:zwave": {Symbol: "", Title: "ZWave gateway", Description: "Gateway providing access to ZWave devices"},
-  "hiveot:thing:sensor:environment": {Symbol: "", Title: "Environmental sensor", Description: "Environmental sensor with one or more features such as temperature, humidity, etc"},
-  "hiveot:thing:actuator:ranged": {Symbol: "", Title: "Ranged actuator", Description: "Generic ranged actuator with a set point"},
-  "hiveot:thing:actuator:valve:water": {Symbol: "", Title: "Water valve", Description: "Electric powered water valve"},
-  "hiveot:thing:control:pool": {Symbol: "", Title: "Pool control", Description: "Device for controlling pool settings"},
-  "hiveot:thing:device:indicator": {Symbol: "", Title: "Indicator", Description: "Visual or audio indicator device"},
-  "hiveot:thing:service": {Symbol: "", Title: "Service", Description: "General service for processing data and offering features of interest"},
-  "hiveot:thing:control:pushbutton": {Symbol: "", Title: "Momentary switch", Description: "Momentary push button control input"},
-  "hiveot:thing:meter": {Symbol: "", Title: "Meter", Description: "General metering device"},
-  "hiveot:thing:meter:electric:power": {Symbol: "", Title: "Electrical Power", Description: "Electrical power meter"},
+  "hiveot:thing:actuator:relay": {Symbol: "", Title: "Relay", Description: "Generic relay electrical switch"},
+  "hiveot:thing:control:irrigation": {Symbol: "", Title: "Irrigation control", Description: "Device for control of an irrigation system"},
+  "hiveot:thing:meter:electric:voltage": {Symbol: "", Title: "Voltage", Description: "Electrical voltage meter"},
   "hiveot:thing:net:wifi:ap": {Symbol: "", Title: "Wifi access point", Description: "Wireless access point for IP networks"},
-  "hiveot:thing:appliance": {Symbol: "", Title: "Appliance", Description: "Appliance to accomplish a particular task for occupant use"},
   "hiveot:thing:computer:pc": {Symbol: "", Title: "PC/Laptop", Description: "Personal computer/laptop"},
-  "hiveot:thing:computer:satphone": {Symbol: "", Title: "Satellite phone", Description: ""},
-  "hiveot:thing:computer:tablet": {Symbol: "", Title: "Tablet", Description: "Tablet computer"},
-  "hiveot:thing:sensor:multi": {Symbol: "", Title: "Multi sensor", Description: "Sense multiple inputs"},
-  "hiveot:thing:control:joystick": {Symbol: "", Title: "Joystick", Description: "Flight control stick"},
-  "hiveot:thing:media:amplifier": {Symbol: "", Title: "Audio amplifier", Description: "Audio amplifier with volume controls"},
-  "hiveot:thing:media:receiver": {Symbol: "", Title: "Receiver", Description: "Audio/video receiver and player"},
-  "hiveot:thing:meter:electric:energy": {Symbol: "", Title: "Electric energy", Description: "Electrical energy meter"},
-  "hiveot:thing:media": {Symbol: "", Title: "A/V media", Description: "Generic device for audio/video media record or playback"},
+  "hiveot:thing:control:pool": {Symbol: "", Title: "Pool control", Description: "Device for controlling pool settings"},
+  "hiveot:thing:meter:wind": {Symbol: "", Title: "Wind", Description: "Dedicated wind meter"},
+  "hiveot:thing:net:switch": {Symbol: "", Title: "Network switch", Description: "Network switch to connect computer devices to the network"},
+  "hiveot:thing:appliance:fridge": {Symbol: "", Title: "Fridge", Description: "Refrigerator appliance"},
+  "hiveot:thing:computer:voipphone": {Symbol: "", Title: "VoIP Phone", Description: "Voice over IP phone"},
+  "hiveot:thing:meter": {Symbol: "", Title: "Meter", Description: "General metering device"},
+  "hiveot:thing:sensor:security:doorwindow": {Symbol: "", Title: "Door/Window sensor", Description: "Dedicated door/window opening security sensor"},
+  "hiveot:thing:meter:electric": {Symbol: "", Title: "", Description: ""},
+  "hiveot:thing:net": {Symbol: "", Title: "Network device", Description: "Generic network device"},
+  "hiveot:thing:net:lora:gw": {Symbol: "", Title: "LoRaWAN gateway", Description: "Gateway providing access to LoRa devices"},
+  "hiveot:thing:sensor": {Symbol: "", Title: "Sensor", Description: "Generic sensor device"},
   "hiveot:thing:actuator:lock": {Symbol: "", Title: "Lock", Description: "Electronic door lock"},
-  "hiveot:thing:computer": {Symbol: "", Title: "Computing Device", Description: "General purpose computing device"},
-  "hiveot:thing:computer:memory": {Symbol: "", Title: "Memory", Description: "Stand-alone memory device such as eeprom or iButtons"},
-  "hiveot:thing:device:battery:monitor": {Symbol: "", Title: "Battery Monitor", Description: "Battery monitor and charge controller"},
+  "hiveot:thing:appliance:dryer": {Symbol: "", Title: "Dryer", Description: "Clothing dryer"},
+  "hiveot:thing:appliance:freezer": {Symbol: "", Title: "Freezer", Description: "Refrigerator freezer"},
+  "hiveot:thing:computer:cellphone": {Symbol: "", Title: "Cell Phone", Description: "Cellular phone"},
+  "hiveot:thing:meter:water": {Symbol: "", Title: "Water metering device", Description: "General water metering device"},
+  "hiveot:thing:sensor:security:motion": {Symbol: "", Title: "Motion sensor", Description: "Dedicated security sensor detecting motion"},
+  "hiveot:thing:computer:embedded": {Symbol: "", Title: "Embedded System", Description: "Embedded computing device"},
+  "hiveot:thing:computer:tablet": {Symbol: "", Title: "Tablet", Description: "Tablet computer"},
   "hiveot:thing:control:dimmer": {Symbol: "", Title: "Dimmer", Description: "Light dimmer input device"},
-  "hiveot:thing:control:switch": {Symbol: "", Title: "Input switch", Description: "On or off switch input control"},
-  "hiveot:thing:net:gateway:onewire": {Symbol: "", Title: "1-Wire gateway", Description: "Gateway providing access to 1-wire devices"},
+  "hiveot:thing:media:receiver": {Symbol: "", Title: "Receiver", Description: "Audio/video receiver and player"},
+  "hiveot:thing:net:gateway": {Symbol: "", Title: "Gateway", Description: "Generic gateway device providing access to other devices"},
   "hiveot:thing:net:router": {Symbol: "", Title: "Network router", Description: "IP ThingNetwork router providing access to other IP networks"},
-  "hiveot:thing:device": {Symbol: "", Title: "Device", Description: "Device of unknown purpose"},
-  "hiveot:thing:media:microphone": {Symbol: "", Title: "Microphone", Description: "Microphone for capturing audio"},
-  "hiveot:thing:meter:electric": {Symbol: "", Title: "", Description: ""},
-  "hiveot:thing:meter:electric:voltage": {Symbol: "", Title: "Voltage", Description: "Electrical voltage meter"},
+  "hiveot:thing:sensor:security": {Symbol: "", Title: "Security", Description: "Generic security sensor"},
+  "hiveot:thing:sensor:smoke": {Symbol: "", Title: "Smoke detector", Description: ""},
+  "hiveot:thing:actuator:motor": {Symbol: "", Title: "Motor", Description: "Motor driven actuator, such as garage door, blinds, tv lifts"},
+  "hiveot:thing:control:toggle": {Symbol: "", Title: "Toggle switch", Description: "Toggle switch input control"},
+  "hiveot:thing:media:speaker": {Symbol: "", Title: "Connected speakers", Description: "Network connected speakers"},
+  "hiveot:thing:meter:fuel:level": {Symbol: "", Title: "Fuel level", Description: "Dedicated fuel level metering device"},
+  "hiveot:thing:net:gateway:zwave": {Symbol: "", Title: "ZWave gateway", Description: "Gateway providing access to ZWave devices"},
+  "hiveot:thing:appliance": {Symbol: "", Title: "Appliance", Description: "Appliance to accomplish a particular task for occupant use"},
   "hiveot:thing:appliance:washer": {Symbol: "", Title: "Washer", Description: "Clothing washer"},
-  "hiveot:thing:computer:potsphone": {Symbol: "", Title: "Land Line", Description: "Plain Old Telephone System, aka landline"},
-  "hiveot:thing:control:climate": {Symbol: "", Title: "Climate control", Description: "Device for controlling climate of a space"},
-  "hiveot:thing:control:irrigation": {Symbol: "", Title: "Irrigation control", Description: "Device for control of an irrigation system"},
-  "hiveot:thing:net:wifi": {Symbol: "", Title: "Wifi device", Description: "Generic wifi device"},
-  "hiveot:thing:net:lora:gw": {Symbol: "", Title: "LoRaWAN gateway", Description: "Gateway providing access to LoRa devices"},
-  "hiveot:thing:sensor:scale": {Symbol: "", Title: "Scale", Description: "Electronic weigh scale"},
+  "hiveot:thing:control:joystick": {Symbol: "", Title: "Joystick", Description: "Flight control stick"},
+  "hiveot:thing:meter:electric:energy": {Symbol: "", Title: "Electric energy", Description: "Electrical energy meter"},
 }
 
 
 // type: UnitClasses
 // version: 0.1
-// generated: 29 Dec 24 17:28 PST
+// generated: 31 Dec 24 22:27 PST
 // source: github.com/hiveot/hub/api/vocab/ht-unit-classes.yaml
 // namespace: ht
 export const UnitAmpere = "hiveot:unit:ampere";
@@ -576,35 +576,35 @@ export const UnitWatt = "hiveot:unit:watt";
 
 // UnitClassesMap maps @type to symbol, title and description
 export const UnitClassesMap = {
+  "hiveot:unit:degree": {Symbol: "degree", Title: "Degree", Description: "Angle in 0-360 degrees"},
+  "hiveot:unit:foot": {Symbol: "ft", Title: "Foot", Description: "Imperial unit of distance. 1 foot equals 0.3048 meters"},
+  "hiveot:unit:psi": {Symbol: "PSI", Title: "PSI", Description: "Unit of pressure. Pounds of force per square inch. 1PSI equals 6984 Pascals."},
+  "hiveot:unit:radian": {Symbol: "", Title: "Radian", Description: "Angle in 0-2pi"},
+  "hiveot:unit:kelvin": {Symbol: "K", Title: "Kelvin", Description: "SI unit of thermodynamic temperature. 0 K represents absolute zero, the absence of all heat. 0 C equals +273.15K"},
+  "hiveot:unit:lumen": {Symbol: "lm", Title: "Lumen", Description: "SI unit luminous flux. Measure of perceived power of visible light. 1lm = 1 cd steradian"},
+  "hiveot:unit:lux": {Symbol: "lx", Title: "Lux", Description: "SI unit illuminance. Equal to 1 lumen per square meter."},
+  "hiveot:unit:ppm": {Symbol: "ppm", Title: "PPM", Description: "Parts per million"},
+  "hiveot:unit:gallon": {Symbol: "gl", Title: "Gallon", Description: "Unit of volume. 1 Imperial gallon is 4.54609 liters. 1 US liquid gallon is 3.78541 liters. 1 US dry gallon is 4.405 liters. "},
+  "hiveot:unit:liter": {Symbol: "l", Title: "Liter", Description: "SI unit of volume equivalent to 1 cubic decimeter."},
   "hiveot:unit:meter": {Symbol: "m", Title: "Meter", Description: "Distance in meters. 1m=c/299792458"},
   "hiveot:unit:millisecond": {Symbol: "ms", Title: "millisecond", Description: "Unit of time in milli-seconds. Equal to 1/1000 of a second."},
-  "hiveot:unit:ppm": {Symbol: "ppm", Title: "PPM", Description: "Parts per million"},
-  "hiveot:unit:psi": {Symbol: "PSI", Title: "PSI", Description: "Unit of pressure. Pounds of force per square inch. 1PSI equals 6984 Pascals."},
-  "hiveot:unit:fahrenheit": {Symbol: "F", Title: "Fahrenheit", Description: "Temperature in Fahrenheit"},
-  "hiveot:unit:milesperhour": {Symbol: "mph", Title: "Miles per hour", Description: "Speed in miles per hour"},
-  "hiveot:unit:foot": {Symbol: "ft", Title: "Foot", Description: "Imperial unit of distance. 1 foot equals 0.3048 meters"},
-  "hiveot:unit:degree": {Symbol: "degree", Title: "Degree", Description: "Angle in 0-360 degrees"},
-  "hiveot:unit:millibar": {Symbol: "mbar", Title: "millibar", Description: "Metric unit of pressure. 1/1000th of a bar. Equal to 100 pascals. Amount of force it takes to move an object weighing a gram, one centimeter in one second."},
   "hiveot:unit:pascal": {Symbol: "Pa", Title: "Pascal", Description: "SI unit of pressure. Equal to 1 newton of force applied over 1 square meter."},
-  "hiveot:unit:percent": {Symbol: "%", Title: "Percent", Description: "Fractions of 100"},
-  "hiveot:unit:second": {Symbol: "s", Title: "Second", Description: "SI unit of time based on caesium frequency"},
-  "hiveot:unit:count": {Symbol: "(N)", Title: "Count", Description: ""},
-  "hiveot:unit:kilowatthour": {Symbol: "kWh", Title: "Kilowatt-hour", Description: "non-SI unit of energy equivalent to 3.6 megajoules."},
-  "hiveot:unit:meterspersecond": {Symbol: "m/s", Title: "Meters per second", Description: "SI unit of speed in meters per second"},
-  "hiveot:unit:mole": {Symbol: "mol", Title: "Mole", Description: "SI unit of measurement for amount of substance. Eg, molecules."},
   "hiveot:unit:watt": {Symbol: "W", Title: "Watt", Description: "SI unit of power. Equal to 1 joule per second; or work performed when a current of 1 ampere flows across an electric potential of one volt."},
   "hiveot:unit:volt": {Symbol: "V", Title: "Volt", Description: "SI unit of electric potential; Energy consumption of 1 joule per electric charge of one coulomb"},
+  "hiveot:unit:count": {Symbol: "(N)", Title: "Count", Description: ""},
+  "hiveot:unit:fahrenheit": {Symbol: "F", Title: "Fahrenheit", Description: "Temperature in Fahrenheit"},
+  "hiveot:unit:candela": {Symbol: "cd", Title: "Candela", Description: "SI unit of luminous intensity in a given direction. Roughly the same brightness as the common candle."},
+  "hiveot:unit:kilowatthour": {Symbol: "kWh", Title: "Kilowatt-hour", Description: "non-SI unit of energy equivalent to 3.6 megajoules."},
+  "hiveot:unit:mercury": {Symbol: "Hg", Title: "Mercury", Description: "Unit of atmospheric pressure in the United States. 1 Hg equals 33.8639 mbar."},
+  "hiveot:unit:percent": {Symbol: "%", Title: "Percent", Description: "Fractions of 100"},
   "hiveot:unit:kilogram": {Symbol: "kg", Title: "Kilogram", Description: ""},
-  "hiveot:unit:radian": {Symbol: "", Title: "Radian", Description: "Angle in 0-2pi"},
+  "hiveot:unit:mole": {Symbol: "mol", Title: "Mole", Description: "SI unit of measurement for amount of substance. Eg, molecules."},
   "hiveot:unit:pound": {Symbol: "lbs", Title: "Pound", Description: "Imperial unit of weight. Equivalent to 0.453592 Kg. 1 Kg is 2.205 lbs"},
-  "hiveot:unit:candela": {Symbol: "cd", Title: "Candela", Description: "SI unit of luminous intensity in a given direction. Roughly the same brightness as the common candle."},
   "hiveot:unit:ampere": {Symbol: "A", Title: "Ampere", Description: "Electrical current in Amperes based on the elementary charge flow per second"},
-  "hiveot:unit:gallon": {Symbol: "gl", Title: "Gallon", Description: "Unit of volume. 1 Imperial gallon is 4.54609 liters. 1 US liquid gallon is 3.78541 liters. 1 US dry gallon is 4.405 liters. "},
-  "hiveot:unit:kph": {Symbol: "kph", Title: "Km per hour", Description: "Speed in kilometers per hour"},
-  "hiveot:unit:lumen": {Symbol: "lm", Title: "Lumen", Description: "SI unit luminous flux. Measure of perceived power of visible light. 1lm = 1 cd steradian"},
-  "hiveot:unit:lux": {Symbol: "lx", Title: "Lux", Description: "SI unit illuminance. Equal to 1 lumen per square meter."},
   "hiveot:unit:celcius": {Symbol: "°C", Title: "Celcius", Description: "Temperature in Celcius"},
-  "hiveot:unit:liter": {Symbol: "l", Title: "Liter", Description: "SI unit of volume equivalent to 1 cubic decimeter."},
-  "hiveot:unit:mercury": {Symbol: "Hg", Title: "Mercury", Description: "Unit of atmospheric pressure in the United States. 1 Hg equals 33.8639 mbar."},
-  "hiveot:unit:kelvin": {Symbol: "K", Title: "Kelvin", Description: "SI unit of thermodynamic temperature. 0 K represents absolute zero, the absence of all heat. 0 C equals +273.15K"},
+  "hiveot:unit:kph": {Symbol: "kph", Title: "Km per hour", Description: "Speed in kilometers per hour"},
+  "hiveot:unit:meterspersecond": {Symbol: "m/s", Title: "Meters per second", Description: "SI unit of speed in meters per second"},
+  "hiveot:unit:milesperhour": {Symbol: "mph", Title: "Miles per hour", Description: "Speed in miles per hour"},
+  "hiveot:unit:millibar": {Symbol: "mbar", Title: "millibar", Description: "Metric unit of pressure. 1/1000th of a bar. Equal to 100 pascals. Amount of force it takes to move an object weighing a gram, one centimeter in one second."},
+  "hiveot:unit:second": {Symbol: "s", Title: "Second", Description: "SI unit of time based on caesium frequency"},
 }
diff --git a/api/py/vocab/vocab.py b/api/py/vocab/vocab.py
index ec4f64bb..c142f750 100644
--- a/api/py/vocab/vocab.py
+++ b/api/py/vocab/vocab.py
@@ -3,7 +3,7 @@
 
 # type: ActionStatusStatus
 # version: 0.1
-# generated: 29 Dec 24 17:28 PST
+# generated: 31 Dec 24 22:27 PST
 # source: github.com/hiveot/hub/api/vocab/ht-constants.yaml
 # description: Request progress status constants
 RequestCompleted = "completed"
@@ -14,7 +14,7 @@
 
 # type: WoTVocab
 # version: 0.1
-# generated: 29 Dec 24 17:28 PST
+# generated: 31 Dec 24 22:27 PST
 # source: github.com/hiveot/hub/api/vocab/wot-vocab.yaml
 # description: WoT vocabulary definition. See https://www.w3.org/TR/2020/WD-wot-thing-description11-20201124/#sec-core-vocabulary-definition
 HTOpLogin = "login"
@@ -102,67 +102,9 @@
 WoTVersion = "version"
 # end of WoTVocab
 
-# type: ActionClasses
-# version: 0.1
-# generated: 29 Dec 24 17:28 PST
-# source: github.com/hiveot/hub/api/vocab/ht-action-classes.yaml
-# namespace: ht
-ActionDimmer = "hiveot:action:dimmer"
-ActionDimmerDecrement = "hiveot:action:dimmer:decrement"
-ActionDimmerIncrement = "hiveot:action:dimmer:increment"
-ActionDimmerSet = "hiveot:action:dimmer:set"
-ActionMedia = "hiveot:action:media"
-ActionMediaMute = "hiveot:action:media:mute"
-ActionMediaNext = "hiveot:action:media:next"
-ActionMediaPause = "hiveot:action:media:pause"
-ActionMediaPlay = "hiveot:action:media:play"
-ActionMediaPrevious = "hiveot:action:media:previous"
-ActionMediaUnmute = "hiveot:action:media:unmute"
-ActionMediaVolume = "hiveot:action:media:volume"
-ActionMediaVolumeDecrease = "hiveot:action:media:volume:decrease"
-ActionMediaVolumeIncrease = "hiveot:action:media:volume:increase"
-ActionSwitch = "hiveot:action:switch"
-ActionSwitchOnOff = "hiveot:action:switch:onoff"
-ActionSwitchToggle = "hiveot:action:switch:toggle"
-ActionThingDisable = "hiveot:action:thing:disable"
-ActionThingEnable = "hiveot:action:thing:enable"
-ActionThingStart = "hiveot:action:thing:start"
-ActionThingStop = "hiveot:action:thing:stop"
-ActionValveClose = "hiveot:action:valve:close"
-ActionValveOpen = "hiveot:action:valve:open"
-# end of ActionClasses
-
-# ActionClassesMap maps @type to symbol, title and description
-ActionClassesMap = {
-  "hiveot:action:switch": {"Symbol": "", "Title": "Switch", "Description": "General switch action"},
-  "hiveot:action:switch:onoff": {"Symbol": "", "Title": "Set On/Off switch", "Description": "Action to set the switch on/off state"},
-  "hiveot:action:valve:open": {"Symbol": "", "Title": "Open valve", "Description": "Action to open the valve"},
-  "hiveot:action:media": {"Symbol": "", "Title": "Media control", "Description": "Commands to control media recording and playback"},
-  "hiveot:action:media:mute": {"Symbol": "", "Title": "Mute", "Description": "Mute audio"},
-  "hiveot:action:media:pause": {"Symbol": "", "Title": "Pause", "Description": "Pause playback"},
-  "hiveot:action:media:volume:increase": {"Symbol": "", "Title": "Increase volume", "Description": "Increase volume"},
-  "hiveot:action:dimmer:set": {"Symbol": "", "Title": "Set dimmer", "Description": "Action to set the dimmer value"},
-  "hiveot:action:valve:close": {"Symbol": "", "Title": "Close valve", "Description": "Action to close the valve"},
-  "hiveot:action:media:next": {"Symbol": "", "Title": "Next", "Description": "Next track or station"},
-  "hiveot:action:media:previous": {"Symbol": "", "Title": "Previous", "Description": "Previous track or station"},
-  "hiveot:action:media:unmute": {"Symbol": "", "Title": "Unmute", "Description": "Unmute audio"},
-  "hiveot:action:dimmer": {"Symbol": "", "Title": "Dimmer", "Description": "General dimmer action"},
-  "hiveot:action:dimmer:decrement": {"Symbol": "", "Title": "Lower dimmer", "Description": ""},
-  "hiveot:action:media:volume": {"Symbol": "", "Title": "Volume", "Description": "Set volume level"},
-  "hiveot:action:media:volume:decrease": {"Symbol": "", "Title": "Decrease volume", "Description": "Decrease volume"},
-  "hiveot:action:thing:disable": {"Symbol": "", "Title": "Disable", "Description": "Action to disable a thing"},
-  "hiveot:action:thing:start": {"Symbol": "", "Title": "Start", "Description": "Start running a task"},
-  "hiveot:action:media:play": {"Symbol": "", "Title": "Play", "Description": "Start or continue playback"},
-  "hiveot:action:dimmer:increment": {"Symbol": "", "Title": "Increase dimmer", "Description": ""},
-  "hiveot:action:switch:toggle": {"Symbol": "", "Title": "Toggle switch", "Description": "Action to toggle the switch"},
-  "hiveot:action:thing:enable": {"Symbol": "", "Title": "Enable", "Description": "Action to enable a thing"},
-  "hiveot:action:thing:stop": {"Symbol": "", "Title": "Stop", "Description": "Stop a running task"},
-}
-
-
 # type: PropertyClasses
 # version: 0.1
-# generated: 29 Dec 24 17:28 PST
+# generated: 31 Dec 24 22:27 PST
 # source: github.com/hiveot/hub/api/vocab/ht-property-classes.yaml
 # namespace: ht
 PropAlarmMotion = "hiveot:prop:alarm:motion"
@@ -249,92 +191,92 @@
 
 # PropertyClassesMap maps @type to symbol, title and description
 PropertyClassesMap = {
-  "hiveot:prop:env:dewpoint": {"Symbol": "", "Title": "Dew point", "Description": "Dew point temperature"},
-  "hiveot:prop:location": {"Symbol": "", "Title": "Location", "Description": "General location information"},
-  "hiveot:prop:net:ip4": {"Symbol": "", "Title": "IP4 address", "Description": "Device IP4 address"},
-  "hiveot:prop:net:signalstrength": {"Symbol": "", "Title": "Signal strength", "Description": "Wireless signal strength"},
-  "hiveot:prop:env:humidex": {"Symbol": "", "Title": "Humidex", "Description": ""},
+  "hiveot:prop:net:port": {"Symbol": "", "Title": "Port", "Description": "Network port"},
+  "hiveot:prop:status:onoff": {"Symbol": "", "Title": "On/off status", "Description": ""},
+  "hiveot:prop:switch:locked": {"Symbol": "", "Title": "Lock", "Description": "Electric lock status"},
+  "hiveot:prop:device:status": {"Symbol": "", "Title": "Status", "Description": "Device status; alive, awake, dead, sleeping"},
+  "hiveot:prop:env:co2": {"Symbol": "", "Title": "Carbon dioxide level", "Description": "Carbon dioxide level"},
   "hiveot:prop:env:wind:heading": {"Symbol": "", "Title": "Wind heading", "Description": ""},
-  "hiveot:prop:media:paused": {"Symbol": "", "Title": "Paused", "Description": "Media is paused"},
+  "hiveot:prop:location:latitude": {"Symbol": "", "Title": "Latitude", "Description": "Latitude geographic coordinate"},
+  "hiveot:prop:location:name": {"Symbol": "", "Title": "Location name", "Description": "Name of the location"},
+  "hiveot:prop:net:connection": {"Symbol": "", "Title": "Connection", "Description": "Connection status, connected, connecting, retrying, disconnected,..."},
+  "hiveot:prop:switch:dimmer": {"Symbol": "", "Title": "Dimmer value", "Description": ""},
+  "hiveot:prop:device:hardwareversion": {"Symbol": "", "Title": "Hardware version", "Description": ""},
+  "hiveot:prop:electric:current": {"Symbol": "", "Title": "Current", "Description": "Electrical current"},
+  "hiveot:prop:env:acceleration": {"Symbol": "", "Title": "Acceleration", "Description": ""},
+  "hiveot:prop:env:co": {"Symbol": "", "Title": "Carbon monoxide level", "Description": "Carbon monoxide level"},
+  "hiveot:prop:net:domainname": {"Symbol": "", "Title": "Domain name", "Description": "Domainname of the client"},
+  "hiveot:prop:net:latency": {"Symbol": "", "Title": "Network latency", "Description": "Delay between hub and client"},
+  "hiveot:prop:net:mac": {"Symbol": "", "Title": "MAC", "Description": "Hardware MAC address"},
+  "hiveot:prop:alarm:motion": {"Symbol": "", "Title": "Motion", "Description": "Motion detected"},
+  "hiveot:prop:device:description": {"Symbol": "", "Title": "Description", "Description": "Device product description"},
+  "hiveot:prop:device:firmwareversion": {"Symbol": "", "Title": "Firmware version", "Description": ""},
+  "hiveot:prop:media:track": {"Symbol": "", "Title": "Track", "Description": "Selected A/V track"},
+  "hiveot:prop:media:volume": {"Symbol": "", "Title": "Volume", "Description": "Media volume setting"},
   "hiveot:prop:media:station": {"Symbol": "", "Title": "Station", "Description": "Selected radio station"},
   "hiveot:prop:net:gateway": {"Symbol": "", "Title": "Gateway", "Description": "Network gateway address"},
-  "hiveot:prop:electric:overload": {"Symbol": "", "Title": "Overload protection", "Description": "Cut load on overload"},
-  "hiveot:prop:env:co2": {"Symbol": "", "Title": "Carbon dioxide level", "Description": "Carbon dioxide level"},
-  "hiveot:prop:env:uv": {"Symbol": "", "Title": "UV", "Description": ""},
-  "hiveot:prop:env:vibration": {"Symbol": "", "Title": "Vibration", "Description": ""},
   "hiveot:prop:device:battery": {"Symbol": "", "Title": "Battery level", "Description": "Device battery level"},
-  "hiveot:prop:device:make": {"Symbol": "", "Title": "Make", "Description": "Device manufacturer"},
-  "hiveot:prop:env:co": {"Symbol": "", "Title": "Carbon monoxide level", "Description": "Carbon monoxide level"},
-  "hiveot:prop:location:street": {"Symbol": "", "Title": "Street", "Description": "Street address"},
-  "hiveot:prop:location:name": {"Symbol": "", "Title": "Location name", "Description": "Name of the location"},
-  "hiveot:prop:media:track": {"Symbol": "", "Title": "Track", "Description": "Selected A/V track"},
-  "hiveot:prop:status:openclosed": {"Symbol": "", "Title": "Open/Closed status", "Description": ""},
-  "hiveot:prop:env": {"Symbol": "", "Title": "Environmental property", "Description": "Property of environmental sensor"},
-  "hiveot:prop:env:luminance": {"Symbol": "", "Title": "Luminance", "Description": ""},
-  "hiveot:prop:net:ip6": {"Symbol": "", "Title": "IP6 address", "Description": "Device IP6 address"},
-  "hiveot:prop:status:onoff": {"Symbol": "", "Title": "On/off status", "Description": ""},
-  "hiveot:prop:switch:dimmer": {"Symbol": "", "Title": "Dimmer value", "Description": ""},
-  "hiveot:prop:device:softwareversion": {"Symbol": "", "Title": "Software version", "Description": ""},
-  "hiveot:prop:status:yes-no": {"Symbol": "", "Title": "Yes/No", "Description": "Status with yes or no value"},
-  "hiveot:prop:env:water:flowrate": {"Symbol": "", "Title": "Water flow rate", "Description": ""},
-  "hiveot:prop:location:zipcode": {"Symbol": "", "Title": "Zip code", "Description": "Location ZIP code"},
-  "hiveot:prop:net:connection": {"Symbol": "", "Title": "Connection", "Description": "Connection status, connected, connecting, retrying, disconnected,..."},
-  "hiveot:prop:switch:onoff": {"Symbol": "", "Title": "On/Off switch", "Description": ""},
-  "hiveot:prop:switch:light": {"Symbol": "", "Title": "Light switch", "Description": ""},
-  "hiveot:prop:net:subnet": {"Symbol": "", "Title": "Subnet", "Description": "Network subnet address. Example: 192.168.0.0"},
-  "hiveot:prop:device": {"Symbol": "", "Title": "Device attributes", "Description": "Attributes describing a device"},
   "hiveot:prop:electric": {"Symbol": "", "Title": "Electrical properties", "Description": "General group of electrical properties"},
-  "hiveot:prop:env:humidity": {"Symbol": "", "Title": "Humidity", "Description": ""},
-  "hiveot:prop:location:city": {"Symbol": "", "Title": "City", "Description": "City name"},
-  "hiveot:prop:location:latitude": {"Symbol": "", "Title": "Latitude", "Description": "Latitude geographic coordinate"},
-  "hiveot:prop:net": {"Symbol": "", "Title": "Network properties", "Description": "General network properties"},
-  "hiveot:prop:net:latency": {"Symbol": "", "Title": "Network latency", "Description": "Delay between hub and client"},
-  "hiveot:prop:device:enabled-disabled": {"Symbol": "", "Title": "Enabled/Disabled", "Description": "Enabled or disabled state"},
+  "hiveot:prop:electric:poer": {"Symbol": "", "Title": "Power", "Description": "Electrical power being consumed"},
+  "hiveot:prop:env:airquality": {"Symbol": "", "Title": "Air quality", "Description": "Air quality level"},
   "hiveot:prop:device:title": {"Symbol": "", "Title": "Title", "Description": "Device friendly title"},
-  "hiveot:prop:env:cpuload": {"Symbol": "", "Title": "CPU load level", "Description": "Device CPU load level"},
-  "hiveot:prop:env:acceleration": {"Symbol": "", "Title": "Acceleration", "Description": ""},
+  "hiveot:prop:env:vibration": {"Symbol": "", "Title": "Vibration", "Description": ""},
+  "hiveot:prop:status:yes-no": {"Symbol": "", "Title": "Yes/No", "Description": "Status with yes or no value"},
+  "hiveot:prop:media:paused": {"Symbol": "", "Title": "Paused", "Description": "Media is paused"},
   "hiveot:prop:env:fuel:level": {"Symbol": "", "Title": "Fuel level", "Description": ""},
+  "hiveot:prop:env:water:flowrate": {"Symbol": "", "Title": "Water flow rate", "Description": ""},
+  "hiveot:prop:location": {"Symbol": "", "Title": "Location", "Description": "General location information"},
+  "hiveot:prop:location:zipcode": {"Symbol": "", "Title": "Zip code", "Description": "Location ZIP code"},
   "hiveot:prop:location:longitude": {"Symbol": "", "Title": "Longitude", "Description": "Longitude geographic coordinate"},
-  "hiveot:prop:media:volume": {"Symbol": "", "Title": "Volume", "Description": "Media volume setting"},
-  "hiveot:prop:net:mac": {"Symbol": "", "Title": "MAC", "Description": "Hardware MAC address"},
-  "hiveot:prop:alarm:motion": {"Symbol": "", "Title": "Motion", "Description": "Motion detected"},
+  "hiveot:prop:net:address": {"Symbol": "", "Title": "Address", "Description": "Network address"},
   "hiveot:prop:device:pollinterval": {"Symbol": "", "Title": "Polling interval", "Description": "Interval to poll for updates"},
-  "hiveot:prop:electric:current": {"Symbol": "", "Title": "Current", "Description": "Electrical current"},
-  "hiveot:prop:electric:poer": {"Symbol": "", "Title": "Power", "Description": "Electrical power being consumed"},
+  "hiveot:prop:env:pressure": {"Symbol": "", "Title": "Pressure", "Description": ""},
+  "hiveot:prop:status:openclosed": {"Symbol": "", "Title": "Open/Closed status", "Description": ""},
   "hiveot:prop:env:barometer": {"Symbol": "", "Title": "Atmospheric pressure", "Description": "Barometric pressure of the atmosphere"},
-  "hiveot:prop:net:hostname": {"Symbol": "", "Title": "Hostname", "Description": "Hostname of the client"},
-  "hiveot:prop:net:mask": {"Symbol": "", "Title": "Netmask", "Description": "Network mask. Example: 255.255.255.0 or 24/8"},
-  "hiveot:prop:device:description": {"Symbol": "", "Title": "Description", "Description": "Device product description"},
-  "hiveot:prop:electric:energy": {"Symbol": "", "Title": "Energy", "Description": "Electrical energy consumed"},
+  "hiveot:prop:env:temperature": {"Symbol": "", "Title": "Temperature", "Description": ""},
+  "hiveot:prop:net:ip4": {"Symbol": "", "Title": "IP4 address", "Description": "Device IP4 address"},
+  "hiveot:prop:net:ip6": {"Symbol": "", "Title": "IP6 address", "Description": "Device IP6 address"},
   "hiveot:prop:alarm:status": {"Symbol": "", "Title": "Alarm state", "Description": "Current alarm status"},
-  "hiveot:prop:env:airquality": {"Symbol": "", "Title": "Air quality", "Description": "Air quality level"},
-  "hiveot:prop:env:fuel:flowrate": {"Symbol": "", "Title": "Fuel flow rate", "Description": ""},
-  "hiveot:prop:env:timezone": {"Symbol": "", "Title": "Timezone", "Description": ""},
+  "hiveot:prop:device": {"Symbol": "", "Title": "Device attributes", "Description": "Attributes describing a device"},
+  "hiveot:prop:electric:overload": {"Symbol": "", "Title": "Overload protection", "Description": "Cut load on overload"},
+  "hiveot:prop:env": {"Symbol": "", "Title": "Environmental property", "Description": "Property of environmental sensor"},
+  "hiveot:prop:device:make": {"Symbol": "", "Title": "Make", "Description": "Device manufacturer"},
+  "hiveot:prop:device:model": {"Symbol": "", "Title": "Model", "Description": "Device model"},
+  "hiveot:prop:location:street": {"Symbol": "", "Title": "Street", "Description": "Street address"},
+  "hiveot:prop:location:city": {"Symbol": "", "Title": "City", "Description": "City name"},
   "hiveot:prop:env:wind:speed": {"Symbol": "", "Title": "Wind speed", "Description": ""},
-  "hiveot:prop:net:port": {"Symbol": "", "Title": "Port", "Description": "Network port"},
-  "hiveot:prop:status:started-stopped": {"Symbol": "", "Title": "Started/Stopped", "Description": "Started or stopped status"},
-  "hiveot:prop:device:hardwareversion": {"Symbol": "", "Title": "Hardware version", "Description": ""},
-  "hiveot:prop:device:status": {"Symbol": "", "Title": "Status", "Description": "Device status; alive, awake, dead, sleeping"},
-  "hiveot:prop:env:pressure": {"Symbol": "", "Title": "Pressure", "Description": ""},
+  "hiveot:prop:net:hostname": {"Symbol": "", "Title": "Hostname", "Description": "Hostname of the client"},
+  "hiveot:prop:switch": {"Symbol": "", "Title": "Switch status", "Description": ""},
+  "hiveot:prop:device:softwareversion": {"Symbol": "", "Title": "Software version", "Description": ""},
+  "hiveot:prop:env:humidex": {"Symbol": "", "Title": "Humidex", "Description": ""},
+  "hiveot:prop:env:volume": {"Symbol": "", "Title": "Volume", "Description": ""},
   "hiveot:prop:env:water:level": {"Symbol": "", "Title": "Water level", "Description": ""},
-  "hiveot:prop:media:playing": {"Symbol": "", "Title": "Playing", "Description": "Media is playing"},
-  "hiveot:prop:device:firmwareversion": {"Symbol": "", "Title": "Firmware version", "Description": ""},
+  "hiveot:prop:env:uv": {"Symbol": "", "Title": "UV", "Description": ""},
+  "hiveot:prop:net:signalstrength": {"Symbol": "", "Title": "Signal strength", "Description": "Wireless signal strength"},
+  "hiveot:prop:net:subnet": {"Symbol": "", "Title": "Subnet", "Description": "Network subnet address. Example: 192.168.0.0"},
   "hiveot:prop:electric:voltage": {"Symbol": "", "Title": "Voltage", "Description": "Electrical voltage potential"},
-  "hiveot:prop:env:volume": {"Symbol": "", "Title": "Volume", "Description": ""},
-  "hiveot:prop:net:domainname": {"Symbol": "", "Title": "Domain name", "Description": "Domainname of the client"},
-  "hiveot:prop:device:model": {"Symbol": "", "Title": "Model", "Description": "Device model"},
-  "hiveot:prop:env:temperature": {"Symbol": "", "Title": "Temperature", "Description": ""},
+  "hiveot:prop:env:humidity": {"Symbol": "", "Title": "Humidity", "Description": ""},
+  "hiveot:prop:env:luminance": {"Symbol": "", "Title": "Luminance", "Description": ""},
+  "hiveot:prop:env:timezone": {"Symbol": "", "Title": "Timezone", "Description": ""},
+  "hiveot:prop:net": {"Symbol": "", "Title": "Network properties", "Description": "General network properties"},
+  "hiveot:prop:status:started-stopped": {"Symbol": "", "Title": "Started/Stopped", "Description": "Started or stopped status"},
+  "hiveot:prop:switch:onoff": {"Symbol": "", "Title": "On/Off switch", "Description": ""},
+  "hiveot:prop:device:enabled-disabled": {"Symbol": "", "Title": "Enabled/Disabled", "Description": "Enabled or disabled state"},
+  "hiveot:prop:env:cpuload": {"Symbol": "", "Title": "CPU load level", "Description": "Device CPU load level"},
+  "hiveot:prop:env:fuel:flowrate": {"Symbol": "", "Title": "Fuel flow rate", "Description": ""},
   "hiveot:prop:media": {"Symbol": "", "Title": "Media commands", "Description": "Control of media equipment"},
+  "hiveot:prop:env:dewpoint": {"Symbol": "", "Title": "Dew point", "Description": "Dew point temperature"},
+  "hiveot:prop:net:mask": {"Symbol": "", "Title": "Netmask", "Description": "Network mask. Example: 255.255.255.0 or 24/8"},
+  "hiveot:prop:electric:energy": {"Symbol": "", "Title": "Energy", "Description": "Electrical energy consumed"},
+  "hiveot:prop:media:playing": {"Symbol": "", "Title": "Playing", "Description": "Media is playing"},
   "hiveot:prop:media:muted": {"Symbol": "", "Title": "Muted", "Description": "Audio is muted"},
-  "hiveot:prop:net:address": {"Symbol": "", "Title": "Address", "Description": "Network address"},
-  "hiveot:prop:switch": {"Symbol": "", "Title": "Switch status", "Description": ""},
-  "hiveot:prop:switch:locked": {"Symbol": "", "Title": "Lock", "Description": "Electric lock status"},
+  "hiveot:prop:switch:light": {"Symbol": "", "Title": "Light switch", "Description": ""},
 }
 
 
 # type: ThingClasses
 # version: 0.1
-# generated: 29 Dec 24 17:28 PST
+# generated: 31 Dec 24 22:27 PST
 # source: github.com/hiveot/hub/api/vocab/ht-thing-classes.yaml
 # namespace: ht
 ThingActuator = "hiveot:thing:actuator"
@@ -437,108 +379,108 @@
 
 # ThingClassesMap maps @type to symbol, title and description
 ThingClassesMap = {
-  "hiveot:thing:actuator:valve:water": {"Symbol": "", "Title": "Water valve", "Description": "Electric powered water valve"},
-  "hiveot:thing:control:joystick": {"Symbol": "", "Title": "Joystick", "Description": "Flight control stick"},
-  "hiveot:thing:media": {"Symbol": "", "Title": "A/V media", "Description": "Generic device for audio/video media record or playback"},
-  "hiveot:thing:media:camera": {"Symbol": "", "Title": "Camera", "Description": "Video camera"},
-  "hiveot:thing:meter:fuel": {"Symbol": "", "Title": "Fuel metering device", "Description": "General fuel metering device"},
+  "hiveot:thing:sensor:scale": {"Symbol": "", "Title": "Scale", "Description": "Electronic weigh scale"},
+  "hiveot:thing:appliance": {"Symbol": "", "Title": "Appliance", "Description": "Appliance to accomplish a particular task for occupant use"},
+  "hiveot:thing:computer:cellphone": {"Symbol": "", "Title": "Cell Phone", "Description": "Cellular phone"},
+  "hiveot:thing:meter:water:consumption": {"Symbol": "", "Title": "Water consumption meter", "Description": "Water consumption meter"},
   "hiveot:thing:net:gateway:onewire": {"Symbol": "", "Title": "1-Wire gateway", "Description": "Gateway providing access to 1-wire devices"},
-  "hiveot:thing:net:gateway:zwave": {"Symbol": "", "Title": "ZWave gateway", "Description": "Gateway providing access to ZWave devices"},
-  "hiveot:thing:actuator:lock": {"Symbol": "", "Title": "Lock", "Description": "Electronic door lock"},
-  "hiveot:thing:computer:pc": {"Symbol": "", "Title": "PC/Laptop", "Description": "Personal computer/laptop"},
-  "hiveot:thing:control:thermostat": {"Symbol": "", "Title": "Thermostat", "Description": "Thermostat HVAC control"},
-  "hiveot:thing:net:gateway:coap": {"Symbol": "", "Title": "CoAP gateway", "Description": "Gateway providing access to CoAP devices"},
-  "hiveot:thing:sensor:smoke": {"Symbol": "", "Title": "Smoke detector", "Description": ""},
-  "hiveot:thing:sensor:water:leak": {"Symbol": "", "Title": "Water leak detector", "Description": "Dedicated water leak detector"},
-  "hiveot:thing:actuator": {"Symbol": "", "Title": "Actuator", "Description": "Generic actuator"},
-  "hiveot:thing:actuator:dimmer": {"Symbol": "", "Title": "Dimmer", "Description": "Light dimmer"},
-  "hiveot:thing:media:amplifier": {"Symbol": "", "Title": "Audio amplifier", "Description": "Audio amplifier with volume controls"},
+  "hiveot:thing:sensor:security": {"Symbol": "", "Title": "Security", "Description": "Generic security sensor"},
+  "hiveot:thing:sensor:security:doorwindow": {"Symbol": "", "Title": "Door/Window sensor", "Description": "Dedicated door/window opening security sensor"},
+  "hiveot:thing:actuator:switch": {"Symbol": "", "Title": "Switch", "Description": "An electric powered on/off switch for powering circuits"},
+  "hiveot:thing:appliance:dryer": {"Symbol": "", "Title": "Dryer", "Description": "Clothing dryer"},
+  "hiveot:thing:appliance:fridge": {"Symbol": "", "Title": "Fridge", "Description": "Refrigerator appliance"},
+  "hiveot:thing:net:gateway:insteon": {"Symbol": "", "Title": "Insteon gateway", "Description": "Gateway providing access to Insteon devices"},
+  "hiveot:thing:sensor:multi": {"Symbol": "", "Title": "Multi sensor", "Description": "Sense multiple inputs"},
+  "hiveot:thing:computer:satphone": {"Symbol": "", "Title": "Satellite phone", "Description": ""},
   "hiveot:thing:media:player": {"Symbol": "", "Title": "Media player", "Description": "CD/DVD/Blueray/USB player of recorded media"},
-  "hiveot:thing:meter:water:consumption": {"Symbol": "", "Title": "Water consumption meter", "Description": "Water consumption meter"},
-  "hiveot:thing:net:router": {"Symbol": "", "Title": "Network router", "Description": "IP ThingNetwork router providing access to other IP networks"},
-  "hiveot:thing:net:wifi:ap": {"Symbol": "", "Title": "Wifi access point", "Description": "Wireless access point for IP networks"},
+  "hiveot:thing:meter:electric:power": {"Symbol": "", "Title": "Electrical Power", "Description": "Electrical power meter"},
+  "hiveot:thing:meter:water": {"Symbol": "", "Title": "Water metering device", "Description": "General water metering device"},
   "hiveot:thing:sensor": {"Symbol": "", "Title": "Sensor", "Description": "Generic sensor device"},
-  "hiveot:thing:sensor:security:glass": {"Symbol": "", "Title": "Glass sensor", "Description": "Dedicated sensor for detecting breaking of glass"},
-  "hiveot:thing:actuator:output": {"Symbol": "", "Title": "Output", "Description": "General purpose electrical output signal"},
-  "hiveot:thing:control:switch": {"Symbol": "", "Title": "Input switch", "Description": "On or off switch input control"},
+  "hiveot:thing:computer:voipphone": {"Symbol": "", "Title": "VoIP Phone", "Description": "Voice over IP phone"},
   "hiveot:thing:net:gateway:zigbee": {"Symbol": "", "Title": "Zigbee gateway", "Description": "Gateway providing access to Zigbee devices"},
-  "hiveot:thing:net:lora:p2p": {"Symbol": "", "Title": "LoRa P2P", "Description": "LoRa Peer-to-peer network device"},
-  "hiveot:thing:sensor:thermometer": {"Symbol": "", "Title": "Thermometer", "Description": "Environmental thermometer"},
+  "hiveot:thing:sensor:input": {"Symbol": "", "Title": "Input sensor", "Description": "General purpose electrical input sensor"},
   "hiveot:thing:actuator:alarm": {"Symbol": "", "Title": "Alarm", "Description": "Siren or light alarm"},
-  "hiveot:thing:control:keypad": {"Symbol": "", "Title": "Keypad", "Description": "Multi-key pad for command input"},
-  "hiveot:thing:net:lora": {"Symbol": "", "Title": "LoRa network device", "Description": "Generic Long Range network protocol device"},
-  "hiveot:thing:sensor:multi": {"Symbol": "", "Title": "Multi sensor", "Description": "Sense multiple inputs"},
-  "hiveot:thing:sensor:security:doorwindow": {"Symbol": "", "Title": "Door/Window sensor", "Description": "Dedicated door/window opening security sensor"},
+  "hiveot:thing:actuator:beacon": {"Symbol": "", "Title": "Beacon", "Description": "Location beacon"},
+  "hiveot:thing:actuator:lock": {"Symbol": "", "Title": "Lock", "Description": "Electronic door lock"},
   "hiveot:thing:actuator:valve": {"Symbol": "", "Title": "Valve", "Description": "Electric powered valve for fluids or gas"},
-  "hiveot:thing:appliance:freezer": {"Symbol": "", "Title": "Freezer", "Description": "Refrigerator freezer"},
+  "hiveot:thing:actuator:valve:water": {"Symbol": "", "Title": "Water valve", "Description": "Electric powered water valve"},
+  "hiveot:thing:net:lora": {"Symbol": "", "Title": "LoRa network device", "Description": "Generic Long Range network protocol device"},
+  "hiveot:thing:sensor:security:motion": {"Symbol": "", "Title": "Motion sensor", "Description": "Dedicated security sensor detecting motion"},
+  "hiveot:thing:sensor:sound": {"Symbol": "", "Title": "Sound detector", "Description": ""},
+  "hiveot:thing:actuator:valve:fuel": {"Symbol": "", "Title": "Fuel valve", "Description": "Electric powered fuel valve"},
   "hiveot:thing:computer": {"Symbol": "", "Title": "Computing Device", "Description": "General purpose computing device"},
+  "hiveot:thing:control:keypad": {"Symbol": "", "Title": "Keypad", "Description": "Multi-key pad for command input"},
+  "hiveot:thing:media:camera": {"Symbol": "", "Title": "Camera", "Description": "Video camera"},
+  "hiveot:thing:net:gateway:coap": {"Symbol": "", "Title": "CoAP gateway", "Description": "Gateway providing access to CoAP devices"},
+  "hiveot:thing:sensor:smoke": {"Symbol": "", "Title": "Smoke detector", "Description": ""},
+  "hiveot:thing:sensor:water:leak": {"Symbol": "", "Title": "Water leak detector", "Description": "Dedicated water leak detector"},
+  "hiveot:thing:appliance:freezer": {"Symbol": "", "Title": "Freezer", "Description": "Refrigerator freezer"},
   "hiveot:thing:control:irrigation": {"Symbol": "", "Title": "Irrigation control", "Description": "Device for control of an irrigation system"},
+  "hiveot:thing:control:pool": {"Symbol": "", "Title": "Pool control", "Description": "Device for controlling pool settings"},
+  "hiveot:thing:device:time": {"Symbol": "", "Title": "Clock", "Description": "Time tracking device such as clocks and time chips"},
   "hiveot:thing:meter:electric:energy": {"Symbol": "", "Title": "Electric energy", "Description": "Electrical energy meter"},
-  "hiveot:thing:actuator:motor": {"Symbol": "", "Title": "Motor", "Description": "Motor driven actuator, such as garage door, blinds, tv lifts"},
-  "hiveot:thing:computer:cellphone": {"Symbol": "", "Title": "Cell Phone", "Description": "Cellular phone"},
-  "hiveot:thing:control:toggle": {"Symbol": "", "Title": "Toggle switch", "Description": "Toggle switch input control"},
-  "hiveot:thing:meter:fuel:flow": {"Symbol": "", "Title": "Fuel flow rate", "Description": "Dedicated fuel flow rate metering device"},
-  "hiveot:thing:meter:water:level": {"Symbol": "", "Title": "Water level", "Description": "Dedicated water level meter"},
-  "hiveot:thing:meter:wind": {"Symbol": "", "Title": "Wind", "Description": "Dedicated wind meter"},
-  "hiveot:thing:appliance:dishwasher": {"Symbol": "", "Title": "Dishwasher", "Description": "Dishwasher"},
   "hiveot:thing:device": {"Symbol": "", "Title": "Device", "Description": "Device of unknown purpose"},
-  "hiveot:thing:device:time": {"Symbol": "", "Title": "Clock", "Description": "Time tracking device such as clocks and time chips"},
-  "hiveot:thing:meter:electric:current": {"Symbol": "", "Title": "Electric current", "Description": "Electrical current meter"},
-  "hiveot:thing:meter:electric:voltage": {"Symbol": "", "Title": "Voltage", "Description": "Electrical voltage meter"},
-  "hiveot:thing:net": {"Symbol": "", "Title": "Network device", "Description": "Generic network device"},
-  "hiveot:thing:net:wifi": {"Symbol": "", "Title": "Wifi device", "Description": "Generic wifi device"},
-  "hiveot:thing:actuator:switch": {"Symbol": "", "Title": "Switch", "Description": "An electric powered on/off switch for powering circuits"},
-  "hiveot:thing:control:pool": {"Symbol": "", "Title": "Pool control", "Description": "Device for controlling pool settings"},
-  "hiveot:thing:meter:water": {"Symbol": "", "Title": "Water metering device", "Description": "General water metering device"},
-  "hiveot:thing:service": {"Symbol": "", "Title": "Service", "Description": "General service for processing data and offering features of interest"},
+  "hiveot:thing:net:switch": {"Symbol": "", "Title": "Network switch", "Description": "Network switch to connect computer devices to the network"},
+  "hiveot:thing:net:wifi:ap": {"Symbol": "", "Title": "Wifi access point", "Description": "Wireless access point for IP networks"},
+  "hiveot:thing:meter:electric": {"Symbol": "", "Title": "", "Description": ""},
+  "hiveot:thing:meter:fuel:level": {"Symbol": "", "Title": "Fuel level", "Description": "Dedicated fuel level metering device"},
+  "hiveot:thing:meter:water:flow": {"Symbol": "", "Title": "Water flow", "Description": "Dedicated water flow-rate meter"},
+  "hiveot:thing:actuator": {"Symbol": "", "Title": "Actuator", "Description": "Generic actuator"},
   "hiveot:thing:actuator:light": {"Symbol": "", "Title": "Light", "Description": "Smart LED or other light"},
-  "hiveot:thing:appliance": {"Symbol": "", "Title": "Appliance", "Description": "Appliance to accomplish a particular task for occupant use"},
-  "hiveot:thing:computer:voipphone": {"Symbol": "", "Title": "VoIP Phone", "Description": "Voice over IP phone"},
-  "hiveot:thing:media:microphone": {"Symbol": "", "Title": "Microphone", "Description": "Microphone for capturing audio"},
-  "hiveot:thing:net:bluetooth": {"Symbol": "", "Title": "Bluetooth", "Description": "Bluetooth radio"},
-  "hiveot:thing:sensor:input": {"Symbol": "", "Title": "Input sensor", "Description": "General purpose electrical input sensor"},
+  "hiveot:thing:actuator:ranged": {"Symbol": "", "Title": "Ranged actuator", "Description": "Generic ranged actuator with a set point"},
+  "hiveot:thing:computer:tablet": {"Symbol": "", "Title": "Tablet", "Description": "Tablet computer"},
+  "hiveot:thing:control:pushbutton": {"Symbol": "", "Title": "Momentary switch", "Description": "Momentary push button control input"},
+  "hiveot:thing:meter:wind": {"Symbol": "", "Title": "Wind", "Description": "Dedicated wind meter"},
+  "hiveot:thing:sensor:environment": {"Symbol": "", "Title": "Environmental sensor", "Description": "Environmental sensor with one or more features such as temperature, humidity, etc"},
+  "hiveot:thing:service": {"Symbol": "", "Title": "Service", "Description": "General service for processing data and offering features of interest"},
+  "hiveot:thing:computer:pc": {"Symbol": "", "Title": "PC/Laptop", "Description": "Personal computer/laptop"},
+  "hiveot:thing:control:switch": {"Symbol": "", "Title": "Input switch", "Description": "On or off switch input control"},
+  "hiveot:thing:control:thermostat": {"Symbol": "", "Title": "Thermostat", "Description": "Thermostat HVAC control"},
+  "hiveot:thing:meter": {"Symbol": "", "Title": "Meter", "Description": "General metering device"},
+  "hiveot:thing:device:indicator": {"Symbol": "", "Title": "Indicator", "Description": "Visual or audio indicator device"},
+  "hiveot:thing:net:lora:gw": {"Symbol": "", "Title": "LoRaWAN gateway", "Description": "Gateway providing access to LoRa devices"},
+  "hiveot:thing:actuator:dimmer": {"Symbol": "", "Title": "Dimmer", "Description": "Light dimmer"},
   "hiveot:thing:actuator:relay": {"Symbol": "", "Title": "Relay", "Description": "Generic relay electrical switch"},
-  "hiveot:thing:appliance:fridge": {"Symbol": "", "Title": "Fridge", "Description": "Refrigerator appliance"},
-  "hiveot:thing:media:tv": {"Symbol": "", "Title": "TV", "Description": "Network connected television"},
   "hiveot:thing:computer:memory": {"Symbol": "", "Title": "Memory", "Description": "Stand-alone memory device such as eeprom or iButtons"},
   "hiveot:thing:computer:potsphone": {"Symbol": "", "Title": "Land Line", "Description": "Plain Old Telephone System, aka landline"},
-  "hiveot:thing:computer:tablet": {"Symbol": "", "Title": "Tablet", "Description": "Tablet computer"},
-  "hiveot:thing:net:lora:gw": {"Symbol": "", "Title": "LoRaWAN gateway", "Description": "Gateway providing access to LoRa devices"},
-  "hiveot:thing:control": {"Symbol": "", "Title": "Input controller", "Description": "Generic input controller"},
   "hiveot:thing:control:dimmer": {"Symbol": "", "Title": "Dimmer", "Description": "Light dimmer input device"},
-  "hiveot:thing:device:battery:monitor": {"Symbol": "", "Title": "Battery Monitor", "Description": "Battery monitor and charge controller"},
-  "hiveot:thing:actuator:ranged": {"Symbol": "", "Title": "Ranged actuator", "Description": "Generic ranged actuator with a set point"},
-  "hiveot:thing:actuator:valve:fuel": {"Symbol": "", "Title": "Fuel valve", "Description": "Electric powered fuel valve"},
-  "hiveot:thing:appliance:dryer": {"Symbol": "", "Title": "Dryer", "Description": "Clothing dryer"},
-  "hiveot:thing:computer:satphone": {"Symbol": "", "Title": "Satellite phone", "Description": ""},
-  "hiveot:thing:meter": {"Symbol": "", "Title": "Meter", "Description": "General metering device"},
-  "hiveot:thing:meter:fuel:level": {"Symbol": "", "Title": "Fuel level", "Description": "Dedicated fuel level metering device"},
-  "hiveot:thing:net:gateway:insteon": {"Symbol": "", "Title": "Insteon gateway", "Description": "Gateway providing access to Insteon devices"},
-  "hiveot:thing:actuator:beacon": {"Symbol": "", "Title": "Beacon", "Description": "Location beacon"},
+  "hiveot:thing:media:tv": {"Symbol": "", "Title": "TV", "Description": "Network connected television"},
+  "hiveot:thing:meter:fuel": {"Symbol": "", "Title": "Fuel metering device", "Description": "General fuel metering device"},
+  "hiveot:thing:meter:fuel:flow": {"Symbol": "", "Title": "Fuel flow rate", "Description": "Dedicated fuel flow rate metering device"},
+  "hiveot:thing:actuator:output": {"Symbol": "", "Title": "Output", "Description": "General purpose electrical output signal"},
+  "hiveot:thing:appliance:dishwasher": {"Symbol": "", "Title": "Dishwasher", "Description": "Dishwasher"},
   "hiveot:thing:control:climate": {"Symbol": "", "Title": "Climate control", "Description": "Device for controlling climate of a space"},
-  "hiveot:thing:control:pushbutton": {"Symbol": "", "Title": "Momentary switch", "Description": "Momentary push button control input"},
-  "hiveot:thing:device:indicator": {"Symbol": "", "Title": "Indicator", "Description": "Visual or audio indicator device"},
-  "hiveot:thing:media:radio": {"Symbol": "", "Title": "Radio", "Description": "AM or FM radio receiver"},
-  "hiveot:thing:meter:water:flow": {"Symbol": "", "Title": "Water flow", "Description": "Dedicated water flow-rate meter"},
+  "hiveot:thing:media:amplifier": {"Symbol": "", "Title": "Audio amplifier", "Description": "Audio amplifier with volume controls"},
+  "hiveot:thing:media:receiver": {"Symbol": "", "Title": "Receiver", "Description": "Audio/video receiver and player"},
+  "hiveot:thing:net:wifi": {"Symbol": "", "Title": "Wifi device", "Description": "Generic wifi device"},
+  "hiveot:thing:control:joystick": {"Symbol": "", "Title": "Joystick", "Description": "Flight control stick"},
+  "hiveot:thing:media:speaker": {"Symbol": "", "Title": "Connected speakers", "Description": "Network connected speakers"},
+  "hiveot:thing:meter:electric:voltage": {"Symbol": "", "Title": "Voltage", "Description": "Electrical voltage meter"},
+  "hiveot:thing:net:lora:p2p": {"Symbol": "", "Title": "LoRa P2P", "Description": "LoRa Peer-to-peer network device"},
+  "hiveot:thing:sensor:security:glass": {"Symbol": "", "Title": "Glass sensor", "Description": "Dedicated sensor for detecting breaking of glass"},
   "hiveot:thing:net:gateway": {"Symbol": "", "Title": "Gateway", "Description": "Generic gateway device providing access to other devices"},
-  "hiveot:thing:net:switch": {"Symbol": "", "Title": "Network switch", "Description": "Network switch to connect computer devices to the network"},
-  "hiveot:thing:sensor:security": {"Symbol": "", "Title": "Security", "Description": "Generic security sensor"},
-  "hiveot:thing:sensor:security:motion": {"Symbol": "", "Title": "Motion sensor", "Description": "Dedicated security sensor detecting motion"},
-  "hiveot:thing:sensor:sound": {"Symbol": "", "Title": "Sound detector", "Description": ""},
+  "hiveot:thing:net:gateway:zwave": {"Symbol": "", "Title": "ZWave gateway", "Description": "Gateway providing access to ZWave devices"},
+  "hiveot:thing:actuator:motor": {"Symbol": "", "Title": "Motor", "Description": "Motor driven actuator, such as garage door, blinds, tv lifts"},
   "hiveot:thing:appliance:washer": {"Symbol": "", "Title": "Washer", "Description": "Clothing washer"},
   "hiveot:thing:computer:embedded": {"Symbol": "", "Title": "Embedded System", "Description": "Embedded computing device"},
-  "hiveot:thing:media:receiver": {"Symbol": "", "Title": "Receiver", "Description": "Audio/video receiver and player"},
-  "hiveot:thing:media:speaker": {"Symbol": "", "Title": "Connected speakers", "Description": "Network connected speakers"},
-  "hiveot:thing:meter:electric": {"Symbol": "", "Title": "", "Description": ""},
-  "hiveot:thing:meter:electric:power": {"Symbol": "", "Title": "Electrical Power", "Description": "Electrical power meter"},
-  "hiveot:thing:sensor:environment": {"Symbol": "", "Title": "Environmental sensor", "Description": "Environmental sensor with one or more features such as temperature, humidity, etc"},
-  "hiveot:thing:sensor:scale": {"Symbol": "", "Title": "Scale", "Description": "Electronic weigh scale"},
+  "hiveot:thing:meter:water:level": {"Symbol": "", "Title": "Water level", "Description": "Dedicated water level meter"},
+  "hiveot:thing:net": {"Symbol": "", "Title": "Network device", "Description": "Generic network device"},
+  "hiveot:thing:control": {"Symbol": "", "Title": "Input controller", "Description": "Generic input controller"},
+  "hiveot:thing:media:microphone": {"Symbol": "", "Title": "Microphone", "Description": "Microphone for capturing audio"},
+  "hiveot:thing:meter:electric:current": {"Symbol": "", "Title": "Electric current", "Description": "Electrical current meter"},
+  "hiveot:thing:net:router": {"Symbol": "", "Title": "Network router", "Description": "IP ThingNetwork router providing access to other IP networks"},
+  "hiveot:thing:sensor:thermometer": {"Symbol": "", "Title": "Thermometer", "Description": "Environmental thermometer"},
+  "hiveot:thing:control:toggle": {"Symbol": "", "Title": "Toggle switch", "Description": "Toggle switch input control"},
+  "hiveot:thing:media": {"Symbol": "", "Title": "A/V media", "Description": "Generic device for audio/video media record or playback"},
+  "hiveot:thing:media:radio": {"Symbol": "", "Title": "Radio", "Description": "AM or FM radio receiver"},
+  "hiveot:thing:net:bluetooth": {"Symbol": "", "Title": "Bluetooth", "Description": "Bluetooth radio"},
+  "hiveot:thing:device:battery:monitor": {"Symbol": "", "Title": "Battery Monitor", "Description": "Battery monitor and charge controller"},
 }
 
 
 # type: UnitClasses
 # version: 0.1
-# generated: 29 Dec 24 17:28 PST
+# generated: 31 Dec 24 22:27 PST
 # source: github.com/hiveot/hub/api/vocab/ht-unit-classes.yaml
 # namespace: ht
 UnitAmpere = "hiveot:unit:ampere"
@@ -576,35 +518,93 @@
 
 # UnitClassesMap maps @type to symbol, title and description
 UnitClassesMap = {
+  "hiveot:unit:second": {"Symbol": "s", "Title": "Second", "Description": "SI unit of time based on caesium frequency"},
+  "hiveot:unit:fahrenheit": {"Symbol": "F", "Title": "Fahrenheit", "Description": "Temperature in Fahrenheit"},
+  "hiveot:unit:gallon": {"Symbol": "gl", "Title": "Gallon", "Description": "Unit of volume. 1 Imperial gallon is 4.54609 liters. 1 US liquid gallon is 3.78541 liters. 1 US dry gallon is 4.405 liters. "},
+  "hiveot:unit:degree": {"Symbol": "degree", "Title": "Degree", "Description": "Angle in 0-360 degrees"},
   "hiveot:unit:kelvin": {"Symbol": "K", "Title": "Kelvin", "Description": "SI unit of thermodynamic temperature. 0 K represents absolute zero, the absence of all heat. 0 C equals +273.15K"},
-  "hiveot:unit:millibar": {"Symbol": "mbar", "Title": "millibar", "Description": "Metric unit of pressure. 1/1000th of a bar. Equal to 100 pascals. Amount of force it takes to move an object weighing a gram, one centimeter in one second."},
-  "hiveot:unit:pound": {"Symbol": "lbs", "Title": "Pound", "Description": "Imperial unit of weight. Equivalent to 0.453592 Kg. 1 Kg is 2.205 lbs"},
-  "hiveot:unit:liter": {"Symbol": "l", "Title": "Liter", "Description": "SI unit of volume equivalent to 1 cubic decimeter."},
-  "hiveot:unit:meter": {"Symbol": "m", "Title": "Meter", "Description": "Distance in meters. 1m=c/299792458"},
-  "hiveot:unit:meterspersecond": {"Symbol": "m/s", "Title": "Meters per second", "Description": "SI unit of speed in meters per second"},
+  "hiveot:unit:ppm": {"Symbol": "ppm", "Title": "PPM", "Description": "Parts per million"},
   "hiveot:unit:candela": {"Symbol": "cd", "Title": "Candela", "Description": "SI unit of luminous intensity in a given direction. Roughly the same brightness as the common candle."},
-  "hiveot:unit:degree": {"Symbol": "degree", "Title": "Degree", "Description": "Angle in 0-360 degrees"},
+  "hiveot:unit:kph": {"Symbol": "kph", "Title": "Km per hour", "Description": "Speed in kilometers per hour"},
   "hiveot:unit:kilowatthour": {"Symbol": "kWh", "Title": "Kilowatt-hour", "Description": "non-SI unit of energy equivalent to 3.6 megajoules."},
-  "hiveot:unit:fahrenheit": {"Symbol": "F", "Title": "Fahrenheit", "Description": "Temperature in Fahrenheit"},
+  "hiveot:unit:lux": {"Symbol": "lx", "Title": "Lux", "Description": "SI unit illuminance. Equal to 1 lumen per square meter."},
+  "hiveot:unit:pascal": {"Symbol": "Pa", "Title": "Pascal", "Description": "SI unit of pressure. Equal to 1 newton of force applied over 1 square meter."},
+  "hiveot:unit:pound": {"Symbol": "lbs", "Title": "Pound", "Description": "Imperial unit of weight. Equivalent to 0.453592 Kg. 1 Kg is 2.205 lbs"},
+  "hiveot:unit:ampere": {"Symbol": "A", "Title": "Ampere", "Description": "Electrical current in Amperes based on the elementary charge flow per second"},
   "hiveot:unit:radian": {"Symbol": "", "Title": "Radian", "Description": "Angle in 0-2pi"},
   "hiveot:unit:volt": {"Symbol": "V", "Title": "Volt", "Description": "SI unit of electric potential; Energy consumption of 1 joule per electric charge of one coulomb"},
-  "hiveot:unit:mole": {"Symbol": "mol", "Title": "Mole", "Description": "SI unit of measurement for amount of substance. Eg, molecules."},
-  "hiveot:unit:ampere": {"Symbol": "A", "Title": "Ampere", "Description": "Electrical current in Amperes based on the elementary charge flow per second"},
-  "hiveot:unit:gallon": {"Symbol": "gl", "Title": "Gallon", "Description": "Unit of volume. 1 Imperial gallon is 4.54609 liters. 1 US liquid gallon is 3.78541 liters. 1 US dry gallon is 4.405 liters. "},
+  "hiveot:unit:meter": {"Symbol": "m", "Title": "Meter", "Description": "Distance in meters. 1m=c/299792458"},
   "hiveot:unit:kilogram": {"Symbol": "kg", "Title": "Kilogram", "Description": ""},
+  "hiveot:unit:mercury": {"Symbol": "Hg", "Title": "Mercury", "Description": "Unit of atmospheric pressure in the United States. 1 Hg equals 33.8639 mbar."},
+  "hiveot:unit:meterspersecond": {"Symbol": "m/s", "Title": "Meters per second", "Description": "SI unit of speed in meters per second"},
+  "hiveot:unit:millibar": {"Symbol": "mbar", "Title": "millibar", "Description": "Metric unit of pressure. 1/1000th of a bar. Equal to 100 pascals. Amount of force it takes to move an object weighing a gram, one centimeter in one second."},
+  "hiveot:unit:millisecond": {"Symbol": "ms", "Title": "millisecond", "Description": "Unit of time in milli-seconds. Equal to 1/1000 of a second."},
   "hiveot:unit:watt": {"Symbol": "W", "Title": "Watt", "Description": "SI unit of power. Equal to 1 joule per second; or work performed when a current of 1 ampere flows across an electric potential of one volt."},
-  "hiveot:unit:foot": {"Symbol": "ft", "Title": "Foot", "Description": "Imperial unit of distance. 1 foot equals 0.3048 meters"},
+  "hiveot:unit:celcius": {"Symbol": "°C", "Title": "Celcius", "Description": "Temperature in Celcius"},
+  "hiveot:unit:liter": {"Symbol": "l", "Title": "Liter", "Description": "SI unit of volume equivalent to 1 cubic decimeter."},
   "hiveot:unit:milesperhour": {"Symbol": "mph", "Title": "Miles per hour", "Description": "Speed in miles per hour"},
-  "hiveot:unit:ppm": {"Symbol": "ppm", "Title": "PPM", "Description": "Parts per million"},
-  "hiveot:unit:lux": {"Symbol": "lx", "Title": "Lux", "Description": "SI unit illuminance. Equal to 1 lumen per square meter."},
-  "hiveot:unit:mercury": {"Symbol": "Hg", "Title": "Mercury", "Description": "Unit of atmospheric pressure in the United States. 1 Hg equals 33.8639 mbar."},
-  "hiveot:unit:pascal": {"Symbol": "Pa", "Title": "Pascal", "Description": "SI unit of pressure. Equal to 1 newton of force applied over 1 square meter."},
   "hiveot:unit:percent": {"Symbol": "%", "Title": "Percent", "Description": "Fractions of 100"},
   "hiveot:unit:psi": {"Symbol": "PSI", "Title": "PSI", "Description": "Unit of pressure. Pounds of force per square inch. 1PSI equals 6984 Pascals."},
-  "hiveot:unit:celcius": {"Symbol": "°C", "Title": "Celcius", "Description": "Temperature in Celcius"},
   "hiveot:unit:count": {"Symbol": "(N)", "Title": "Count", "Description": ""},
   "hiveot:unit:lumen": {"Symbol": "lm", "Title": "Lumen", "Description": "SI unit luminous flux. Measure of perceived power of visible light. 1lm = 1 cd steradian"},
-  "hiveot:unit:kph": {"Symbol": "kph", "Title": "Km per hour", "Description": "Speed in kilometers per hour"},
-  "hiveot:unit:millisecond": {"Symbol": "ms", "Title": "millisecond", "Description": "Unit of time in milli-seconds. Equal to 1/1000 of a second."},
-  "hiveot:unit:second": {"Symbol": "s", "Title": "Second", "Description": "SI unit of time based on caesium frequency"},
+  "hiveot:unit:mole": {"Symbol": "mol", "Title": "Mole", "Description": "SI unit of measurement for amount of substance. Eg, molecules."},
+  "hiveot:unit:foot": {"Symbol": "ft", "Title": "Foot", "Description": "Imperial unit of distance. 1 foot equals 0.3048 meters"},
+}
+
+
+# type: ActionClasses
+# version: 0.1
+# generated: 31 Dec 24 22:27 PST
+# source: github.com/hiveot/hub/api/vocab/ht-action-classes.yaml
+# namespace: ht
+ActionDimmer = "hiveot:action:dimmer"
+ActionDimmerDecrement = "hiveot:action:dimmer:decrement"
+ActionDimmerIncrement = "hiveot:action:dimmer:increment"
+ActionDimmerSet = "hiveot:action:dimmer:set"
+ActionMedia = "hiveot:action:media"
+ActionMediaMute = "hiveot:action:media:mute"
+ActionMediaNext = "hiveot:action:media:next"
+ActionMediaPause = "hiveot:action:media:pause"
+ActionMediaPlay = "hiveot:action:media:play"
+ActionMediaPrevious = "hiveot:action:media:previous"
+ActionMediaUnmute = "hiveot:action:media:unmute"
+ActionMediaVolume = "hiveot:action:media:volume"
+ActionMediaVolumeDecrease = "hiveot:action:media:volume:decrease"
+ActionMediaVolumeIncrease = "hiveot:action:media:volume:increase"
+ActionSwitch = "hiveot:action:switch"
+ActionSwitchOnOff = "hiveot:action:switch:onoff"
+ActionSwitchToggle = "hiveot:action:switch:toggle"
+ActionThingDisable = "hiveot:action:thing:disable"
+ActionThingEnable = "hiveot:action:thing:enable"
+ActionThingStart = "hiveot:action:thing:start"
+ActionThingStop = "hiveot:action:thing:stop"
+ActionValveClose = "hiveot:action:valve:close"
+ActionValveOpen = "hiveot:action:valve:open"
+# end of ActionClasses
+
+# ActionClassesMap maps @type to symbol, title and description
+ActionClassesMap = {
+  "hiveot:action:media": {"Symbol": "", "Title": "Media control", "Description": "Commands to control media recording and playback"},
+  "hiveot:action:media:play": {"Symbol": "", "Title": "Play", "Description": "Start or continue playback"},
+  "hiveot:action:thing:start": {"Symbol": "", "Title": "Start", "Description": "Start running a task"},
+  "hiveot:action:valve:close": {"Symbol": "", "Title": "Close valve", "Description": "Action to close the valve"},
+  "hiveot:action:media:pause": {"Symbol": "", "Title": "Pause", "Description": "Pause playback"},
+  "hiveot:action:media:previous": {"Symbol": "", "Title": "Previous", "Description": "Previous track or station"},
+  "hiveot:action:dimmer:set": {"Symbol": "", "Title": "Set dimmer", "Description": "Action to set the dimmer value"},
+  "hiveot:action:switch": {"Symbol": "", "Title": "Switch", "Description": "General switch action"},
+  "hiveot:action:switch:onoff": {"Symbol": "", "Title": "Set On/Off switch", "Description": "Action to set the switch on/off state"},
+  "hiveot:action:thing:disable": {"Symbol": "", "Title": "Disable", "Description": "Action to disable a thing"},
+  "hiveot:action:thing:stop": {"Symbol": "", "Title": "Stop", "Description": "Stop a running task"},
+  "hiveot:action:media:volume": {"Symbol": "", "Title": "Volume", "Description": "Set volume level"},
+  "hiveot:action:dimmer": {"Symbol": "", "Title": "Dimmer", "Description": "General dimmer action"},
+  "hiveot:action:dimmer:decrement": {"Symbol": "", "Title": "Lower dimmer", "Description": ""},
+  "hiveot:action:thing:enable": {"Symbol": "", "Title": "Enable", "Description": "Action to enable a thing"},
+  "hiveot:action:valve:open": {"Symbol": "", "Title": "Open valve", "Description": "Action to open the valve"},
+  "hiveot:action:media:mute": {"Symbol": "", "Title": "Mute", "Description": "Mute audio"},
+  "hiveot:action:media:next": {"Symbol": "", "Title": "Next", "Description": "Next track or station"},
+  "hiveot:action:media:unmute": {"Symbol": "", "Title": "Unmute", "Description": "Unmute audio"},
+  "hiveot:action:media:volume:increase": {"Symbol": "", "Title": "Increase volume", "Description": "Increase volume"},
+  "hiveot:action:media:volume:decrease": {"Symbol": "", "Title": "Decrease volume", "Description": "Decrease volume"},
+  "hiveot:action:dimmer:increment": {"Symbol": "", "Title": "Increase dimmer", "Description": ""},
+  "hiveot:action:switch:toggle": {"Symbol": "", "Title": "Toggle switch", "Description": "Action to toggle the switch"},
 }
diff --git a/runtime/RuntimeDirectory_test.go b/runtime/RuntimeDirectory_test.go
index 034be0a6..ebe72a19 100644
--- a/runtime/RuntimeDirectory_test.go
+++ b/runtime/RuntimeDirectory_test.go
@@ -139,7 +139,7 @@ func TestReadTDsRest(t *testing.T) {
 	ts.AddTDs(agentID, 100)
 
 	serverURL := ts.GetServerURL(authn.ClientTypeConsumer)
-	cl2 := tlsclient.NewTLSClient(serverURL, nil, ts.Certs.CaCert, time.Second*30, "")
+	cl2 := tlsclient.NewTLSClient(serverURL, nil, ts.Certs.CaCert, time.Second*30)
 	cl2.SetAuthToken(token)
 
 	tdJSONList, err := digitwin.DirectoryReadAllTDs(cl, 100, 0)
diff --git a/runtime/api/ValueListToMap.go b/runtime/api/ValueListToMap.go
index 318972e4..58dd0b3c 100644
--- a/runtime/api/ValueListToMap.go
+++ b/runtime/api/ValueListToMap.go
@@ -1,6 +1,8 @@
 package api
 
-import "github.com/hiveot/hub/api/go/digitwin"
+import (
+	"github.com/hiveot/hub/api/go/digitwin"
+)
 
 // ActionListToMap creates a map from a digitwin action value list
 func ActionListToMap(valueList []digitwin.ActionStatus) map[string]digitwin.ActionStatus {
diff --git a/runtime/digitwin/router/NotificationFlow.go b/runtime/digitwin/router/NotificationFlow.go
index 956cb465..b5bd1975 100644
--- a/runtime/digitwin/router/NotificationFlow.go
+++ b/runtime/digitwin/router/NotificationFlow.go
@@ -3,6 +3,7 @@ package router
 
 import (
 	"fmt"
+	"github.com/hiveot/hub/api/go/digitwin"
 	"github.com/hiveot/hub/transports"
 	"github.com/hiveot/hub/transports/tputils"
 	"github.com/hiveot/hub/wot"
@@ -18,16 +19,26 @@ func (svc *DigitwinRouter) HandleNotification(notif transports.NotificationMessa
 	notif.ThingID = dThingID
 
 	if notif.Operation == wot.HTOpEvent {
-
-		err := svc.dtwStore.UpdateEventValue(dThingID, notif.Name, notif.Data)
+		tv := digitwin.ThingValue{
+			Created: notif.Created,
+			Data:    notif.Data,
+			Name:    notif.Name,
+			ThingID: notif.ThingID,
+		}
+		err := svc.dtwStore.UpdateEventValue(tv)
 		if err == nil {
 			// broadcast the event to subscribers of the digital twin
 			go svc.cm.PublishNotification(notif)
 		}
 	} else if notif.Operation == wot.HTOpUpdateProperty {
 
-		changed, _ := svc.dtwStore.UpdatePropertyValue(
-			notif.ThingID, notif.Name, notif.Data, "")
+		tv := digitwin.ThingValue{
+			Created: notif.Created,
+			Data:    notif.Data,
+			Name:    notif.Name,
+			ThingID: notif.ThingID,
+		}
+		changed, _ := svc.dtwStore.UpdatePropertyValue(tv)
 		if changed {
 			svc.cm.PublishNotification(notif)
 		}
@@ -80,7 +91,7 @@ func (svc *DigitwinRouter) HandleUpdateMultipleProperties(notif transports.Notif
 		return
 	}
 	// update the property in the digitwin and notify observers for each change
-	changes, err := svc.dtwStore.UpdateProperties(notif.ThingID, propMap, "")
+	changes, err := svc.dtwStore.UpdateProperties(notif.ThingID, notif.Created, propMap)
 	if len(changes) > 0 {
 		for k, v := range changes {
 			notif := transports.NewNotificationMessage(wot.HTOpUpdateProperty, notif.ThingID, k, v)
diff --git a/runtime/digitwin/store/DigitwinStore.go b/runtime/digitwin/store/DigitwinStore.go
index b793d5c0..d2e90937 100644
--- a/runtime/digitwin/store/DigitwinStore.go
+++ b/runtime/digitwin/store/DigitwinStore.go
@@ -124,7 +124,7 @@ func (svc *DigitwinStore) QueryAllActions(dThingID string) (
 	return actMap, err
 }
 
-// ReadAllEvents returns all last known action invocation status of the given thing
+// ReadAllEvents returns all last received events of the given thing
 func (svc *DigitwinStore) ReadAllEvents(dThingID string) (
 	v map[string]digitwin.ThingValue, err error) {
 
@@ -476,77 +476,61 @@ func (svc *DigitwinStore) UpdateActionStatus(agentID string, resp transports.Res
 // This does accept event values that are not defined in the TD.
 // This is intentional.
 //
-// dThingID is the ID of the digital twin whose event is submitted.
-// data is the event payload
-// eventName is the name of the event whose value is updated.
-func (svc *DigitwinStore) UpdateEventValue(dThingID string, eventName string, data any) error {
+// ev is the received notification of the event update
+func (svc *DigitwinStore) UpdateEventValue(ev digitwin.ThingValue) error {
 	svc.cacheMux.Lock()
 	defer svc.cacheMux.Unlock()
 
-	dtw, found := svc.dtwCache[dThingID]
+	dtw, found := svc.dtwCache[ev.ThingID]
 	if !found {
-		err := fmt.Errorf("dThing with ID '%s' not found", dThingID)
-		slog.Warn("UpdateEventValue Can't update state of an unknown Thing. Event ignored.", "dThingID", dThingID)
+		err := fmt.Errorf("dThing with ID '%s' not found", ev.ThingID)
+		slog.Warn("UpdateEventValue Unknown Thing. Event ignored.", "dThingID", ev.ThingID)
 		return err
 	}
-	eventValue := digitwin.ThingValue{
-		Data:    data,
-		Updated: time.Now().Format(wot.RFC3339Milli),
-		//MessageID: messageID,
-		Name: eventName,
-	}
-	dtw.EventValues[eventName] = eventValue
-	svc.changedThings[dThingID] = true
+	dtw.EventValues[ev.Name] = ev
+	svc.changedThings[ev.ThingID] = true
 
 	return nil
 }
 
 // UpdatePropertyValue updates the last known thing property value.
 //
-// dThingID is the ID of the digital twin Thing
-// propName is the name of the property whose value is updated
 // newValue of the property
-// requestID provided by the agent, in response to an action or write
 //
 // This returns a flag indicating whether the property value has changed.
-func (svc *DigitwinStore) UpdatePropertyValue(
-	dThingID string, propName string, newValue any, requestID string) (
+func (svc *DigitwinStore) UpdatePropertyValue(newValue digitwin.ThingValue) (
 	hasChanged bool, err error) {
 
 	svc.cacheMux.Lock()
 	defer svc.cacheMux.Unlock()
 
-	dtw, found := svc.dtwCache[dThingID]
+	dtw, found := svc.dtwCache[newValue.ThingID]
 	if !found {
-		err := fmt.Errorf("dThing with ID '%s' not found", dThingID)
+		err := fmt.Errorf("dThing with ID '%s' not found", newValue.ThingID)
 		return false, err
 	}
 	if svc.strict {
-		aff := dtw.DtwTD.GetProperty(propName)
+		aff := dtw.DtwTD.GetProperty(newValue.Name)
 		if aff == nil {
 			return false,
-				fmt.Errorf("UpdatePropertyValue: unknown property '%s' for thing '%s'", propName, dThingID)
+				fmt.Errorf("UpdatePropertyValue: unknown property '%s' for thing '%s'",
+					newValue.Name, newValue.ThingID)
 		}
 	}
-	propValue, found := dtw.PropValues[propName]
+	propValue, found := dtw.PropValues[newValue.Name]
 	if !found {
-		propValue = digitwin.ThingValue{}
+		hasChanged = true
+	} else {
+		hasChanged = propValue.Data != newValue.Data
 	}
-	oldValue := propValue.Data
-	hasChanged = oldValue != propValue
-
-	propValue.Data = newValue
-	propValue.RequestID = requestID
-	propValue.Name = propName
-	propValue.Updated = time.Now().Format(wot.RFC3339Milli)
-
-	dtw.PropValues[propName] = propValue
-	svc.changedThings[dThingID] = hasChanged
+	dtw.PropValues[newValue.Name] = newValue
+	svc.changedThings[newValue.ThingID] = hasChanged
 
 	return hasChanged, nil
 }
 
-// UpdateProperties updates the last known thing property values.
+// UpdateProperties updates the last known thing property values with a new
+// property value notification.
 //
 // This will bulk update all properties in the map. They are stored separately.
 //
@@ -556,15 +540,23 @@ func (svc *DigitwinStore) UpdatePropertyValue(
 // requestID provided by the agent, in response to an action or write
 //
 // This returns a map with changed property values.
-func (svc *DigitwinStore) UpdateProperties(
-	dThingID string, propMap map[string]any, requestID string) (
+func (svc *DigitwinStore) UpdateProperties(dThingID string, created string, propMap map[string]any) (
 	changes map[string]any, err error) {
 
 	changes = make(map[string]any)
-	for propName, newValue := range propMap {
-		changed, _ := svc.UpdatePropertyValue(dThingID, propName, newValue, requestID)
+	for k, v := range propMap {
+		newValue := digitwin.ThingValue{
+			Created: created,
+			Data:    v,
+			Name:    k,
+			ThingID: dThingID,
+		}
+
+		//	wot.HTOpUpdateProperty, dThingID, k, v)
+		//}
+		changed, _ := svc.UpdatePropertyValue(newValue)
 		if changed {
-			changes[propName] = newValue
+			changes[k] = newValue
 		}
 	}
 	return changes, nil
@@ -575,23 +567,23 @@ func (svc *DigitwinStore) UpdateProperties(
 //
 //	dThingID is the digital twin ID
 //	tv is the new thing value of the property
-func (svc *DigitwinStore) WriteProperty(dThingID string, tv digitwin.ThingValue) error {
-	svc.cacheMux.Lock()
-	defer svc.cacheMux.Unlock()
-
-	dtw, found := svc.dtwCache[dThingID]
-	if !found {
-		err := fmt.Errorf("dThing with ID '%s' not found", dThingID)
-		return err
-	}
-	if tv.Updated == "" {
-		tv.Updated = time.Now().Format(wot.RFC3339Milli)
-	}
-	dtw.PropValues[tv.Name] = tv
-	svc.changedThings[dThingID] = true
-
-	return nil
-}
+//func (svc *DigitwinStore) WriteProperty(dThingID string, tv digitwin.ThingValue) error {
+//	svc.cacheMux.Lock()
+//	defer svc.cacheMux.Unlock()
+//
+//	dtw, found := svc.dtwCache[dThingID]
+//	if !found {
+//		err := fmt.Errorf("dThing with ID '%s' not found", dThingID)
+//		return err
+//	}
+//	if tv.Updated == "" {
+//		tv.Updated = time.Now().Format(wot.RFC3339Milli)
+//	}
+//	dtw.PropValues[tv.Name] = tv
+//	svc.changedThings[dThingID] = true
+//
+//	return nil
+//}
 
 // OpenDigitwinStore initializes the digitwin store using the given storage bucket.
 // This will load the digitwin directory into a memory cache.
diff --git a/runtime/digitwin/store/DigitwinStore_test.go b/runtime/digitwin/store/DigitwinStore_test.go
index a91e3141..aa108ae0 100644
--- a/runtime/digitwin/store/DigitwinStore_test.go
+++ b/runtime/digitwin/store/DigitwinStore_test.go
@@ -2,9 +2,11 @@ package store_test
 
 import (
 	"fmt"
+	"github.com/hiveot/hub/api/go/digitwin"
 	"github.com/hiveot/hub/lib/buckets/kvbtree"
 	"github.com/hiveot/hub/lib/logging"
 	"github.com/hiveot/hub/runtime/digitwin/store"
+	"github.com/hiveot/hub/wot"
 	"github.com/hiveot/hub/wot/td"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -67,7 +69,14 @@ func addValues(svc *store.DigitwinStore,
 		}
 
 		value := fmt.Sprintf("%2.3f", randomValue)
-		svc.UpdateEventValue(dThingID, valueNames[randomName], value)
+		name := valueNames[randomName]
+		tv := digitwin.ThingValue{
+			Created: time.Now().Format(wot.RFC3339Milli),
+			Data:    value,
+			Name:    name,
+			ThingID: dThingID,
+		}
+		_ = svc.UpdateEventValue(tv)
 	}
 }
 
@@ -171,7 +180,13 @@ func TestUpdateProps(t *testing.T) {
 	defer closeFn()
 	addValues(svc, 10, agent1ID, []string{thing1ID}, 3600*24*30)
 
-	changed, err := svc.UpdatePropertyValue(dThingID1, prop1Name, prop1Value, "")
+	tv := digitwin.ThingValue{
+		Created: time.Now().Format(wot.RFC3339Milli),
+		Data:    prop1Value,
+		Name:    prop1Name,
+		ThingID: dThingID1,
+	}
+	changed, err := svc.UpdatePropertyValue(tv)
 	require.NoError(t, err)
 	require.True(t, changed)
 
@@ -188,7 +203,14 @@ func TestAddPropsFail(t *testing.T) {
 	_ = svc
 	defer closeFn()
 
-	changed, err := svc.UpdatePropertyValue(dThingID, "prop1", "val1", "")
+	tv := digitwin.ThingValue{
+		Created: time.Now().Format(wot.RFC3339Milli),
+		Data:    "val1",
+		Name:    "prop1",
+		ThingID: dThingID,
+	}
+	changed, err := svc.UpdatePropertyValue(tv)
+
 	require.Error(t, err)
 	require.False(t, changed)
 }
diff --git a/runtime/digitwin/tdd/digitwinValues.json b/runtime/digitwin/tdd/digitwinValues.json
index 9b959269..345bc4c1 100644
--- a/runtime/digitwin/tdd/digitwinValues.json
+++ b/runtime/digitwin/tdd/digitwinValues.json
@@ -101,7 +101,13 @@
 			"title": "Thing Value",
 			"description": "Property or event value",
 			"type": "object",
+			"comment": "fixme: this has the same fields as a transports ThingValue",
 			"properties": {
+				"created": {
+					"title": "Updated time",
+					"description": "Time the value was last updated",
+					"type": "dateTime"
+				},
 				"data": {
 					"title": "Payload",
 					"description": "Data in format as described by the thing's property affordance",
@@ -112,19 +118,9 @@
 					"description":"Name of the property holding the value",
 					"type": "string"
 				},
-				"requestID": {
-					"title": "Message ID",
-					"description": "link to property write or action that caused the value to change",
-					"type": "string"
-				},
-				"updated": {
-					"title": "Updated time",
-					"description": "Time the value was last updated",
-					"type": "dateTime"
-				},
-				"senderID": {
-					"title": "Sender ID",
-					"description": "ID of the sender updating the value",
+				"thingID": {
+					"title": "Thing ID",
+					"description": "Digital twin Thing ID",
 					"type": "string"
 				}
 			}
diff --git a/services/hiveoview/src/constants.go b/services/hiveoview/src/constants.go
index fd92b048..fd7441bf 100644
--- a/services/hiveoview/src/constants.go
+++ b/services/hiveoview/src/constants.go
@@ -18,10 +18,11 @@ const (
 
 // Router paths
 const (
-	RenderAboutPath   = "/about"
-	RenderAppHeadPath = "/app/appHead"
-	RenderLoginPath   = "/login"
-	UIPostLoginPath   = "/login"
+	RenderAboutPath     = "/about"
+	RenderAppHeadPath   = "/app/appHead"
+	RenderLoginPath     = "/login"
+	UIPostLoginPath     = "/login"
+	UIPostFormLoginPath = "/loginForm"
 
 	// action paths
 	RenderActionRequestPath     = "/action/{thingID}/{name}/request"
diff --git a/services/hiveoview/src/service/CreateRoutes.go b/services/hiveoview/src/service/CreateRoutes.go
index fbe2fa29..c71a4cc9 100644
--- a/services/hiveoview/src/service/CreateRoutes.go
+++ b/services/hiveoview/src/service/CreateRoutes.go
@@ -62,8 +62,8 @@ func (svc *HiveovService) CreateRoutes(router *chi.Mux, rootPath string) http.Ha
 		r.Get("/static/*", staticFileServer.ServeHTTP)
 		r.Get("/webcomp/*", staticFileServer.ServeHTTP)
 		r.Get("/login", login.RenderLogin)
-		//r.Post("/login", login.PostLoginHandler(svc.sm))
-		r.Post(src.UIPostLoginPath, login.PostLoginFormHandler(svc.sm))
+		r.Post(src.UIPostLoginPath, login.PostLoginHandler(svc.sm))
+		r.Post(src.UIPostFormLoginPath, login.PostLoginFormHandler(svc.sm))
 		r.Get("/logout", session.SessionLogout)
 	})
 
diff --git a/services/hiveoview/src/session/SessionManager.go b/services/hiveoview/src/session/SessionManager.go
index e4ff44cf..9f6b14d3 100644
--- a/services/hiveoview/src/session/SessionManager.go
+++ b/services/hiveoview/src/session/SessionManager.go
@@ -180,7 +180,8 @@ func (sm *WebSessionManager) onClose(cs *WebClientSession) {
 // If successful this updates the secure cookie with a new auth token and also
 // returns this token.
 // If a cid is provided in the headers it will create a session using it.
-func (sm *WebSessionManager) ConnectWithPassword(w http.ResponseWriter, r *http.Request,
+func (sm *WebSessionManager) ConnectWithPassword(
+	w http.ResponseWriter, r *http.Request,
 	loginID string, password string, cid string) (newToken string, err error) {
 
 	hc, err := clients.NewConsumerClient(sm.hubURL, loginID, sm.caCert, nil, sm.timeout)
@@ -284,6 +285,7 @@ func (sm *WebSessionManager) GetSessionFromCookie(r *http.Request) (
 	// also check query parameters.
 	cid = r.Header.Get(httpserver.ConnectionIDHeader)
 	if cid == "" {
+		//slog.Error("GetSessionFromCookie: Missing CID")
 		cid = r.URL.Query().Get("cid")
 	}
 
diff --git a/services/hiveoview/src/views/app/app.go b/services/hiveoview/src/views/app/app.go
index 31d8e740..5e151f5d 100644
--- a/services/hiveoview/src/views/app/app.go
+++ b/services/hiveoview/src/views/app/app.go
@@ -34,6 +34,8 @@ func RenderAppPages(r *http.Request) (buff *bytes.Buffer, err error) {
 		cs := ctxClientSession.(*session.WebClientSession)
 		cid = cs.GetCID()
 	}
+	// This Cid field must match the one in app.gohtml hx-headers=...
+	// app.gohtml:6  sse-connect="/websse?cid={{.Cid}}"
 	data := map[string]string{"Cid": cid}
 	return views.TM.RenderFull(AppTemplate, data)
 }
diff --git a/services/hiveoview/src/views/login/PostLogin.go b/services/hiveoview/src/views/login/PostLogin.go
index 0fe16c77..fc4a5ca7 100644
--- a/services/hiveoview/src/views/login/PostLogin.go
+++ b/services/hiveoview/src/views/login/PostLogin.go
@@ -1,9 +1,13 @@
 package login
 
 import (
+	"encoding/json"
+	"fmt"
 	"github.com/hiveot/hub/services/hiveoview/src"
 	"github.com/hiveot/hub/services/hiveoview/src/session"
 	"github.com/hiveot/hub/transports/servers/httpserver"
+	jsoniter "github.com/json-iterator/go"
+	"io"
 	"log/slog"
 	"net/http"
 )
@@ -21,7 +25,7 @@ import (
 func PostLoginFormHandler(sm *session.WebSessionManager) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		// obtain login form fields
-
+		err := r.ParseForm()
 		loginID := r.FormValue("login")
 		password := r.FormValue("password")
 		if loginID == "" && password == "" {
@@ -29,11 +33,19 @@ func PostLoginFormHandler(sm *session.WebSessionManager) http.HandlerFunc {
 			//w.WriteHeader(http.StatusBadRequest)
 			return
 		}
+		// hx-headers doesnt work on posting a form so use query instead to pass a CID
 		cid := r.Header.Get(httpserver.ConnectionIDHeader)
+		if cid == "" {
+			cid = r.URL.Query().Get(httpserver.ConnectionIDHeader)
+		}
+		if cid == "" {
+			slog.Error("PostLoginFormHandler: Missing CID for client. Disconnecting", "loginID", loginID)
+			http.Error(w, "missing CID", http.StatusBadRequest)
+			return
+		}
 		slog.Info("PostLoginFormHandler",
 			"loginID", loginID,
 			"cid", cid)
-
 		newToken, err := sm.ConnectWithPassword(w, r, loginID, password, cid)
 		_ = newToken
 		if err != nil {
@@ -58,42 +70,54 @@ func PostLoginFormHandler(sm *session.WebSessionManager) http.HandlerFunc {
 		header := w.Header()
 		header.Add("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store")
 		// prevent the browser from re-posting on back button or refresh (POST-Redirect-GET) pattern
-		http.Redirect(w, r, src.RenderDashboardRootPath, http.StatusSeeOther)
+
+		// A redirect apparently cannot include the custom CID header.
+		header.Add(httpserver.ConnectionIDHeader, cid) // this doesn't work
+		// fall back to query params
+		redirPath := fmt.Sprintf("%s?%s=%s",
+			src.RenderDashboardRootPath, httpserver.ConnectionIDHeader, cid)
+		http.Redirect(w, r, redirPath, http.StatusSeeOther)
 	}
 }
 
-// PostLoginHandler lets a client login using a login ID and password,
+// PostLoginHandler lets a client login using a login ID and password object,
 // and returns an auth token.
 //
+// # Intended primarily for testing using the hub sse client
+//
 // This requires a transports.ConnectionIDHeader (connection-id header)
 // for a session to be retained.
 // This returns a new authentication token that can be used as bearer token instead
 // of logging in again.
-//func PostLoginHandler(sm *session.WebSessionManager) http.HandlerFunc {
-//	return func(w http.ResponseWriter, r *http.Request) {
-//		body, err := io.ReadAll(r.Body)
-//		if err != nil {
-//			return
-//		}
-//		loginMessage := map[string]string{}
-//		err = json.Unmarshal(body, &loginMessage)
-//		// FIXME: use a shared login message struct
-//		loginID := loginMessage["login"]
-//		password := loginMessage["password"]
-//		if loginID == "" && password == "" {
-//			http.Redirect(w, r, src.RenderLoginPath, http.StatusBadRequest)
-//			return
-//		}
-//		cid := r.Header.Get(httpserver.ConnectionIDHeader)
-//		slog.Info("PostLoginHandler",
-//			"loginID", loginID,
-//			"cid", cid)
-//
-//		newToken, err := sm.ConnectWithPassword(w, r, loginID, password, cid)
-//
-//		// this will prevent a redirect from working
-//		newTokenJSON, _ := jsoniter.Marshal(newToken)
-//		w.Write(newTokenJSON)
-//
-//	}
-//}
+func PostLoginHandler(sm *session.WebSessionManager) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		body, err := io.ReadAll(r.Body)
+		if err != nil {
+			return
+		}
+		loginMessage := map[string]string{}
+		err = json.Unmarshal(body, &loginMessage)
+		// FIXME: use a shared login message struct
+		loginID := loginMessage["login"]
+		password := loginMessage["password"]
+		if loginID == "" && password == "" {
+			http.Redirect(w, r, src.RenderLoginPath, http.StatusBadRequest)
+			return
+		}
+		cid := r.Header.Get(httpserver.ConnectionIDHeader)
+		if cid == "" {
+			slog.Error("ConnectWithPassword: Missing CID for client. Disconnecting", "loginID", loginID)
+			http.Error(w, "missing CID", http.StatusBadRequest)
+			return
+		}
+		slog.Info("PostLoginHandler",
+			"loginID", loginID,
+			"cid", cid)
+		newToken, err := sm.ConnectWithPassword(w, r, loginID, password, cid)
+
+		// this will prevent a redirect from working
+		newTokenJSON, _ := jsoniter.Marshal(newToken)
+		w.Write(newTokenJSON)
+
+	}
+}
diff --git a/services/hiveoview/src/views/login/login.go b/services/hiveoview/src/views/login/login.go
index 5a3c9f4b..7522458c 100644
--- a/services/hiveoview/src/views/login/login.go
+++ b/services/hiveoview/src/views/login/login.go
@@ -1,8 +1,11 @@
 package login
 
 import (
+	"fmt"
 	"github.com/hiveot/hub/services/hiveoview/src"
 	"github.com/hiveot/hub/services/hiveoview/src/views"
+	"github.com/hiveot/hub/transports/servers/httpserver"
+	"github.com/teris-io/shortid"
 	"log/slog"
 	"net/http"
 )
@@ -18,10 +21,15 @@ type LoginTemplateData struct {
 
 // RenderLogin renders the login form
 func RenderLogin(w http.ResponseWriter, r *http.Request) {
+
+	// hx-headers doesnt work on posting a form, so use query instead to pass a CID
+	cid := "login-" + shortid.MustGenerate()
+	postLoginPath := fmt.Sprintf("%s?%s=%s", src.UIPostFormLoginPath, httpserver.ConnectionIDHeader, cid)
 	data := LoginTemplateData{
 		LoginID:       "",
 		LoginError:    "",
-		PostLoginPath: src.UIPostLoginPath,
+		PostLoginPath: postLoginPath,
+		Cid:           cid,
 	}
 
 	loginError := r.URL.Query().Get("error")
diff --git a/services/hiveoview/test/Hiveov_test.go b/services/hiveoview/test/Hiveov_test.go
index 9dc8b051..1beb85a8 100644
--- a/services/hiveoview/test/Hiveov_test.go
+++ b/services/hiveoview/test/Hiveov_test.go
@@ -12,13 +12,11 @@ import (
 	"github.com/hiveot/hub/transports/tputils/tlsclient"
 	"github.com/hiveot/hub/wot"
 	"github.com/hiveot/hub/wot/td"
-	jsoniter "github.com/json-iterator/go"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	"io"
-	"net/url"
 	"os"
 	"path"
+	"strings"
 	"sync/atomic"
 	"testing"
 	"time"
@@ -86,6 +84,7 @@ func WebLogin(fullURL string, clientID string,
 	sseCl := sseclient.NewSsescConsumerClient(
 		fullURL, clientID, nil, ts.Certs.CaCert,
 		getHiveoviewForm, time.Minute)
+	// hiveoview uses a different login path as the hub
 	sseCl.SetSSEPath(service.WebSsePath)
 	sseCl.SetConnectHandler(onConnection)
 	sseCl.SetNotificationHandler(onNotification)
@@ -93,7 +92,6 @@ func WebLogin(fullURL string, clientID string,
 
 	//err = sseCl.ConnectWithLoginForm(clientID)
 	// FIXME: password is clientID
-	// hiveoview uses a different login path as the hub
 	_, err = sseCl.ConnectWithPassword(clientID)
 
 	//time.Sleep(time.Second * 10)
@@ -156,107 +154,27 @@ func TestLogin(t *testing.T) {
 	// 2: login using plain TLS connection and a form
 	hostPort := fmt.Sprintf("localhost:%d", servicePort)
 	cl2 := tlsclient.NewTLSClient(
-		hostPort, nil, ts.Certs.CaCert, time.Second*60, "cid1")
+		hostPort, nil, ts.Certs.CaCert, time.Second*60)
 
 	// try login. The test user password is the clientID
 	// authenticate the connection with the hiveot http/sse service (not the hub server)
 	// the service will in turn forward the request to the hub.
-	loginMessage := map[string]string{
+	formData := map[string]string{
 		"login":    clientID1,
 		"password": clientID1,
 	}
 	// this login will set an auth cookie
-	loginJSON, _ := jsoniter.Marshal(loginMessage)
-	_ = loginJSON
-	resp, _, statusCode, err := cl2.Post("/login", loginJSON, "cid2")
+	resp, statusCode, err := cl2.PostForm(src.UIPostFormLoginPath, formData)
 	//resp holds the serialized new token
 	cl2.Close()
 	require.NoError(t, err)
 	assert.Equal(t, 200, statusCode)
 
-	// result contains the new paseto auth token (v4.public.*)
-	var newToken string
-	err = jsoniter.Unmarshal(resp, &newToken)
-	assert.NotEmpty(t, newToken)
-	assert.NoError(t, err)
-	clientID, sessID, err := ts.Runtime.AuthnSvc.SessionAuth.ValidateToken(newToken)
-	_ = clientID
-	_ = sessID
-	require.NoError(t, err)
-
-	// retrieving about should succeed
-	data, statusCode, err := cl2.Get(src.RenderAboutPath)
-	_ = statusCode
-	assert.NoError(t, err)
-	assert.NotEmpty(t, data)
-	// todo verify the redirect to /about
-
-	// request using a new client and the given auth token
-	//cl3 := tlsclient.NewTLSClient(
-	//	hostPort, nil, ts.Certs.CaCert, time.Second*60, "cid3")
-	//cl3.SetAuthToken(newToken)
-	//data, statusCode, err = cl3.Get(src.RenderAboutPath)
-	//_ = statusCode
-	//assert.NoError(t, err)
-	//assert.NotEmpty(t, data)
-	// todo verify the result is the about path, not a redirect to login
-
-	t.Log("TestLogin completed")
-}
-
-// test login from a client using forms
-func TestLoginForm(t *testing.T) {
-	const clientID1 = "user1"
-
-	// 1: setup: start a runtime and service; this generates an error that
-	//    the state service isnt found. ignore it.
-	svc := service.NewHiveovService(servicePort, true, nil,
-		"", ts.Certs.ServerCert, ts.Certs.CaCert, noState, timeout)
-	avcAg, _ := ts.AddConnectService(serviceID)
-	require.NotNil(t, avcAg)
-	defer avcAg.Disconnect()
-	err := svc.Start(avcAg)
-
-	require.NoError(t, err)
-	defer svc.Stop()
-
-	// make sure the test client exists
-	cl1, token1 := ts.AddConnectConsumer(clientID1, authz.ClientRoleOperator)
-	cl1.Disconnect()
-
-	_ = token1
-
-	ccount, _ := ts.Runtime.CM.GetNrConnections()
-	_ = ccount
-	time.Sleep(time.Millisecond * 10)
-
-	// 2: login using plain TLS connection and a form
-	hostPort := fmt.Sprintf("localhost:%d", servicePort)
-	cl2 := tlsclient.NewTLSClient(
-		hostPort, nil, ts.Certs.CaCert, time.Second*60, "cid1")
-
-	// try login. The test user password is the clientID
-	// the client should receive a cookie with a token
-	formMock := url.Values{}
-	formMock.Add("loginID", clientID1)
-	formMock.Add("password", clientID1)
-	fullURL := fmt.Sprintf("https://%s/loginForm", hostPort)
-
-	// authenticate the connection with the hiveot http/sse service (not the hub server)
-	// the service will in turn forward the request to the hub.
-	resp, err := cl2.GetHttpClient().PostForm(fullURL, formMock)
-	cl2.Close()
-	require.NoError(t, err)
-
-	// 3. login should have redirected to /dashboard. It contained an auth cookie
-	assert.Equal(t, 200, resp.StatusCode)
-	assert.Equal(t, "/dashboard", resp.Request.URL.Path)
+	// login should have redirected to /dashboard. It contained an auth cookie
+	//assert.Equal(t, "/dashboard", resp.Request.URL.Path)
 
-	// result contains html of the dashboard page
-	body, err := io.ReadAll(resp.Body)
-	_ = resp.Body.Close()
-	assert.NoError(t, err)
-	assert.NotEmpty(t, body)
+	// result contains a redirected web page
+	assert.True(t, strings.HasPrefix(string(resp), "<!DOCTYPE html>"))
 	t.Log("TestLogin completed")
 }
 
diff --git a/services/idprov/IdProv_test.go b/services/idprov/IdProv_test.go
index b4455ea3..7b90af64 100644
--- a/services/idprov/IdProv_test.go
+++ b/services/idprov/IdProv_test.go
@@ -99,7 +99,7 @@ func TestAutomaticProvisioning(t *testing.T) {
 
 	// next, provisioning should succeed
 	idProvServerURL := fmt.Sprintf("localhost:%d", testPort)
-	tlsClient := tlsclient.NewTLSClient(idProvServerURL, nil, ts.Certs.CaCert, 0, "")
+	tlsClient := tlsclient.NewTLSClient(idProvServerURL, nil, ts.Certs.CaCert, 0)
 	//tlsClient.ConnectNoAuth()
 	status, token1, err := idprovclient.SubmitIdProvRequest(
 		device1ID, device1KP.ExportPublic(), "", tlsClient)
@@ -154,7 +154,7 @@ func TestAutomaticProvisioningBadParameters(t *testing.T) {
 
 	// test missing deviceID
 	idProvServerURL := "localhost:9002"
-	tlsClient := tlsclient.NewTLSClient(idProvServerURL, nil, ts.Certs.CaCert, 0, "")
+	tlsClient := tlsclient.NewTLSClient(idProvServerURL, nil, ts.Certs.CaCert, 0)
 	status, tokenEnc, err := idprovclient.SubmitIdProvRequest(
 		"", device1PubPEM, "", tlsClient)
 	assert.Error(t, err)
@@ -185,7 +185,7 @@ func TestManualProvisioning(t *testing.T) {
 
 	// request provisioning
 	idProvServerAddr := fmt.Sprintf("localhost:%d", testPort)
-	tlsClient := tlsclient.NewTLSClient(idProvServerAddr, nil, ts.Certs.CaCert, 0, "")
+	tlsClient := tlsclient.NewTLSClient(idProvServerAddr, nil, ts.Certs.CaCert, 0)
 	//tlsClient.ConnectNoAuth()
 	status, token, err := idprovclient.SubmitIdProvRequest(device1ID, device1PubPEM, "", tlsClient)
 	require.NoError(t, err)
diff --git a/services/idprov/idprovclient/SubmitIdProvRequest.go b/services/idprov/idprovclient/SubmitIdProvRequest.go
index 8cce7514..617e196d 100644
--- a/services/idprov/idprovclient/SubmitIdProvRequest.go
+++ b/services/idprov/idprovclient/SubmitIdProvRequest.go
@@ -28,7 +28,7 @@ func SubmitIdProvRequest(clientID string, pubKey string, mac string, tlsClient *
 		MAC:      mac,
 	}
 	reqData, _ := jsoniter.Marshal(req)
-	respData, _, _, err := tlsClient.Post(idprovapi.ProvisionRequestPath, reqData, "")
+	respData, _, err := tlsClient.Post(idprovapi.ProvisionRequestPath, reqData)
 	resp := idprovapi.ProvisionRequestResp{}
 	err = jsoniter.Unmarshal(respData, &resp)
 	return resp.Status, resp.Token, err
diff --git a/transports/Messages.go b/transports/Messages.go
index e115a887..441f6c39 100644
--- a/transports/Messages.go
+++ b/transports/Messages.go
@@ -57,11 +57,11 @@ type NotificationMessage struct {
 	// Data for the notification as described in the TD affordance dataschema.
 	// If the operation is one of the Thing level operations, the input is specified
 	// by the operation's dataschema.
-	Data any `json:"input,omitempty"` // native
+	Data any `json:"data,omitempty"` // native
 
 	// Created holds the date-time the notification was created. using RFC3339milli
 	// This MUST be set by the protocol binding if not provided.
-	Created string `json:"timestamp"`
+	Created string `json:"created"`
 
 	// AgentID contains the Agent ID that published the notification
 	// The protocol server MUST set this to the authenticated client.
diff --git a/transports/clients/base/BaseClient.go b/transports/clients/base/BaseClient.go
index c6ecbabf..229bf74e 100644
--- a/transports/clients/base/BaseClient.go
+++ b/transports/clients/base/BaseClient.go
@@ -19,7 +19,7 @@ import (
 type BaseClient struct {
 	// ID of this client
 	BaseClientID string
-	// unique connectionID start with the clientID
+	// unique connectionID starting with the clientID.
 	BaseConnectionID string
 
 	// CA certificate to verify the server with
@@ -251,7 +251,7 @@ func (cl *BaseClient) SendRequest(req transports.RequestMessage, waitForCompleti
 	resp transports.ResponseMessage, err error) {
 
 	t0 := time.Now()
-	slog.Info("SendRequest",
+	slog.Debug("SendRequest",
 		slog.String("op", req.Operation),
 		slog.String("dThingID", req.ThingID),
 		slog.String("name", req.Name),
@@ -297,7 +297,7 @@ func (cl *BaseClient) SendRequest(req transports.RequestMessage, waitForCompleti
 			slog.String("requestID", req.RequestID),
 			slog.String("error", err.Error()))
 	} else {
-		slog.Info("SendRequest: success",
+		slog.Debug("SendRequest: success",
 			slog.String("op", req.Operation),
 			slog.Float64("duration msec", float64(duration.Microseconds())/1000),
 			slog.String("requestID", req.RequestID))
diff --git a/transports/clients/base/RnR.go b/transports/clients/base/RnR.go
index 2e102e60..74b41b00 100644
--- a/transports/clients/base/RnR.go
+++ b/transports/clients/base/RnR.go
@@ -56,8 +56,8 @@ func (rnr *RnRChan) CloseAll() {
 // If a timeout passes while writing is block the write is released.
 func (rnr *RnRChan) HandleResponse(msg transports.ResponseMessage) bool {
 	rnr.mux.Lock()
-	defer rnr.mux.Unlock()
 	rChan, isRPC := rnr.correlData[msg.RequestID]
+	rnr.mux.Unlock()
 	if isRPC {
 		ctx, cancelFn := context.WithTimeout(context.Background(), rnr.writeTimeout)
 		select {
diff --git a/transports/clients/httpclient/HttpBasicConsumerClient.go b/transports/clients/httpclient/HttpBasicConsumerClient.go
index a39a6b05..ad6f2e31 100644
--- a/transports/clients/httpclient/HttpBasicConsumerClient.go
+++ b/transports/clients/httpclient/HttpBasicConsumerClient.go
@@ -338,7 +338,7 @@ func (cl *HttpConsumerClient) Init(
 	cl.BaseClient = base.BaseClient{
 		BaseCaCert:       caCert,
 		BaseClientID:     clientID,
-		BaseConnectionID: clientID + "." + shortid.MustGenerate(),
+		BaseConnectionID: "http-" + shortid.MustGenerate(),
 		BaseProtocolType: transports.ProtocolTypeHTTPS,
 		BaseFullURL:      fullURL,
 		BaseHostPort:     baseHostPort,
diff --git a/transports/clients/mqttclient/MqttConsumerClient.go b/transports/clients/mqttclient/MqttConsumerClient.go
index a07d73fb..a46d68d5 100644
--- a/transports/clients/mqttclient/MqttConsumerClient.go
+++ b/transports/clients/mqttclient/MqttConsumerClient.go
@@ -604,7 +604,7 @@ func (cl *MqttConsumerClient) Init(fullURL string, clientID string,
 
 	cl.BaseCaCert = caCert
 	cl.BaseClientID = clientID
-	cl.BaseConnectionID = clientID + "." + shortid.MustGenerate()
+	cl.BaseConnectionID = "mqtt-" + shortid.MustGenerate()
 	cl.BaseTimeout = timeout
 	cl.BaseProtocolType = transports.ProtocolTypeMQTTS
 	cl.BaseFullURL = fullURL
diff --git a/transports/clients/wssclient/WssConsumerClient.go b/transports/clients/wssclient/WssConsumerClient.go
index 4e5a42d8..7f08363c 100644
--- a/transports/clients/wssclient/WssConsumerClient.go
+++ b/transports/clients/wssclient/WssConsumerClient.go
@@ -86,12 +86,10 @@ func (cl *WssConsumerClient) ConnectWithPassword(password string) (newToken stri
 	}
 	// TODO: this is part of the http binding, not the websocket binding
 	// a sacrificial client to get a token
-	tlsClient := tlsclient.NewTLSClient(
-		loginURL, nil, cl.BaseCaCert, cl.BaseTimeout, "")
+	tlsClient := tlsclient.NewTLSClient(loginURL, nil, cl.BaseCaCert, cl.BaseTimeout)
 	argsJSON, _ := json.Marshal(loginMessage)
 	defer tlsClient.Close()
-	resp, _, statusCode, _, err2 := tlsClient.Invoke(
-		"POST", loginURL, argsJSON, "", nil)
+	resp, statusCode, err2 := tlsClient.Post(loginURL, argsJSON)
 	if err2 != nil {
 		err = fmt.Errorf("%d: Login failed: %s", statusCode, err2)
 		return "", err
@@ -161,11 +159,6 @@ func (cl *WssConsumerClient) Disconnect() {
 	cl.BaseMux.Unlock()
 }
 
-// InvokeAction invokes an action on a thing and wait for the response
-//func (cl *WssConsumerClient) InvokeAction(dThingID, name string, input any, output any) error {
-//	return cl.SendOperation(wot.OpInvokeAction, dThingID, name, input, output, requestID)
-//}
-
 // Logout from the server and end the session.
 // This is specific to the Hiveot Hub.
 func (cl *WssConsumerClient) Logout() error {
@@ -174,14 +167,12 @@ func (cl *WssConsumerClient) Logout() error {
 	slog.Info("Logout", slog.String("clientID", cl.BaseClientID))
 
 	// Use a sacrificial http client to logout
-	tlsClient := tlsclient.NewTLSClient(
-		cl.BaseHostPort, nil, cl.BaseCaCert, cl.BaseTimeout, "")
+	tlsClient := tlsclient.NewTLSClient(cl.BaseHostPort, nil, cl.BaseCaCert, cl.BaseTimeout)
 	tlsClient.SetAuthToken(cl.token)
 	defer tlsClient.Close()
 
 	logoutURL := fmt.Sprintf("https://%s%s", cl.BaseHostPort, httpserver.HttpPostLogoutPath)
-	_, _, _, _, err2 := tlsClient.Invoke(
-		"POST", logoutURL, nil, "", nil)
+	_, _, err2 := tlsClient.Post(logoutURL, nil)
 	if err2 != nil {
 		err := fmt.Errorf("logout failed: %s", err2)
 		return err
@@ -223,13 +214,12 @@ func (cl *WssConsumerClient) RefreshToken(oldToken string) (newToken string, err
 	// TODO: this is part of the http binding, not the websocket binding
 	// a sacrificial client to get a token
 	tlsClient := tlsclient.NewTLSClient(
-		cl.BaseHostPort, nil, cl.BaseCaCert, cl.BaseTimeout, "")
+		cl.BaseHostPort, nil, cl.BaseCaCert, cl.BaseTimeout)
 	tlsClient.SetAuthToken(oldToken)
 	defer tlsClient.Close()
 
 	argsJSON, _ := json.Marshal(oldToken)
-	resp, _, statusCode, _, err2 := tlsClient.Invoke(
-		"POST", refreshURL, argsJSON, "", nil)
+	resp, statusCode, err2 := tlsClient.Post(refreshURL, argsJSON)
 	if err2 != nil {
 		err = fmt.Errorf("%d: Refresh failed: %s", statusCode, err2)
 		return "", err
@@ -325,12 +315,9 @@ func (cl *WssConsumerClient) Init(fullURL string, clientID string,
 
 	cl.HttpConsumerClient.Init(
 		fullURL, clientID, clientCert, caCert, getForm, timeout)
-	// subclasses (eg: agent) replace BaseHandleMessage with the agent handler
-	//cl.BaseHandleMessage = cl.HandleConsumerMessage
 
 	// max delay 3 seconds before a response is expected
 	cl.maxReconnectAttempts = 0 // 1 attempt per second
-	//cl.BaseSendMessage = cl.SendMessage
 	cl.BasePubRequest = cl.PubRequest
 }
 
diff --git a/transports/servers/httpserver/HttpRouter.go b/transports/servers/httpserver/HttpRouter.go
index fc99cf32..19b3dc50 100644
--- a/transports/servers/httpserver/HttpRouter.go
+++ b/transports/servers/httpserver/HttpRouter.go
@@ -16,7 +16,7 @@ const (
 	RequestIDHeader = "request-id"
 	// ConnectionIDHeader identifies the client's connection in case of multiple
 	// connections from the same client.
-	ConnectionIDHeader = "connection-id"
+	ConnectionIDHeader = "cid"
 	// DataSchemaHeader to indicate which  'additionalresults' dataschema being returned.
 	DataSchemaHeader = "dataschema"
 
diff --git a/transports/tests/connect_test.go b/transports/tests/connect_test.go
index 2b636ec9..44236ccb 100644
--- a/transports/tests/connect_test.go
+++ b/transports/tests/connect_test.go
@@ -213,7 +213,7 @@ func TestLoginRefresh(t *testing.T) {
 	t.Log(fmt.Sprintf("---%s---\n", t.Name()))
 	const thingID1 = "thing1"
 
-	srv, cancelFn, _ := StartTransportServer(nil, nil, nil)
+	srv, cancelFn, cm := StartTransportServer(nil, nil, nil)
 	defer cancelFn()
 	cl1 := NewConsumer(testClientID1, srv.GetForm)
 	defer cl1.Disconnect()
@@ -224,7 +224,15 @@ func TestLoginRefresh(t *testing.T) {
 	token, err := cl1.ConnectWithPassword(testClientID1)
 	require.NoError(t, err)
 	require.NotEmpty(t, token)
-	//time.Sleep(time.Millisecond * 1)
+
+	// check if both client and server have the connection ID
+	// the server prefixes it with clientID- to ensure no client can steal another's ID
+	cid1 := cl1.GetConnectionID()
+	assert.NotEmpty(t, cid1)
+	srvConn := cm.GetConnectionByClientID(testClientID1)
+	require.NotNil(t, srvConn)
+	cid1server := srvConn.GetConnectionID()
+	assert.Equal(t, testClientID1+"-"+cid1, cid1server)
 
 	err = cl1.Ping()
 	require.NoError(t, err)
diff --git a/transports/tputils/tlsclient/TLSClient.go b/transports/tputils/tlsclient/TLSClient.go
index ebd87d9a..95d0b948 100644
--- a/transports/tputils/tlsclient/TLSClient.go
+++ b/transports/tputils/tlsclient/TLSClient.go
@@ -8,20 +8,12 @@ import (
 	"io"
 	"log/slog"
 	"net/http"
+	"net/url"
 	"time"
 )
 
 const DefaultClientTimeout = time.Second * 30
 
-// HTTPRequestIDHeader defines the name of the HTTP message-id header field.
-// Intended for including a message ID in the request or response
-const HTTPRequestIDHeader = "message-id"
-
-// HTTPConnectionIDHeader defines the name of the HTTP 'cid' header field.
-// Intended for the client to include a connection-id to link asynchronous requests
-// to responses. TODO: does remoteaddr change between calls?
-const HTTPConnectionIDHeader = "cid"
-
 // TLSClient is a simple TLS Client with authentication using certificates or JWT authentication with login/pw
 type TLSClient struct {
 	// host and port of the server to setup to
@@ -63,8 +55,7 @@ func (cl *TLSClient) Close() {
 func (cl *TLSClient) Delete(path string) (resp []byte, httpStatus int, err error) {
 	// careful, a double // in the path causes a 301 and changes POST to GET
 	serverURL := fmt.Sprintf("https://%s%s", cl.hostPort, path)
-	resp, _, httpStatus, _, err = cl.Invoke(
-		"DELETE", serverURL, nil, "", nil)
+	resp, httpStatus, _, err = cl.Send("DELETE", serverURL, nil, "", nil)
 	return resp, httpStatus, err
 
 }
@@ -75,7 +66,7 @@ func (cl *TLSClient) Delete(path string) (resp []byte, httpStatus int, err error
 //	path to invoke
 func (cl *TLSClient) Get(path string) (resp []byte, httpStatus int, err error) {
 	serverURL := fmt.Sprintf("https://%s%s", cl.hostPort, path)
-	resp, _, httpStatus, _, err = cl.Invoke("GET", serverURL, nil, "", nil)
+	resp, httpStatus, _, err = cl.Send("GET", serverURL, nil, "", nil)
 	return resp, httpStatus, err
 }
 
@@ -84,7 +75,7 @@ func (cl *TLSClient) GetHttpClient() *http.Client {
 	return cl.httpClient
 }
 
-// Invoke a HTTPS method and read response.
+// Send a HTTPS method and read response.
 //
 // If a JWT authentication is enabled then add the bearer token to the header
 // If msg is a string then it is considered to be already serialized.
@@ -93,21 +84,23 @@ func (cl *TLSClient) GetHttpClient() *http.Client {
 //	method: GET, PUT, POST, ...
 //	url: full URL to invoke
 //	body contains the serialized request body
-//	requestID: optional message ID to include in the request header
+//	contentType: default is "application/json"
 //	qParams: optional map with query parameters
 //
 // This returns the serialized response data, a response message ID, return status code or an error
-func (cl *TLSClient) Invoke(method string, requrl string, body []byte, requestID string, qParams map[string]string) (
-	resp []byte, respRequestID string, httpStatus int, headers http.Header, err error) {
+func (cl *TLSClient) Send(
+	method string, requrl string, body []byte, contentType string, qParams map[string]string) (
+	resp []byte, httpStatus int, headers http.Header, err error) {
 
 	var req *http.Request
-	contentType := "application/json"
-
+	if contentType == "" {
+		contentType = "application/json"
+	}
 	if cl == nil || cl.httpClient == nil {
 		err = fmt.Errorf("_send: '%s'. Client is not started", requrl)
-		return nil, "", http.StatusInternalServerError, nil, err
+		return nil, http.StatusInternalServerError, nil, err
 	}
-	slog.Debug("TLSClient._send", "method", method, "requrl", requrl)
+	slog.Debug("TLSClient.Send", "method", method, "requrl", requrl)
 
 	// Caution! a double // in the path causes a 301 and changes post to get
 	req, err = NewRequest(method, requrl, cl.bearerToken, body)
@@ -120,26 +113,22 @@ func (cl *TLSClient) Invoke(method string, requrl string, body []byte, requestID
 		req.URL.RawQuery = qValues.Encode()
 	}
 	if err != nil {
-		return nil, "", http.StatusInternalServerError, nil, err
+		return nil, http.StatusInternalServerError, nil, err
 	}
 
 	// set headers
 	req.Header.Set("Content-Type", contentType)
-	if requestID != "" {
-		req.Header.Set(HTTPRequestIDHeader, requestID)
-	}
 	for k, v := range cl.headers {
 		req.Header.Set(k, v)
 	}
 
 	httpResp, err := cl.httpClient.Do(req)
 	if err != nil {
-		err = fmt.Errorf("_send: %s %s: %w", method, requrl, err)
+		err = fmt.Errorf("Send: %s %s: %w", method, requrl, err)
 		slog.Error(err.Error())
-		return nil, "", 500, nil, err
+		return nil, 500, nil, err
 	}
 	respBody, err := io.ReadAll(httpResp.Body)
-	respRequestID = httpResp.Header.Get(HTTPRequestIDHeader)
 	// response body MUST be closed
 	_ = httpResp.Body.Close()
 	httpStatus = httpResp.StatusCode
@@ -153,11 +142,11 @@ func (cl *TLSClient) Invoke(method string, requrl string, body []byte, requestID
 		}
 	} else if httpStatus >= 500 {
 		err = fmt.Errorf("Error %d (%s): %s", httpStatus, httpResp.Status, respBody)
-		slog.Error("_send returned internal server error", "requrl", requrl, "err", err.Error())
+		slog.Error("Send returned internal server error", "requrl", requrl, "err", err.Error())
 	} else if err != nil {
-		err = fmt.Errorf("_send: Error %s %s: %w", method, requrl, err)
+		err = fmt.Errorf("Send: Error %s %s: %w", method, requrl, err)
 	}
-	return respBody, respRequestID, httpStatus, httpResp.Header, err
+	return respBody, httpStatus, httpResp.Header, err
 }
 
 //// Logout from the server and end the session
@@ -178,8 +167,7 @@ func (cl *TLSClient) Patch(
 
 	// careful, a double // in the path causes a 301 and changes POST to GET
 	serverURL := fmt.Sprintf("https://%s%s", cl.hostPort, path)
-	resp, _, statusCode, _, err = cl.Invoke(
-		"PATCH", serverURL, body, "", nil)
+	resp, statusCode, _, err = cl.Send(http.MethodPatch, serverURL, body, "", nil)
 	return resp, statusCode, err
 }
 
@@ -189,15 +177,30 @@ func (cl *TLSClient) Patch(
 //
 //	path to invoke
 //	body contains the serialized request body
-//	requestID optional field to link async requests and responses
-func (cl *TLSClient) Post(path string, body []byte, requestID string) (
-	resp []byte, respRequestID string, statusCode int, err error) {
+func (cl *TLSClient) Post(path string, body []byte) (
+	resp []byte, statusCode int, err error) {
+
+	// careful, a double // in the path causes a 301 and changes POST to GET
+	serverURL := fmt.Sprintf("https://%s%s", cl.hostPort, path)
+	resp, statusCode, _, err = cl.Send(
+		http.MethodPost, serverURL, body, "", nil)
+	return resp, statusCode, err
+}
+
+// PostForm posts a form message.
+func (cl *TLSClient) PostForm(path string, formData map[string]string) (
+	resp []byte, statusCode int, err error) {
 
 	// careful, a double // in the path causes a 301 and changes POST to GET
 	serverURL := fmt.Sprintf("https://%s%s", cl.hostPort, path)
-	resp, requestID, statusCode, _, err = cl.Invoke(
-		"POST", serverURL, body, requestID, nil)
-	return resp, requestID, statusCode, err
+	form := url.Values{}
+	for k, v := range formData {
+		form.Add(k, v)
+	}
+	body := form.Encode()
+	resp, statusCode, _, err = cl.Send(
+		http.MethodPost, serverURL, []byte(body), "application/x-www-form-urlencoded", nil)
+	return resp, statusCode, err
 }
 
 // Put a message with json payload
@@ -207,14 +210,13 @@ func (cl *TLSClient) Post(path string, body []byte, requestID string) (
 //	path to invoke
 //	body contains the serialized request body
 //	requestID optional field to link async requests and responses
-func (cl *TLSClient) Put(path string, body []byte, requestID string) (
-	resp []byte, respRequestID string, statusCode int, err error) {
+func (cl *TLSClient) Put(path string, body []byte) (
+	resp []byte, statusCode int, err error) {
 
 	// careful, a double // in the path causes a 301 and changes POST to GET
 	serverURL := fmt.Sprintf("https://%s%s", cl.hostPort, path)
-	resp, requestID, statusCode, _, err = cl.Invoke(
-		"PUT", serverURL, body, requestID, nil)
-	return resp, requestID, statusCode, err
+	resp, statusCode, _, err = cl.Send(http.MethodPut, serverURL, body, "", nil)
+	return resp, statusCode, err
 }
 
 // SetAuthToken Sets login ID and secret for bearer token authentication using a
@@ -247,10 +249,9 @@ func (cl *TLSClient) SetHeader(name string, val string) {
 //	clientCert is an option client certificate used to connect
 //	caCert with the x509 CA certificate, nil if not available
 //	timeout duration of the request or 0 for default
-//	cid is the recommended connection ID to include as a header
 //
 // returns TLS client for submitting requests
-func NewTLSClient(hostPort string, clientCert *tls.Certificate, caCert *x509.Certificate, timeout time.Duration, cid string) *TLSClient {
+func NewTLSClient(hostPort string, clientCert *tls.Certificate, caCert *x509.Certificate, timeout time.Duration) *TLSClient {
 	if timeout == 0 {
 		timeout = DefaultClientTimeout
 	}
@@ -304,9 +305,6 @@ func NewTLSClient(hostPort string, clientCert *tls.Certificate, caCert *x509.Cer
 		caCert:     caCert,
 		headers:    make(map[string]string),
 	}
-	if cid != "" {
-		cl.headers[HTTPConnectionIDHeader] = cid
-	}
 
 	return cl
 }
diff --git a/transports/tputils/tlsclient/TLSClient_test.go b/transports/tputils/tlsclient/TLSClient_test.go
index 40671500..c93bcb3a 100644
--- a/transports/tputils/tlsclient/TLSClient_test.go
+++ b/transports/tputils/tlsclient/TLSClient_test.go
@@ -5,7 +5,6 @@ import (
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/json"
-	"fmt"
 	"github.com/hiveot/hub/api/go/authn"
 	"github.com/hiveot/hub/lib/certs"
 	"github.com/hiveot/hub/lib/logging"
@@ -91,7 +90,7 @@ func TestNoCA(t *testing.T) {
 	assert.NoError(t, err)
 
 	// certificate authentication but no CA
-	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, nil, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, nil, 0)
 	assert.NoError(t, err)
 
 	_, _, err = cl.Get(path1)
@@ -100,7 +99,7 @@ func TestNoCA(t *testing.T) {
 	cl.Close()
 
 	// No authentication
-	cl = tlsclient.NewTLSClient(testAddress, nil, nil, 0, "")
+	cl = tlsclient.NewTLSClient(testAddress, nil, nil, 0)
 
 	_, _, err = cl.Get(path1)
 	assert.NoError(t, err)
@@ -125,7 +124,7 @@ func TestAuthClientCert(t *testing.T) {
 		path1Hit++
 	})
 	//
-	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, authBundle.CaCert, 0)
 	assert.NoError(t, err)
 
 	clientCert := cl.Certificate()
@@ -145,9 +144,9 @@ func TestAuthClientCert(t *testing.T) {
 	//
 	_, _, err = cl.Get(path1)
 	assert.NoError(t, err)
-	_, _, _, err = cl.Post(path1, nil, "")
+	_, _, err = cl.Post(path1, nil)
 	assert.NoError(t, err)
-	_, _, _, err = cl.Put(path1, nil, "")
+	_, _, err = cl.Put(path1, nil)
 	assert.NoError(t, err)
 	_, _, err = cl.Delete(path1)
 	assert.NoError(t, err)
@@ -160,13 +159,13 @@ func TestAuthClientCert(t *testing.T) {
 }
 
 func TestNotStarted(t *testing.T) {
-	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 0)
 	_, _, err := cl.Get("/notstarted")
 	assert.Error(t, err)
 	cl.Close()
 }
 func TestNoClientCert(t *testing.T) {
-	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 3, "")
+	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 3)
 	cl.Close()
 }
 
@@ -178,7 +177,7 @@ func TestBadClientCert(t *testing.T) {
 	otherTLS := certs.X509CertToTLS(otherCert, authBundle.ClientKey)
 	assert.NoError(t, err)
 
-	cl := tlsclient.NewTLSClient(testAddress, otherTLS, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, otherTLS, authBundle.CaCert, 0)
 	// this should produce an error in the log
 	//assert.Error(t, err)
 	cl.Close()
@@ -187,7 +186,7 @@ func TestBadClientCert(t *testing.T) {
 func TestNoServer(t *testing.T) {
 	// setup server and client environm
 	//
-	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, authBundle.CaCert, 0)
 	_, _, err := cl.Get("/noserver")
 	assert.Error(t, err)
 	cl.Close()
@@ -197,7 +196,7 @@ func TestCert404(t *testing.T) {
 	srv, err := startTestServer(mux)
 	assert.NoError(t, err)
 
-	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, authBundle.ClientCert, authBundle.CaCert, 0)
 
 	_, _, err = cl.Get("/pathnotfound")
 	assert.Error(t, err)
@@ -214,7 +213,6 @@ func TestAuthJWT(t *testing.T) {
 	user1 := "user1"
 	password1 := "password1"
 	secret := make([]byte, 64)
-	msgID1 := "msgid-1"
 	_, _ = rand.Read(secret)
 
 	// setup server and client environment
@@ -228,7 +226,7 @@ func TestAuthJWT(t *testing.T) {
 		err = json.Unmarshal(body, &authMsg)
 
 		// expect a requestID
-		msgID := req.Header.Get(tlsclient.HTTPRequestIDHeader)
+		//msgID := req.Header.Get(tlsclient.HTTPRequestIDHeader)
 		assert.NoError(t, err)
 		assert.Equal(t, user1, authMsg.ClientID)
 		assert.Equal(t, password1, authMsg.Password)
@@ -245,7 +243,7 @@ func TestAuthJWT(t *testing.T) {
 			token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 			newToken, err := token.SignedString(secret)
 			assert.NoError(t, err)
-			resp.Header().Set(tlsclient.HTTPRequestIDHeader, msgID)
+			//resp.Header().Set(tlsclient.HTTPRequestIDHeader, msgID)
 			data, _ := json.Marshal(newToken)
 			_, _ = resp.Write(data)
 		} else {
@@ -265,16 +263,14 @@ func TestAuthJWT(t *testing.T) {
 	srv, err := startTestServer(mux)
 	assert.NoError(t, err)
 	//
-	loginURL := fmt.Sprintf("https://%s%s", testAddress, httpserver.HttpPostLoginPath)
 	loginMessage := authn.UserLoginArgs{
 		ClientID: user1,
 		Password: password1,
 	}
-	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 0)
 	jsonArgs, _ := json.Marshal(loginMessage)
-	resp, msgID2, _, _, err := cl.Invoke("POST", loginURL, jsonArgs, msgID1, nil)
+	resp, _, err := cl.Post(httpserver.HttpPostLoginPath, jsonArgs)
 	require.NoError(t, err)
-	assert.Equal(t, msgID1, msgID2)
 	reply := ""
 	err = json.Unmarshal(resp, &reply)
 
@@ -290,7 +286,6 @@ func TestAuthJWT(t *testing.T) {
 
 func TestAuthJWTFail(t *testing.T) {
 	pathHello1 := "/hello"
-	requestID1 := "msgid-1"
 
 	// setup server and client environment
 	mux := http.NewServeMux()
@@ -303,9 +298,9 @@ func TestAuthJWTFail(t *testing.T) {
 		resp.WriteHeader(http.StatusUnauthorized)
 	})
 	//
-	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 0, "")
+	cl := tlsclient.NewTLSClient(testAddress, nil, authBundle.CaCert, 0)
 	cl.SetAuthToken("badtoken")
-	resp, _, _, err := cl.Post(pathHello1, []byte("test"), requestID1)
+	resp, _, err := cl.Post(pathHello1, []byte("test"))
 	assert.Empty(t, resp)
 	// unauthorized
 	assert.Error(t, err)
diff --git a/transports/tputils/tlsserver/TLSServer_test.go b/transports/tputils/tlsserver/TLSServer_test.go
index b3fd99b2..e7f70b78 100644
--- a/transports/tputils/tlsserver/TLSServer_test.go
+++ b/transports/tputils/tlsserver/TLSServer_test.go
@@ -79,7 +79,7 @@ func TestNoAuth(t *testing.T) {
 	require.NoError(t, err)
 	defer srv.Stop()
 
-	cl := tlsclient.NewTLSClient(clientHostPort, nil, testCerts.CaCert, time.Second*120, "")
+	cl := tlsclient.NewTLSClient(clientHostPort, nil, testCerts.CaCert, time.Second*120)
 	_, _, err = cl.Get(path1)
 	assert.NoError(t, err)
 	assert.Equal(t, 1, path1Hit)
@@ -119,7 +119,7 @@ func TestTokenAuth(t *testing.T) {
 	defer srv.Stop()
 
 	// create a client and login
-	cl := tlsclient.NewTLSClient(clientHostPort, nil, testCerts.CaCert, time.Second*120, "")
+	cl := tlsclient.NewTLSClient(clientHostPort, nil, testCerts.CaCert, time.Second*120)
 	require.NoError(t, err)
 	defer cl.Close()
 	cl.SetAuthToken(token1)
@@ -224,7 +224,7 @@ func TestWriteResponse(t *testing.T) {
 		path2Hit++
 	})
 
-	cl := tlsclient.NewTLSClient(clientHostPort, nil, testCerts.CaCert, time.Second*120, "")
+	cl := tlsclient.NewTLSClient(clientHostPort, nil, testCerts.CaCert, time.Second*120)
 	require.NoError(t, err)
 	defer cl.Close()
 	reply, _, err := cl.Get(path2)
diff --git a/wot/consumedthing/InteractionOutput.go b/wot/consumedthing/InteractionOutput.go
index 76fbc075..a944dfa6 100644
--- a/wot/consumedthing/InteractionOutput.go
+++ b/wot/consumedthing/InteractionOutput.go
@@ -196,12 +196,12 @@ func NewInteractionOutputFromValue(
 	tv *digitwin.ThingValue, tdi *td.TD) *InteractionOutput {
 
 	io := &InteractionOutput{
-		ThingID:  tdi.ID,
-		Name:     tv.Name,
-		SenderID: tv.SenderID,
-		Updated:  tv.Updated,
-		Value:    NewDataSchemaValue(tv.Data),
-		Err:      nil,
+		ThingID: tdi.ID,
+		Name:    tv.Name,
+		//SenderID: tv.SenderID,
+		Updated: tv.Created,
+		Value:   NewDataSchemaValue(tv.Data),
+		Err:     nil,
 	}
 	if tdi == nil {
 		return io
@@ -221,27 +221,33 @@ func NewInteractionOutputFromValue(
 //	affType is one of AffordanceTypeAction, event or property
 //	name is the interaction affordance name the output belongs to
 //	raw is the raw data
-//	created is the timestamp the data is created
-func NewInteractionOutput(tdi *td.TD, affType string, name string, raw any, created string) *InteractionOutput {
+//	updated is the timestamp the data is last updated
+func NewInteractionOutput(tdi *td.TD, affType string, name string, raw any, updated string) *InteractionOutput {
+
 	var schema *td.DataSchema
+	var title string
+
 	switch affType {
 	case AffordanceTypeAction:
 		aff := tdi.Actions[name]
 		if aff == nil {
 			break
 		}
+		title = aff.Title
 		schema = aff.Output
 	case AffordanceTypeEvent:
 		aff := tdi.Events[name]
 		if aff == nil {
 			break
 		}
+		title = aff.Title
 		schema = aff.Data
 	case AffordanceTypeProperty:
 		aff := tdi.Properties[name]
 		if aff == nil {
 			break
 		}
+		title = aff.Title
 		schema = &aff.DataSchema
 	}
 	if schema == nil {
@@ -249,10 +255,14 @@ func NewInteractionOutput(tdi *td.TD, affType string, name string, raw any, crea
 			Title: "unknown schema",
 		}
 	}
+	if title == "" {
+		title = schema.Title
+	}
 	io := &InteractionOutput{
 		ThingID: tdi.ID,
 		Name:    name,
-		Updated: created,
+		Title:   title,
+		Updated: updated,
 		Schema:  *schema,
 		Value:   NewDataSchemaValue(raw),
 	}