Skip to content

Commit

Permalink
Dev iteration, working on improving handling of vocabulary.
Browse files Browse the repository at this point in the history
- bug fixes in the  isy99x binding and the hiveoview web server.
  • Loading branch information
hspaay committed Mar 13, 2024
1 parent 37daa1c commit 6ec20ad
Show file tree
Hide file tree
Showing 31 changed files with 1,278 additions and 1,068 deletions.
400 changes: 199 additions & 201 deletions api/go/ht-vocab.go

Large diffs are not rendered by default.

590 changes: 294 additions & 296 deletions api/py/ht-vocab.py

Large diffs are not rendered by default.

20 changes: 8 additions & 12 deletions api/vocab/ht-property-classes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ PropertyClasses:
PropDeviceDescription:
class: "ht:prop:device:description"
title: "Description"
description: "Device product description"
description: "Device product description" # also TD.Description
PropDeviceEnabledDisabled:
class: "ht:prop:device:enabled-disabled"
title: "Enabled/Disabled"
Expand All @@ -59,18 +59,14 @@ PropertyClasses:
class: "ht:prop:device:hardwareversion"
title: "Hardware version"
description: ""
PropDeviceManufacturer:
class: "ht:prop:device:manufacturer"
title: "Manufacturer"
PropDeviceMake:
class: "ht:prop:device:make"
title: "Make"
description: "Device manufacturer"
PropDeviceModel:
class: "ht:prop:device:model"
title: "Model"
description: "Device model"
PropDeviceName:
class: "ht:prop:device:name"
title: "Name"
description: "Device name"
PropDevicePollinterval:
class: "ht:prop:device:pollinterval"
title: "Polling interval"
Expand All @@ -88,6 +84,10 @@ PropertyClasses:
sleeping: "Sleeping"
title: "Status"
description: "Device status; alive, awake, dead, sleeping"
PropDeviceTitle:
class: "ht:prop:device:title"
title: "Title"
description: "Device friendly title"

