Skip to content

Commit 5f02268

Browse files
committed
feat(cisco/spaces): add support for webex events
1 parent dfadff2 commit 5f02268

File tree

4 files changed

+137
-12
lines changed

4 files changed

+137
-12
lines changed

drivers/cisco/dna_spaces.cr

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ class Cisco::DNASpaces < PlaceOS::Driver
183183
end
184184

185185
# MAC Address => Location (including user)
186-
@locations : Hash(String, DeviceLocationUpdate | IotTelemetry) = {} of String => DeviceLocationUpdate | IotTelemetry
186+
@locations : Hash(String, DeviceLocationUpdate | IotTelemetry | WebexTelemetryUpdate) = {} of String => DeviceLocationUpdate | IotTelemetry | WebexTelemetryUpdate
187187
@loc_lock : Mutex = Mutex.new
188-
@devices : Hash(String, IotTelemetry) = {} of String => IotTelemetry
188+
@devices : Hash(String, IotTelemetry | WebexTelemetryUpdate) = {} of String => IotTelemetry | WebexTelemetryUpdate
189189
@dev_lock : Mutex = Mutex.new
190190

191191
def locations
@@ -292,14 +292,14 @@ class Cisco::DNASpaces < PlaceOS::Driver
292292
when DeviceEntry
293293
# This is used entirely for
294294
@description_lock.synchronize { payload.location.descriptions(@location_descriptions) }
295-
when DeviceLocationUpdate, IotTelemetry
295+
when DeviceLocationUpdate, IotTelemetry, WebexTelemetryUpdate
296296
device_mac = format_mac(payload.device.mac_address)
297297

298298
# we want timestamps in seconds
299299
payload.last_seen = payload.last_seen // 1000
300300

301-
if payload.is_a?(IotTelemetry)
302-
iot_payload = payload.as(IotTelemetry)
301+
if payload.is_a?(IotTelemetry) || payload.is_a?(WebexTelemetryUpdate)
302+
iot_payload = payload.as(IotTelemetry | WebexTelemetryUpdate)
303303
self[device_mac] = iot_payload
304304
devices { |dev| dev[device_mac] = iot_payload }
305305

@@ -436,6 +436,7 @@ class Cisco::DNASpaces < PlaceOS::Driver
436436

437437
macs.compact_map { |mac|
438438
if location = locate_mac(mac)
439+
next if location.is_a?(WebexTelemetryUpdate)
439440
if location.last_seen > location_max_age
440441
# we update the mac_address to a formatted version
441442
location.device.mac_address = mac
@@ -455,7 +456,7 @@ class Cisco::DNASpaces < PlaceOS::Driver
455456
"y" => location.y_pos,
456457
"lon" => lon,
457458
"lat" => lat,
458-
"s2_cell_id" => S2Cells::LatLon.new(lat, lon).to_token(@s2_level),
459+
"s2_cell_id" => S2Cells::CellId.from_lat_lng(lat, lon).parent(@s2_level).to_token,
459460
"mac" => location.device.mac_address,
460461
"variance" => location.unc,
461462
"last_seen" => location.last_seen,
@@ -592,7 +593,8 @@ class Cisco::DNASpaces < PlaceOS::Driver
592593
end
593594
end
594595

595-
locations.map do |loc|
596+
locations.compact_map do |loc|
597+
next if loc.is_a?(WebexTelemetryUpdate)
596598
lat = loc.latitude
597599
lon = loc.longitude
598600

@@ -603,7 +605,7 @@ class Cisco::DNASpaces < PlaceOS::Driver
603605
y: loc.y_pos - offset_y,
604606
lon: lon,
605607
lat: lat,
606-
s2_cell_id: S2Cells::LatLon.new(lat, lon).to_token(@s2_level),
608+
s2_cell_id: S2Cells::CellId.from_lat_lng(lat, lon).parent(@s2_level).to_token,
607609
mac: loc.device.mac_address,
608610
variance: loc.unc,
609611
last_seen: loc.last_seen,

drivers/cisco/dna_spaces/events.cr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ abstract class Cisco::DNASpaces::Events
2323
"DEVICE_COUNT" => DeviceCountWrapper,
2424
"BLE_RSSI_UPDATE" => BleRssiUpdateWrapper,
2525
"IOT_TELEMETRY" => IotTelemetryWrapper,
26+
"WEBEX_TELEMETRY" => WebexTelemetryUpdateWrapper,
2627
}
2728

2829
@[JSON::Field(key: "recordUid")]
@@ -132,3 +133,10 @@ class Cisco::DNASpaces::IotTelemetryWrapper < Cisco::DNASpaces::Events
132133
@[JSON::Field(key: "iotTelemetry")]
133134
getter payload : IotTelemetry
134135
end
136+
137+
class Cisco::DNASpaces::WebexTelemetryUpdateWrapper < Cisco::DNASpaces::Events
138+
getter eventType : String = "WEBEX_TELEMETRY"
139+
140+
@[JSON::Field(key: "webexTelemetryUpdate")]
141+
getter payload : WebexTelemetryUpdate
142+
end

drivers/cisco/dna_spaces/sensor_interface.cr

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class Cisco::DNASpaces
55
}
66
NO_MATCH = [] of Interface::Sensor::Detail
77

8-
protected def to_sensors(zone_id, filter, device : IotTelemetry)
8+
protected def to_sensors(zone_id, filter, device : IotTelemetry | WebexTelemetryUpdate)
99
if level_loc = device.location_mappings["FLOOR"]?
1010
if floorplan = @floorplan_mappings[level_loc]?
1111
building = floorplan["building"]?.as(String?)
@@ -22,6 +22,7 @@ class Cisco::DNASpaces
2222

2323
IOT_SENSORS.each do |type|
2424
next if filter && filter != type
25+
# next if device.is_a?(WebexTelemetryUpdate) && !filter.in?({SensorType::PeopleCount, SensorType::Presence})
2526

2627
unit = nil
2728
value = nil
@@ -96,7 +97,7 @@ class Cisco::DNASpaces
9697
device = devices { |dev| dev[mac]? }
9798
return NO_MATCH unless device
9899
return case device
99-
in IotTelemetry
100+
in IotTelemetry, WebexTelemetryUpdate
100101
to_sensors(zone_id, filter, device)
101102
in DeviceLocationUpdate
102103
NO_MATCH
@@ -106,7 +107,7 @@ class Cisco::DNASpaces
106107
device_values = devices &.values
107108
device_values.flat_map do |device|
108109
case device
109-
in IotTelemetry
110+
in IotTelemetry, WebexTelemetryUpdate
110111
to_sensors(zone_id, filter, device)
111112
in DeviceLocationUpdate
112113
NO_MATCH
@@ -124,7 +125,7 @@ class Cisco::DNASpaces
124125

125126
filter = SensorType.parse(id)
126127
case device
127-
in IotTelemetry
128+
in IotTelemetry, WebexTelemetryUpdate
128129
to_sensors(nil, filter, device).first?
129130
in DeviceLocationUpdate
130131
end
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
require "./events"
2+
require "./location"
3+
4+
# https://partners.dnaspaces.io/docs/v1/basic/c-dnas-firehose-api-references.html#!c-firehose-proto-buf-doc.html
5+
class Cisco::DNASpaces::WebexDeviceInfo
6+
include JSON::Serializable
7+
8+
@[JSON::Field(key: "deviceId")]
9+
getter id : String
10+
11+
@[JSON::Field(key: "macAddress")]
12+
property mac_address : String
13+
14+
@[JSON::Field(key: "ipAddress")]
15+
getter ip_address : String
16+
17+
# these fields are named to be compatible with the IoT field names
18+
@[JSON::Field(key: "product")]
19+
getter type : String
20+
21+
@[JSON::Field(key: "displayName")]
22+
getter device_name : String
23+
24+
@[JSON::Field(key: "serialNumber")]
25+
getter serial_number : String
26+
27+
@[JSON::Field(key: "softwareVersion")]
28+
getter software_version : String
29+
30+
@[JSON::Field(key: "workspaceId")]
31+
getter workspace_id : String
32+
33+
@[JSON::Field(key: "orgId")]
34+
getter org_id : String
35+
end
36+
37+
struct Cisco::DNASpaces::WebexTelemetry
38+
include JSON::Serializable
39+
40+
getter presence : Bool?
41+
42+
@[JSON::Field(key: "peopleCount")]
43+
getter count : Int32?
44+
end
45+
46+
class Cisco::DNASpaces::WebexTelemetryUpdate
47+
include JSON::Serializable
48+
49+
@[JSON::Field(key: "deviceInfo")]
50+
getter device : WebexDeviceInfo
51+
getter location : Location
52+
getter telemetries : Array(WebexTelemetry) { [] of WebexTelemetry }
53+
54+
@[JSON::Field(ignore: true)]
55+
getter people_count : Int32 do
56+
telemetries.compact_map(&.count).first? || 0
57+
end
58+
59+
@[JSON::Field(ignore: true)]
60+
getter presence : Bool do
61+
telemetries.compact_map(&.presence).first? || (people_count > 0)
62+
end
63+
64+
@[JSON::Field(ignore: true)]
65+
property last_seen : Int64 do
66+
Time.utc.to_unix_ms
67+
end
68+
69+
def has_position?
70+
true
71+
end
72+
73+
@[JSON::Field(ignore: true)]
74+
property map_id : String = ""
75+
76+
def visit_id
77+
nil
78+
end
79+
80+
def raw_user_id : String
81+
""
82+
end
83+
84+
@[JSON::Field(ignore: true)]
85+
@location_mappings : Hash(String, String)? = nil
86+
87+
# Ensure we only process these once
88+
def location_mappings : Hash(String, String)
89+
if mappings = @location_mappings
90+
mappings
91+
else
92+
mappings = location.details
93+
@location_mappings = mappings
94+
mappings
95+
end
96+
end
97+
98+
# these are unused but here for compilation reasons
99+
def humidity
100+
nil
101+
end
102+
103+
def air_quality
104+
nil
105+
end
106+
107+
def temperature
108+
nil
109+
end
110+
111+
def ambient_noise
112+
nil
113+
end
114+
end

0 commit comments

Comments
 (0)