# ht:prop:electric group of electrical properties
PropElectric:
Expand Down Expand Up @@ -279,10 +279,6 @@ PropertyClasses:
class: "ht:prop:net:address"
title: "Address"
description: "Network address"
PropNetConnected:
class: "ht:prop:net:connected"
title: "Connected"
description: "Connected or disconnected status"
PropNetConnection:
class: "ht:prop:net:connection"
title: "Connection"
Expand Down
32 changes: 29 additions & 3 deletions bindings/hiveoview/src/session/ClientSession.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ func (cs *ClientSession) onConnectChange(stat transports.HubTransportStatus) {
func (cs *ClientSession) onEvent(msg *things.ThingValue) {
cs.mux.RLock()
defer cs.mux.RUnlock()
// FIXME: HOW TO UPDATE THE VIEW MODEL?
// a: each view has its own viewmodel that is updated
// is this reimplementing vue?
// each view can reload if their data changes

if msg.Name == transports.EventNameTD {
// TODO: send the current view a TD changed event
// TODO: how are the other views that use the TD updated?
_ = cs.SendSSE(msg.Name, string(msg.Data))
} else if msg.Name == transports.EventNameProps {
// TODO: send the current view a properties changed event, if applicable
// TODO: how are the other views that display the value updated?
} else {
// value changed event
// TODO: send the current view a value changed event, if applicable
// TODO: how are the other views that display the value updated?
}
slog.Info("received event", "id", msg.Name)
// TODO: determine how events are consumed
// SSE's usually expect an HTML snippet, not json data
//_ = cs.SendSSE(msg.Name, string(msg.Data))
Expand Down Expand Up @@ -168,6 +186,8 @@ func (cs *ClientSession) SendSSE(event string, content string) error {

// NewClientSession creates a new client session for the given Hub connection
// Intended for use by the session manager.
// This subscribes to events for configured agents.
//
// note that expiry is a placeholder for now used to refresh auth token.
// it should be obtained from the login authentication/refresh.
func NewClientSession(sessionID string, hc *hubclient.HubClient, remoteAddr string) *ClientSession {
Expand All @@ -186,11 +206,17 @@ func NewClientSession(sessionID string, hc *hubclient.HubClient, remoteAddr stri
// restore the session data model
stateCl := stateclient.NewStateClient(hc)
found, err := stateCl.Get(hc.ClientID(), &cs.clientModel)
_ = found
_ = err
if found {
// subscribe
if len(cs.clientModel.Agents) > 0 {
for _, agent := range cs.clientModel.Agents {
// subscribe to TD and value events
err = hc.SubEvents(agent, "", "")
}
} else {
// no agent set so subscribe to all agents
err = hc.SubEvents("", "", "")
}

// subscribe to configured agents
return &cs
}
5 changes: 4 additions & 1 deletion bindings/hiveoview/src/session/SessionManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ type SessionManager struct {
tokenKP keys.IHiveKey
}

// ActivateNewSession (re)activates a new session using a connected hub client.
// ActivateNewSession (re)activates a new session for a newly connected hub client.
//
// If a session exists, it will be closed and removed first.
// This requests a session token for storing in the cookie to allow re-opening the session
// after the browser pages is closed or refreshed, without requiring a new password.
// This replaces the session cookie in the browser with a new cookie.
// This subscribes to events of configured agents.
//
// This returns the new session instance or nil with an error if a session could not be created.
func (sm *SessionManager) ActivateNewSession(
Expand All @@ -69,6 +70,7 @@ func (sm *SessionManager) ActivateNewSession(
if sessionID == "" {
sessionID = uuid.NewString()
}
// create a session for this connection and subscribe to events from configured agents.
cs = NewClientSession(sessionID, hc, r.RemoteAddr)
sm.mux.Lock()
sm.sessions[sessionID] = cs
Expand Down Expand Up @@ -125,6 +127,7 @@ func (sm *SessionManager) Close(sessionID string) error {
func (sm *SessionManager) ConnectWithPassword(loginID string, password string) (*hubclient.HubClient, error) {
hc := hubclient.NewHubClient(sm.hubURL, loginID, sm.caCert, sm.core)
err := hc.ConnectWithPassword(password)
// subscribe to updates
return hc, err
}

Expand Down
17 changes: 8 additions & 9 deletions bindings/hiveoview/src/views/thing/editConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package thing

import (
"encoding/json"
"fmt"
"github.com/go-chi/chi/v5"
"github.com/hiveot/hub/bindings/hiveoview/src/session"
"github.com/hiveot/hub/bindings/hiveoview/src/views/app"
Expand Down Expand Up @@ -89,14 +88,14 @@ func PostThingConfig(w http.ResponseWriter, r *http.Request) {
}

_ = mySession.SendSSE("notify", "success: Configuration '"+propKey+"' updated")

// read the updated config value and update the UI fragments
cl := historyclient.NewReadHistoryClient(hc)
tvs, err := cl.GetLatest(agentID, thingID, []string{propKey})
propAddr := fmt.Sprintf("%s/%s/%s", agentID, thingID, propKey)
propVal := fmt.Sprintf("%.100s", tvs[propKey].Data)
slog.Info("Updated value of prop", "propAddr", propAddr, "propVal", propVal)
mySession.SendSSE(propAddr, propVal)
//
//// read the updated config value and update the UI fragments
//cl := historyclient.NewReadHistoryClient(hc)
//tvs, err := cl.GetLatest(agentID, thingID, []string{propKey})
//propAddr := fmt.Sprintf("%s/%s/%s", agentID, thingID, propKey)
//propVal := fmt.Sprintf("%.100s", tvs[propKey].Data)
//slog.Info("Updated value of prop", "propAddr", propAddr, "propVal", propVal)
//mySession.SendSSE(propAddr, propVal)

w.WriteHeader(http.StatusOK)

Expand Down
8 changes: 7 additions & 1 deletion bindings/hiveoview/src/views/thing/thingDetails.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type DetailsTemplateData struct {
AgentID string
ThingID string
MakeModel string
Name string
DeviceType string
TD things.TD
// These lists are sorted by property/event/action name
Expand Down Expand Up @@ -88,7 +89,7 @@ func RenderThingDetails(w http.ResponseWriter, r *http.Request) {

// get the value of a make & model properties, if they exist
// TODO: this is a bit of a pain to do. Is this a common problem?
makeID, _ := thingData.TD.GetPropertyOfType(vocab.PropDeviceManufacturer)
makeID, _ := thingData.TD.GetPropertyOfType(vocab.PropDeviceMake)
modelID, _ := thingData.TD.GetPropertyOfType(vocab.PropDeviceModel)
makeValue := propMap.Get(makeID)
modelValue := propMap.Get(modelID)
Expand All @@ -98,6 +99,11 @@ func RenderThingDetails(w http.ResponseWriter, r *http.Request) {
if modelValue != nil {
thingData.MakeModel = thingData.MakeModel + string(modelValue.Data)
}
// use name from configuration if available. Fall back to title.
thingData.Name = thingData.Values.ToString(vocab.PropDeviceTitle)
if thingData.Name == "" {
thingData.Name = thingData.TD.Title
}
}
}
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions bindings/hiveoview/src/views/thing/thingDetails.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
<h4>{{.Thing.TD.Title}}</h4>
</summary>
<ul class="h-grid-table details-header">
<label for="deviceType">Device Type:</label>
<input id="deviceType" readonly style="margin: 0; text-overflow: ellipsis; "
placeholder="{{.Thing.TD.GetAtTypeVocab}}"/>
<label for="deviceName">Title:</label>
<input id="deviceName" readonly style="margin: 0; text-overflow: ellipsis; "
placeholder="{{.Thing.Name}}"/>

<label for="manufacturer">Device Make & Model:</label>
<label for="manufacturer">Device Description:</label>
<input id="manufacturer" type="text" readonly
style="margin: 0; text-overflow: ellipsis;"
placeholder="{{.Thing.MakeModel}} {{.Thing.TD.Description}}"/>
Expand Down
29 changes: 18 additions & 11 deletions bindings/ipnet/service/MakeTDs.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,19 @@ func (svc *IPNetBinding) MakeBindingProps() map[string]string {
// MakeDeviceTD generates a TD document for discovered devices
func (svc *IPNetBinding) MakeDeviceTD(deviceInfo *IPDeviceInfo) *things.TD {
thingID := deviceInfo.MAC
td := things.NewTD(thingID, "Network device", vocab.ThingNet)
deviceName := deviceInfo.GetDefaultName()
td := things.NewTD(thingID, deviceName, vocab.ThingNet)

// these are configured through the configuration file.
// FIXME: what is the best way to include a port list?
prop := td.AddProperty("ports", "", "Ports", vocab.WoTDataTypeArray)
prop = td.AddPropertyAsString("IP4", vocab.PropNetIP4, "IP4 address")
prop = td.AddPropertyAsString("IP6", vocab.PropNetIP6, "IP6 address")
prop = td.AddPropertyAsString("MAC", vocab.PropNetMAC, "MAC address")
prop = td.AddPropertyAsInt("Latency", vocab.PropNetLatency, "Latency")
prop := td.AddPropertyAsString("", vocab.PropDeviceTitle, "Device name")
prop.ReadOnly = true // TODO: allow edit and save the new device name
prop = td.AddProperty("", vocab.PropNetPort, "Ports", vocab.WoTDataTypeArray)
prop = td.AddPropertyAsString("", vocab.PropNetHostname, "Hostname")
prop = td.AddPropertyAsString("", vocab.PropNetIP4, "IP4 address")
prop = td.AddPropertyAsString("", vocab.PropNetIP6, "IP6 address")
prop = td.AddPropertyAsString("", vocab.PropNetMAC, "MAC address")
prop = td.AddPropertyAsInt("", vocab.PropNetLatency, "Latency")
prop.Unit = vocab.UnitMilliSecond

return td
Expand All @@ -48,10 +52,13 @@ func (svc *IPNetBinding) MakeDeviceTD(deviceInfo *IPDeviceInfo) *things.TD {
func (svc *IPNetBinding) MakeDeviceProps(deviceInfo *IPDeviceInfo) map[string]string {
pv := make(map[string]string)
portListJSON, _ := ser.JsonMarshal(deviceInfo.Ports)
pv["ports"] = string(portListJSON)
pv["IP4"] = deviceInfo.IP4
pv["IP6"] = deviceInfo.IP6
pv["MAC"] = deviceInfo.MAC
pv["Latency"] = deviceInfo.Latency.String()
// TODO: Use the saved device name
pv[vocab.PropDeviceTitle] = deviceInfo.GetDefaultName()
pv[vocab.PropNetHostname] = deviceInfo.Hostname
pv[vocab.PropNetPort] = string(portListJSON)
pv[vocab.PropNetIP4] = deviceInfo.IP4
pv[vocab.PropNetIP6] = deviceInfo.IP6
pv[vocab.PropNetMAC] = deviceInfo.MAC
pv[vocab.PropNetLatency] = deviceInfo.Latency.String()
return pv
}
13 changes: 13 additions & 0 deletions bindings/ipnet/service/NmapAPI.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ type IPDeviceInfo struct {
Ports []IPDeviceInfoPort // Device connectable ports
}

// GetDefaultName returns the default name of the device.
// This is the hostname or IP address if not known
func (di *IPDeviceInfo) GetDefaultName() string {
name := di.Hostname
if name == "" {
name = di.IP4
}
if name == "" {
name = di.IP6
}
return name
}

// DeviceInfoPort containg discovered port number, port name, and protocol (tcp, udp, ...)
type IPDeviceInfoPort struct {
Port int
Expand Down
Binary file not shown.
Loading

0 comments on commit 6ec20ad

Please sign in to comment.