[{"data":1,"prerenderedAt":2054},["ShallowReactive",2],{"docs:/docs/guides/iot":3},{"id":4,"title":5,"body":6,"description":2047,"extension":2048,"meta":2049,"navigation":79,"path":2050,"seo":2051,"stem":2052,"__hash__":2053},"docs/docs/guides/iot.md","IoT & Tracking",{"type":7,"value":8,"toc":2038},"minimark",[9,13,17,22,25,29,41,343,347,357,1382,1386,1389,1913,1917,1952,1956,2013,2017,2034],[10,11,5],"h1",{"id":12},"iot-tracking",[14,15,16],"p",{},"Build real-time IoT applications and tracking systems with NoLag.",[18,19,21],"h2",{"id":20},"overview","Overview",[14,23,24],{},"NoLag is ideal for IoT applications that require real-time data streaming from devices. Whether you're tracking vehicles, monitoring sensors, or controlling smart devices, NoLag provides the low-latency infrastructure you need.",[18,26,28],{"id":27},"app-setup","App Setup",[14,30,31,32,36,37,40],{},"Rooms never exist implicitly, so create the app, its room, and its actors before any device or dashboard connects. Give each vehicle its own ",[33,34,35],"code",{},"device"," actor and the dashboard its own ",[33,38,39],{},"user"," actor: publishers never receive their own messages, so a dashboard that reused a device's token would never see that device's updates.",[42,43,44],"code-tabs",{},[45,46,52],"pre",{"className":47,"code":48,"filename":49,"language":50,"meta":51,"style":51},"language-typescript shiki shiki-themes github-light github-dark","import { NoLagApi } from '@nolag/js-sdk'\n\nconst api = new NoLagApi(process.env.NOLAG_API_KEY) // nlg_live_...\n\n// 1. Create the app and declare the topics it allows. The slug that comes back\n//    has a random suffix, so read it from the response.\nconst app = await api.apps.create({\n  name: 'Fleet Tracker',\n  slug: 'fleet-tracker',\n  topics: ['location', 'telemetry'],\n})\nconsole.log(app.slug) // e.g. \"fleet-tracker-a3f9\": this is your APP_SLUG\n\n// 2. Create the room. Room slugs are kept exactly as you supply them.\nawait api.rooms.create(app.appId, { name: 'Vehicles', slug: 'vehicles' })\n\n// 3. One device actor per vehicle, and a user actor for the dashboard.\n//    Each access token is shown once; keep them.\nconst truck42 = await api.actors.create({ name: 'truck-42', actorType: 'device', externalId: 'truck-42' })\nconst dashboard = await api.actors.create({ name: 'fleet-dashboard', actorType: 'user' })\nconsole.log(truck42.accessToken, dashboard.accessToken)\n","Setup (server side, once)","typescript","",[33,53,54,74,81,114,119,125,131,153,165,176,194,200,215,220,226,252,257,263,269,305,333],{"__ignoreMap":51},[55,56,59,63,67,70],"span",{"class":57,"line":58},"line",1,[55,60,62],{"class":61},"szBVR","import",[55,64,66],{"class":65},"sVt8B"," { NoLagApi } ",[55,68,69],{"class":61},"from",[55,71,73],{"class":72},"sZZnC"," '@nolag/js-sdk'\n",[55,75,77],{"class":57,"line":76},2,[55,78,80],{"emptyLinePlaceholder":79},true,"\n",[55,82,84,87,91,94,97,101,104,107,110],{"class":57,"line":83},3,[55,85,86],{"class":61},"const",[55,88,90],{"class":89},"sj4cs"," api",[55,92,93],{"class":61}," =",[55,95,96],{"class":61}," new",[55,98,100],{"class":99},"sScJk"," NoLagApi",[55,102,103],{"class":65},"(process.env.",[55,105,106],{"class":89},"NOLAG_API_KEY",[55,108,109],{"class":65},") ",[55,111,113],{"class":112},"sJ8bj","// nlg_live_...\n",[55,115,117],{"class":57,"line":116},4,[55,118,80],{"emptyLinePlaceholder":79},[55,120,122],{"class":57,"line":121},5,[55,123,124],{"class":112},"// 1. Create the app and declare the topics it allows. The slug that comes back\n",[55,126,128],{"class":57,"line":127},6,[55,129,130],{"class":112},"//    has a random suffix, so read it from the response.\n",[55,132,134,136,139,141,144,147,150],{"class":57,"line":133},7,[55,135,86],{"class":61},[55,137,138],{"class":89}," app",[55,140,93],{"class":61},[55,142,143],{"class":61}," await",[55,145,146],{"class":65}," api.apps.",[55,148,149],{"class":99},"create",[55,151,152],{"class":65},"({\n",[55,154,156,159,162],{"class":57,"line":155},8,[55,157,158],{"class":65},"  name: ",[55,160,161],{"class":72},"'Fleet Tracker'",[55,163,164],{"class":65},",\n",[55,166,168,171,174],{"class":57,"line":167},9,[55,169,170],{"class":65},"  slug: ",[55,172,173],{"class":72},"'fleet-tracker'",[55,175,164],{"class":65},[55,177,179,182,185,188,191],{"class":57,"line":178},10,[55,180,181],{"class":65},"  topics: [",[55,183,184],{"class":72},"'location'",[55,186,187],{"class":65},", ",[55,189,190],{"class":72},"'telemetry'",[55,192,193],{"class":65},"],\n",[55,195,197],{"class":57,"line":196},11,[55,198,199],{"class":65},"})\n",[55,201,203,206,209,212],{"class":57,"line":202},12,[55,204,205],{"class":65},"console.",[55,207,208],{"class":99},"log",[55,210,211],{"class":65},"(app.slug) ",[55,213,214],{"class":112},"// e.g. \"fleet-tracker-a3f9\": this is your APP_SLUG\n",[55,216,218],{"class":57,"line":217},13,[55,219,80],{"emptyLinePlaceholder":79},[55,221,223],{"class":57,"line":222},14,[55,224,225],{"class":112},"// 2. Create the room. Room slugs are kept exactly as you supply them.\n",[55,227,229,232,235,237,240,243,246,249],{"class":57,"line":228},15,[55,230,231],{"class":61},"await",[55,233,234],{"class":65}," api.rooms.",[55,236,149],{"class":99},[55,238,239],{"class":65},"(app.appId, { name: ",[55,241,242],{"class":72},"'Vehicles'",[55,244,245],{"class":65},", slug: ",[55,247,248],{"class":72},"'vehicles'",[55,250,251],{"class":65}," })\n",[55,253,255],{"class":57,"line":254},16,[55,256,80],{"emptyLinePlaceholder":79},[55,258,260],{"class":57,"line":259},17,[55,261,262],{"class":112},"// 3. One device actor per vehicle, and a user actor for the dashboard.\n",[55,264,266],{"class":57,"line":265},18,[55,267,268],{"class":112},"//    Each access token is shown once; keep them.\n",[55,270,272,274,277,279,281,284,286,289,292,295,298,301,303],{"class":57,"line":271},19,[55,273,86],{"class":61},[55,275,276],{"class":89}," truck42",[55,278,93],{"class":61},[55,280,143],{"class":61},[55,282,283],{"class":65}," api.actors.",[55,285,149],{"class":99},[55,287,288],{"class":65},"({ name: ",[55,290,291],{"class":72},"'truck-42'",[55,293,294],{"class":65},", actorType: ",[55,296,297],{"class":72},"'device'",[55,299,300],{"class":65},", externalId: ",[55,302,291],{"class":72},[55,304,251],{"class":65},[55,306,308,310,313,315,317,319,321,323,326,328,331],{"class":57,"line":307},20,[55,309,86],{"class":61},[55,311,312],{"class":89}," dashboard",[55,314,93],{"class":61},[55,316,143],{"class":61},[55,318,283],{"class":65},[55,320,149],{"class":99},[55,322,288],{"class":65},[55,324,325],{"class":72},"'fleet-dashboard'",[55,327,294],{"class":65},[55,329,330],{"class":72},"'user'",[55,332,251],{"class":65},[55,334,336,338,340],{"class":57,"line":335},21,[55,337,205],{"class":65},[55,339,208],{"class":99},[55,341,342],{"class":65},"(truck42.accessToken, dashboard.accessToken)\n",[18,344,346],{"id":345},"fleet-tracking-example","Fleet Tracking Example",[14,348,349,350,352,353,356],{},"The dashboard connects with its ",[33,351,39],{}," actor and subscribes to every vehicle's updates in the ",[33,354,355],{},"vehicles"," room.",[42,358,359,834,999],{},[45,360,363],{"className":47,"code":361,"filename":362,"language":50,"meta":51,"style":51},"import { NoLag } from '@nolag/js-sdk'\n\nconst APP_SLUG = 'fleet-tracker-a3f9' // the slug returned when you created the app\n\ninterface Location {\n  vehicleId: string\n  latitude: number\n  longitude: number\n  heading: number\n  speed: number\n  timestamp: number\n}\n\ninterface Telemetry {\n  vehicleId: string\n  fuelLevel: number\n  engineStatus: string\n  batteryVoltage: number\n}\n\nconst client = NoLag('dashboard_access_token')\nclient.on('error', (err) => console.error(err)) // unknown_topic etc. arrive here\nawait client.connect()\n\nconst fleet = client.setApp(APP_SLUG).setRoom('vehicles')\n\n// Subscribe to all vehicle updates\nfleet.subscribe('location')\nfleet.subscribe('telemetry')\n\n// Handle location updates. Payloads arrive as `unknown`; name the shape you expect.\nfleet.on\u003CLocation>('location', (data) => {\n  updateMapMarker(data.vehicleId, {\n    lat: data.latitude,\n    lng: data.longitude,\n    heading: data.heading,\n    speed: data.speed\n  })\n})\n\n// Handle telemetry data\nfleet.on\u003CTelemetry>('telemetry', (data) => {\n  updateVehicleStatus(data.vehicleId, {\n    fuel: data.fuelLevel,\n    engine: data.engineStatus,\n    battery: data.batteryVoltage\n  })\n})\n","TypeScript",[33,364,365,376,380,395,399,410,422,432,441,450,459,468,473,477,486,494,503,512,521,525,529,550,587,601,606,638,643,649,664,677,682,688,717,726,732,738,744,750,756,761,766,772,798,806,812,818,824,829],{"__ignoreMap":51},[55,366,367,369,372,374],{"class":57,"line":58},[55,368,62],{"class":61},[55,370,371],{"class":65}," { NoLag } ",[55,373,69],{"class":61},[55,375,73],{"class":72},[55,377,378],{"class":57,"line":76},[55,379,80],{"emptyLinePlaceholder":79},[55,381,382,384,387,389,392],{"class":57,"line":83},[55,383,86],{"class":61},[55,385,386],{"class":89}," APP_SLUG",[55,388,93],{"class":61},[55,390,391],{"class":72}," 'fleet-tracker-a3f9'",[55,393,394],{"class":112}," // the slug returned when you created the app\n",[55,396,397],{"class":57,"line":116},[55,398,80],{"emptyLinePlaceholder":79},[55,400,401,404,407],{"class":57,"line":121},[55,402,403],{"class":61},"interface",[55,405,406],{"class":99}," Location",[55,408,409],{"class":65}," {\n",[55,411,412,416,419],{"class":57,"line":127},[55,413,415],{"class":414},"s4XuR","  vehicleId",[55,417,418],{"class":61},":",[55,420,421],{"class":89}," string\n",[55,423,424,427,429],{"class":57,"line":133},[55,425,426],{"class":414},"  latitude",[55,428,418],{"class":61},[55,430,431],{"class":89}," number\n",[55,433,434,437,439],{"class":57,"line":155},[55,435,436],{"class":414},"  longitude",[55,438,418],{"class":61},[55,440,431],{"class":89},[55,442,443,446,448],{"class":57,"line":167},[55,444,445],{"class":414},"  heading",[55,447,418],{"class":61},[55,449,431],{"class":89},[55,451,452,455,457],{"class":57,"line":178},[55,453,454],{"class":414},"  speed",[55,456,418],{"class":61},[55,458,431],{"class":89},[55,460,461,464,466],{"class":57,"line":196},[55,462,463],{"class":414},"  timestamp",[55,465,418],{"class":61},[55,467,431],{"class":89},[55,469,470],{"class":57,"line":202},[55,471,472],{"class":65},"}\n",[55,474,475],{"class":57,"line":217},[55,476,80],{"emptyLinePlaceholder":79},[55,478,479,481,484],{"class":57,"line":222},[55,480,403],{"class":61},[55,482,483],{"class":99}," Telemetry",[55,485,409],{"class":65},[55,487,488,490,492],{"class":57,"line":228},[55,489,415],{"class":414},[55,491,418],{"class":61},[55,493,421],{"class":89},[55,495,496,499,501],{"class":57,"line":254},[55,497,498],{"class":414},"  fuelLevel",[55,500,418],{"class":61},[55,502,431],{"class":89},[55,504,505,508,510],{"class":57,"line":259},[55,506,507],{"class":414},"  engineStatus",[55,509,418],{"class":61},[55,511,421],{"class":89},[55,513,514,517,519],{"class":57,"line":265},[55,515,516],{"class":414},"  batteryVoltage",[55,518,418],{"class":61},[55,520,431],{"class":89},[55,522,523],{"class":57,"line":271},[55,524,472],{"class":65},[55,526,527],{"class":57,"line":307},[55,528,80],{"emptyLinePlaceholder":79},[55,530,531,533,536,538,541,544,547],{"class":57,"line":335},[55,532,86],{"class":61},[55,534,535],{"class":89}," client",[55,537,93],{"class":61},[55,539,540],{"class":99}," NoLag",[55,542,543],{"class":65},"(",[55,545,546],{"class":72},"'dashboard_access_token'",[55,548,549],{"class":65},")\n",[55,551,553,556,559,561,564,567,570,572,575,578,581,584],{"class":57,"line":552},22,[55,554,555],{"class":65},"client.",[55,557,558],{"class":99},"on",[55,560,543],{"class":65},[55,562,563],{"class":72},"'error'",[55,565,566],{"class":65},", (",[55,568,569],{"class":414},"err",[55,571,109],{"class":65},[55,573,574],{"class":61},"=>",[55,576,577],{"class":65}," console.",[55,579,580],{"class":99},"error",[55,582,583],{"class":65},"(err)) ",[55,585,586],{"class":112},"// unknown_topic etc. arrive here\n",[55,588,590,592,595,598],{"class":57,"line":589},23,[55,591,231],{"class":61},[55,593,594],{"class":65}," client.",[55,596,597],{"class":99},"connect",[55,599,600],{"class":65},"()\n",[55,602,604],{"class":57,"line":603},24,[55,605,80],{"emptyLinePlaceholder":79},[55,607,609,611,614,616,618,621,623,626,629,632,634,636],{"class":57,"line":608},25,[55,610,86],{"class":61},[55,612,613],{"class":89}," fleet",[55,615,93],{"class":61},[55,617,594],{"class":65},[55,619,620],{"class":99},"setApp",[55,622,543],{"class":65},[55,624,625],{"class":89},"APP_SLUG",[55,627,628],{"class":65},").",[55,630,631],{"class":99},"setRoom",[55,633,543],{"class":65},[55,635,248],{"class":72},[55,637,549],{"class":65},[55,639,641],{"class":57,"line":640},26,[55,642,80],{"emptyLinePlaceholder":79},[55,644,646],{"class":57,"line":645},27,[55,647,648],{"class":112},"// Subscribe to all vehicle updates\n",[55,650,652,655,658,660,662],{"class":57,"line":651},28,[55,653,654],{"class":65},"fleet.",[55,656,657],{"class":99},"subscribe",[55,659,543],{"class":65},[55,661,184],{"class":72},[55,663,549],{"class":65},[55,665,667,669,671,673,675],{"class":57,"line":666},29,[55,668,654],{"class":65},[55,670,657],{"class":99},[55,672,543],{"class":65},[55,674,190],{"class":72},[55,676,549],{"class":65},[55,678,680],{"class":57,"line":679},30,[55,681,80],{"emptyLinePlaceholder":79},[55,683,685],{"class":57,"line":684},31,[55,686,687],{"class":112},"// Handle location updates. Payloads arrive as `unknown`; name the shape you expect.\n",[55,689,691,693,695,698,701,704,706,708,711,713,715],{"class":57,"line":690},32,[55,692,654],{"class":65},[55,694,558],{"class":99},[55,696,697],{"class":65},"\u003C",[55,699,700],{"class":99},"Location",[55,702,703],{"class":65},">(",[55,705,184],{"class":72},[55,707,566],{"class":65},[55,709,710],{"class":414},"data",[55,712,109],{"class":65},[55,714,574],{"class":61},[55,716,409],{"class":65},[55,718,720,723],{"class":57,"line":719},33,[55,721,722],{"class":99},"  updateMapMarker",[55,724,725],{"class":65},"(data.vehicleId, {\n",[55,727,729],{"class":57,"line":728},34,[55,730,731],{"class":65},"    lat: data.latitude,\n",[55,733,735],{"class":57,"line":734},35,[55,736,737],{"class":65},"    lng: data.longitude,\n",[55,739,741],{"class":57,"line":740},36,[55,742,743],{"class":65},"    heading: data.heading,\n",[55,745,747],{"class":57,"line":746},37,[55,748,749],{"class":65},"    speed: data.speed\n",[55,751,753],{"class":57,"line":752},38,[55,754,755],{"class":65},"  })\n",[55,757,759],{"class":57,"line":758},39,[55,760,199],{"class":65},[55,762,764],{"class":57,"line":763},40,[55,765,80],{"emptyLinePlaceholder":79},[55,767,769],{"class":57,"line":768},41,[55,770,771],{"class":112},"// Handle telemetry data\n",[55,773,775,777,779,781,784,786,788,790,792,794,796],{"class":57,"line":774},42,[55,776,654],{"class":65},[55,778,558],{"class":99},[55,780,697],{"class":65},[55,782,783],{"class":99},"Telemetry",[55,785,703],{"class":65},[55,787,190],{"class":72},[55,789,566],{"class":65},[55,791,710],{"class":414},[55,793,109],{"class":65},[55,795,574],{"class":61},[55,797,409],{"class":65},[55,799,801,804],{"class":57,"line":800},43,[55,802,803],{"class":99},"  updateVehicleStatus",[55,805,725],{"class":65},[55,807,809],{"class":57,"line":808},44,[55,810,811],{"class":65},"    fuel: data.fuelLevel,\n",[55,813,815],{"class":57,"line":814},45,[55,816,817],{"class":65},"    engine: data.engineStatus,\n",[55,819,821],{"class":57,"line":820},46,[55,822,823],{"class":65},"    battery: data.batteryVoltage\n",[55,825,827],{"class":57,"line":826},47,[55,828,755],{"class":65},[55,830,832],{"class":57,"line":831},48,[55,833,199],{"class":65},[45,835,840],{"className":836,"code":837,"filename":838,"language":839,"meta":51,"style":51},"language-python shiki shiki-themes github-light github-dark","from nolag import NoLag\n\nAPP_SLUG = 'fleet-tracker-a3f9'  # the slug returned when you created the app\n\nclient = NoLag('dashboard_access_token')\nclient.on('error', lambda err: print(err))  # unknown_topic etc. arrive here\nawait client.connect()\n\nfleet = client.set_app(APP_SLUG).set_room('vehicles')\n\n# Subscribe to all vehicle updates\nawait fleet.subscribe('location')\nawait fleet.subscribe('telemetry')\n\n# Handle location updates\ndef on_location(data, meta):\n    update_map_marker(data['vehicleId'], {\n        'lat': data['latitude'],\n        'lng': data['longitude'],\n        'heading': data['heading'],\n        'speed': data['speed']\n    })\n\n# Handle telemetry data\ndef on_telemetry(data, meta):\n    update_vehicle_status(data['vehicleId'], {\n        'fuel': data['fuelLevel'],\n        'engine': data['engineStatus'],\n        'battery': data['batteryVoltage']\n    })\n\nfleet.on('location', on_location)\nfleet.on('telemetry', on_telemetry)\n","Python","python",[33,841,842,847,851,856,860,865,870,875,879,884,888,893,898,903,907,912,917,922,927,932,937,942,947,951,956,961,966,971,976,981,985,989,994],{"__ignoreMap":51},[55,843,844],{"class":57,"line":58},[55,845,846],{},"from nolag import NoLag\n",[55,848,849],{"class":57,"line":76},[55,850,80],{"emptyLinePlaceholder":79},[55,852,853],{"class":57,"line":83},[55,854,855],{},"APP_SLUG = 'fleet-tracker-a3f9'  # the slug returned when you created the app\n",[55,857,858],{"class":57,"line":116},[55,859,80],{"emptyLinePlaceholder":79},[55,861,862],{"class":57,"line":121},[55,863,864],{},"client = NoLag('dashboard_access_token')\n",[55,866,867],{"class":57,"line":127},[55,868,869],{},"client.on('error', lambda err: print(err))  # unknown_topic etc. arrive here\n",[55,871,872],{"class":57,"line":133},[55,873,874],{},"await client.connect()\n",[55,876,877],{"class":57,"line":155},[55,878,80],{"emptyLinePlaceholder":79},[55,880,881],{"class":57,"line":167},[55,882,883],{},"fleet = client.set_app(APP_SLUG).set_room('vehicles')\n",[55,885,886],{"class":57,"line":178},[55,887,80],{"emptyLinePlaceholder":79},[55,889,890],{"class":57,"line":196},[55,891,892],{},"# Subscribe to all vehicle updates\n",[55,894,895],{"class":57,"line":202},[55,896,897],{},"await fleet.subscribe('location')\n",[55,899,900],{"class":57,"line":217},[55,901,902],{},"await fleet.subscribe('telemetry')\n",[55,904,905],{"class":57,"line":222},[55,906,80],{"emptyLinePlaceholder":79},[55,908,909],{"class":57,"line":228},[55,910,911],{},"# Handle location updates\n",[55,913,914],{"class":57,"line":254},[55,915,916],{},"def on_location(data, meta):\n",[55,918,919],{"class":57,"line":259},[55,920,921],{},"    update_map_marker(data['vehicleId'], {\n",[55,923,924],{"class":57,"line":265},[55,925,926],{},"        'lat': data['latitude'],\n",[55,928,929],{"class":57,"line":271},[55,930,931],{},"        'lng': data['longitude'],\n",[55,933,934],{"class":57,"line":307},[55,935,936],{},"        'heading': data['heading'],\n",[55,938,939],{"class":57,"line":335},[55,940,941],{},"        'speed': data['speed']\n",[55,943,944],{"class":57,"line":552},[55,945,946],{},"    })\n",[55,948,949],{"class":57,"line":589},[55,950,80],{"emptyLinePlaceholder":79},[55,952,953],{"class":57,"line":603},[55,954,955],{},"# Handle telemetry data\n",[55,957,958],{"class":57,"line":608},[55,959,960],{},"def on_telemetry(data, meta):\n",[55,962,963],{"class":57,"line":640},[55,964,965],{},"    update_vehicle_status(data['vehicleId'], {\n",[55,967,968],{"class":57,"line":645},[55,969,970],{},"        'fuel': data['fuelLevel'],\n",[55,972,973],{"class":57,"line":651},[55,974,975],{},"        'engine': data['engineStatus'],\n",[55,977,978],{"class":57,"line":666},[55,979,980],{},"        'battery': data['batteryVoltage']\n",[55,982,983],{"class":57,"line":679},[55,984,946],{},[55,986,987],{"class":57,"line":684},[55,988,80],{"emptyLinePlaceholder":79},[55,990,991],{"class":57,"line":690},[55,992,993],{},"fleet.on('location', on_location)\n",[55,995,996],{"class":57,"line":719},[55,997,998],{},"fleet.on('telemetry', on_telemetry)\n",[45,1000,1005],{"className":1001,"code":1002,"filename":1003,"language":1004,"meta":51,"style":51},"language-go shiki shiki-themes github-light github-dark","package main\n\nimport (\n    \"log\"\n\n    nolag \"github.com/NoLagApp/go-sdk\"\n)\n\nconst appSlug = \"fleet-tracker-a3f9\" // the slug returned when you created the app\n\n// Numbers in a payload arrive as the msgpack decoder's sized types (int8, uint16,\n// int64, float64, ...), never as int, so convert through a type switch rather\n// than asserting a single type. A speed of 42 and a speed of 42.5 decode differently.\nfunc num(v any) float64 {\n    switch n := v.(type) {\n    case float64:\n        return n\n    case float32:\n        return float64(n)\n    case int8:\n        return float64(n)\n    case int16:\n        return float64(n)\n    case int32:\n        return float64(n)\n    case int64:\n        return float64(n)\n    case uint8:\n        return float64(n)\n    case uint16:\n        return float64(n)\n    case uint32:\n        return float64(n)\n    case uint64:\n        return float64(n)\n    }\n    return 0\n}\n\nfunc main() {\n    client := nolag.New(\"dashboard_access_token\")\n    client.OnError(func(err *nolag.ServerError) {\n        log.Println(err) // unknown_topic etc. arrive here\n    })\n    if err := client.Connect(); err != nil {\n        log.Fatal(err)\n    }\n\n    fleet := client.SetApp(appSlug).SetRoom(\"vehicles\")\n\n    // Subscribe to all vehicle updates with handlers\n    fleet.Subscribe(\"location\", func(data any, meta nolag.MessageMeta) {\n        d, _ := data.(map[string]any)\n        vehicleID, _ := d[\"vehicleId\"].(string)\n        updateMapMarker(vehicleID, MapPosition{\n            Lat:     num(d[\"latitude\"]),\n            Lng:     num(d[\"longitude\"]),\n            Heading: num(d[\"heading\"]),\n            Speed:   num(d[\"speed\"]),\n        })\n    })\n\n    fleet.Subscribe(\"telemetry\", func(data any, meta nolag.MessageMeta) {\n        d, _ := data.(map[string]any)\n        vehicleID, _ := d[\"vehicleId\"].(string)\n        engine, _ := d[\"engineStatus\"].(string)\n        updateVehicleStatus(vehicleID, VehicleStatus{\n            Fuel:    num(d[\"fuelLevel\"]),\n            Engine:  engine,\n            Battery: num(d[\"batteryVoltage\"]),\n        })\n    })\n\n    select {} // keep the process alive\n}\n","Go","go",[33,1006,1007,1012,1016,1021,1026,1030,1035,1039,1043,1048,1052,1057,1062,1067,1072,1077,1082,1087,1092,1097,1102,1106,1111,1115,1120,1124,1129,1133,1138,1142,1147,1151,1156,1160,1165,1169,1174,1179,1183,1187,1192,1197,1202,1207,1211,1216,1221,1225,1229,1235,1240,1246,1252,1258,1264,1270,1276,1282,1288,1294,1300,1305,1310,1316,1321,1326,1332,1338,1344,1350,1356,1361,1366,1371,1377],{"__ignoreMap":51},[55,1008,1009],{"class":57,"line":58},[55,1010,1011],{},"package main\n",[55,1013,1014],{"class":57,"line":76},[55,1015,80],{"emptyLinePlaceholder":79},[55,1017,1018],{"class":57,"line":83},[55,1019,1020],{},"import (\n",[55,1022,1023],{"class":57,"line":116},[55,1024,1025],{},"    \"log\"\n",[55,1027,1028],{"class":57,"line":121},[55,1029,80],{"emptyLinePlaceholder":79},[55,1031,1032],{"class":57,"line":127},[55,1033,1034],{},"    nolag \"github.com/NoLagApp/go-sdk\"\n",[55,1036,1037],{"class":57,"line":133},[55,1038,549],{},[55,1040,1041],{"class":57,"line":155},[55,1042,80],{"emptyLinePlaceholder":79},[55,1044,1045],{"class":57,"line":167},[55,1046,1047],{},"const appSlug = \"fleet-tracker-a3f9\" // the slug returned when you created the app\n",[55,1049,1050],{"class":57,"line":178},[55,1051,80],{"emptyLinePlaceholder":79},[55,1053,1054],{"class":57,"line":196},[55,1055,1056],{},"// Numbers in a payload arrive as the msgpack decoder's sized types (int8, uint16,\n",[55,1058,1059],{"class":57,"line":202},[55,1060,1061],{},"// int64, float64, ...), never as int, so convert through a type switch rather\n",[55,1063,1064],{"class":57,"line":217},[55,1065,1066],{},"// than asserting a single type. A speed of 42 and a speed of 42.5 decode differently.\n",[55,1068,1069],{"class":57,"line":222},[55,1070,1071],{},"func num(v any) float64 {\n",[55,1073,1074],{"class":57,"line":228},[55,1075,1076],{},"    switch n := v.(type) {\n",[55,1078,1079],{"class":57,"line":254},[55,1080,1081],{},"    case float64:\n",[55,1083,1084],{"class":57,"line":259},[55,1085,1086],{},"        return n\n",[55,1088,1089],{"class":57,"line":265},[55,1090,1091],{},"    case float32:\n",[55,1093,1094],{"class":57,"line":271},[55,1095,1096],{},"        return float64(n)\n",[55,1098,1099],{"class":57,"line":307},[55,1100,1101],{},"    case int8:\n",[55,1103,1104],{"class":57,"line":335},[55,1105,1096],{},[55,1107,1108],{"class":57,"line":552},[55,1109,1110],{},"    case int16:\n",[55,1112,1113],{"class":57,"line":589},[55,1114,1096],{},[55,1116,1117],{"class":57,"line":603},[55,1118,1119],{},"    case int32:\n",[55,1121,1122],{"class":57,"line":608},[55,1123,1096],{},[55,1125,1126],{"class":57,"line":640},[55,1127,1128],{},"    case int64:\n",[55,1130,1131],{"class":57,"line":645},[55,1132,1096],{},[55,1134,1135],{"class":57,"line":651},[55,1136,1137],{},"    case uint8:\n",[55,1139,1140],{"class":57,"line":666},[55,1141,1096],{},[55,1143,1144],{"class":57,"line":679},[55,1145,1146],{},"    case uint16:\n",[55,1148,1149],{"class":57,"line":684},[55,1150,1096],{},[55,1152,1153],{"class":57,"line":690},[55,1154,1155],{},"    case uint32:\n",[55,1157,1158],{"class":57,"line":719},[55,1159,1096],{},[55,1161,1162],{"class":57,"line":728},[55,1163,1164],{},"    case uint64:\n",[55,1166,1167],{"class":57,"line":734},[55,1168,1096],{},[55,1170,1171],{"class":57,"line":740},[55,1172,1173],{},"    }\n",[55,1175,1176],{"class":57,"line":746},[55,1177,1178],{},"    return 0\n",[55,1180,1181],{"class":57,"line":752},[55,1182,472],{},[55,1184,1185],{"class":57,"line":758},[55,1186,80],{"emptyLinePlaceholder":79},[55,1188,1189],{"class":57,"line":763},[55,1190,1191],{},"func main() {\n",[55,1193,1194],{"class":57,"line":768},[55,1195,1196],{},"    client := nolag.New(\"dashboard_access_token\")\n",[55,1198,1199],{"class":57,"line":774},[55,1200,1201],{},"    client.OnError(func(err *nolag.ServerError) {\n",[55,1203,1204],{"class":57,"line":800},[55,1205,1206],{},"        log.Println(err) // unknown_topic etc. arrive here\n",[55,1208,1209],{"class":57,"line":808},[55,1210,946],{},[55,1212,1213],{"class":57,"line":814},[55,1214,1215],{},"    if err := client.Connect(); err != nil {\n",[55,1217,1218],{"class":57,"line":820},[55,1219,1220],{},"        log.Fatal(err)\n",[55,1222,1223],{"class":57,"line":826},[55,1224,1173],{},[55,1226,1227],{"class":57,"line":831},[55,1228,80],{"emptyLinePlaceholder":79},[55,1230,1232],{"class":57,"line":1231},49,[55,1233,1234],{},"    fleet := client.SetApp(appSlug).SetRoom(\"vehicles\")\n",[55,1236,1238],{"class":57,"line":1237},50,[55,1239,80],{"emptyLinePlaceholder":79},[55,1241,1243],{"class":57,"line":1242},51,[55,1244,1245],{},"    // Subscribe to all vehicle updates with handlers\n",[55,1247,1249],{"class":57,"line":1248},52,[55,1250,1251],{},"    fleet.Subscribe(\"location\", func(data any, meta nolag.MessageMeta) {\n",[55,1253,1255],{"class":57,"line":1254},53,[55,1256,1257],{},"        d, _ := data.(map[string]any)\n",[55,1259,1261],{"class":57,"line":1260},54,[55,1262,1263],{},"        vehicleID, _ := d[\"vehicleId\"].(string)\n",[55,1265,1267],{"class":57,"line":1266},55,[55,1268,1269],{},"        updateMapMarker(vehicleID, MapPosition{\n",[55,1271,1273],{"class":57,"line":1272},56,[55,1274,1275],{},"            Lat:     num(d[\"latitude\"]),\n",[55,1277,1279],{"class":57,"line":1278},57,[55,1280,1281],{},"            Lng:     num(d[\"longitude\"]),\n",[55,1283,1285],{"class":57,"line":1284},58,[55,1286,1287],{},"            Heading: num(d[\"heading\"]),\n",[55,1289,1291],{"class":57,"line":1290},59,[55,1292,1293],{},"            Speed:   num(d[\"speed\"]),\n",[55,1295,1297],{"class":57,"line":1296},60,[55,1298,1299],{},"        })\n",[55,1301,1303],{"class":57,"line":1302},61,[55,1304,946],{},[55,1306,1308],{"class":57,"line":1307},62,[55,1309,80],{"emptyLinePlaceholder":79},[55,1311,1313],{"class":57,"line":1312},63,[55,1314,1315],{},"    fleet.Subscribe(\"telemetry\", func(data any, meta nolag.MessageMeta) {\n",[55,1317,1319],{"class":57,"line":1318},64,[55,1320,1257],{},[55,1322,1324],{"class":57,"line":1323},65,[55,1325,1263],{},[55,1327,1329],{"class":57,"line":1328},66,[55,1330,1331],{},"        engine, _ := d[\"engineStatus\"].(string)\n",[55,1333,1335],{"class":57,"line":1334},67,[55,1336,1337],{},"        updateVehicleStatus(vehicleID, VehicleStatus{\n",[55,1339,1341],{"class":57,"line":1340},68,[55,1342,1343],{},"            Fuel:    num(d[\"fuelLevel\"]),\n",[55,1345,1347],{"class":57,"line":1346},69,[55,1348,1349],{},"            Engine:  engine,\n",[55,1351,1353],{"class":57,"line":1352},70,[55,1354,1355],{},"            Battery: num(d[\"batteryVoltage\"]),\n",[55,1357,1359],{"class":57,"line":1358},71,[55,1360,1299],{},[55,1362,1364],{"class":57,"line":1363},72,[55,1365,946],{},[55,1367,1369],{"class":57,"line":1368},73,[55,1370,80],{"emptyLinePlaceholder":79},[55,1372,1374],{"class":57,"line":1373},74,[55,1375,1376],{},"    select {} // keep the process alive\n",[55,1378,1380],{"class":57,"line":1379},75,[55,1381,472],{},[18,1383,1385],{"id":1384},"device-publishing","Device Publishing",[14,1387,1388],{},"On the IoT device, connect with that device's own actor and publish updates at regular intervals:",[42,1390,1391,1613,1748],{},[45,1392,1394],{"className":47,"code":1393,"filename":362,"language":50,"meta":51,"style":51},"import { NoLag } from '@nolag/js-sdk'\n\nconst APP_SLUG = 'fleet-tracker-a3f9' // the slug returned when you created the app\nconst DEVICE_ID = 'truck-42'\n\n// On the IoT device: its own device actor\nconst client = NoLag('truck_42_access_token')\nawait client.connect()\n\nconst device = client.setApp(APP_SLUG).setRoom('vehicles')\n\n// Publish location updates every 5 seconds\nsetInterval(() => {\n  const location = gps.getLocation()\n\n  device.emit('location', {\n    vehicleId: DEVICE_ID,\n    latitude: location.lat,\n    longitude: location.lng,\n    heading: location.heading,\n    speed: location.speed,\n    timestamp: Date.now()\n  })\n}, 5000)\n",[33,1395,1396,1406,1410,1422,1434,1438,1443,1460,1470,1474,1501,1505,1510,1522,1540,1544,1559,1569,1574,1579,1584,1589,1599,1603],{"__ignoreMap":51},[55,1397,1398,1400,1402,1404],{"class":57,"line":58},[55,1399,62],{"class":61},[55,1401,371],{"class":65},[55,1403,69],{"class":61},[55,1405,73],{"class":72},[55,1407,1408],{"class":57,"line":76},[55,1409,80],{"emptyLinePlaceholder":79},[55,1411,1412,1414,1416,1418,1420],{"class":57,"line":83},[55,1413,86],{"class":61},[55,1415,386],{"class":89},[55,1417,93],{"class":61},[55,1419,391],{"class":72},[55,1421,394],{"class":112},[55,1423,1424,1426,1429,1431],{"class":57,"line":116},[55,1425,86],{"class":61},[55,1427,1428],{"class":89}," DEVICE_ID",[55,1430,93],{"class":61},[55,1432,1433],{"class":72}," 'truck-42'\n",[55,1435,1436],{"class":57,"line":121},[55,1437,80],{"emptyLinePlaceholder":79},[55,1439,1440],{"class":57,"line":127},[55,1441,1442],{"class":112},"// On the IoT device: its own device actor\n",[55,1444,1445,1447,1449,1451,1453,1455,1458],{"class":57,"line":133},[55,1446,86],{"class":61},[55,1448,535],{"class":89},[55,1450,93],{"class":61},[55,1452,540],{"class":99},[55,1454,543],{"class":65},[55,1456,1457],{"class":72},"'truck_42_access_token'",[55,1459,549],{"class":65},[55,1461,1462,1464,1466,1468],{"class":57,"line":155},[55,1463,231],{"class":61},[55,1465,594],{"class":65},[55,1467,597],{"class":99},[55,1469,600],{"class":65},[55,1471,1472],{"class":57,"line":167},[55,1473,80],{"emptyLinePlaceholder":79},[55,1475,1476,1478,1481,1483,1485,1487,1489,1491,1493,1495,1497,1499],{"class":57,"line":178},[55,1477,86],{"class":61},[55,1479,1480],{"class":89}," device",[55,1482,93],{"class":61},[55,1484,594],{"class":65},[55,1486,620],{"class":99},[55,1488,543],{"class":65},[55,1490,625],{"class":89},[55,1492,628],{"class":65},[55,1494,631],{"class":99},[55,1496,543],{"class":65},[55,1498,248],{"class":72},[55,1500,549],{"class":65},[55,1502,1503],{"class":57,"line":196},[55,1504,80],{"emptyLinePlaceholder":79},[55,1506,1507],{"class":57,"line":202},[55,1508,1509],{"class":112},"// Publish location updates every 5 seconds\n",[55,1511,1512,1515,1518,1520],{"class":57,"line":217},[55,1513,1514],{"class":99},"setInterval",[55,1516,1517],{"class":65},"(() ",[55,1519,574],{"class":61},[55,1521,409],{"class":65},[55,1523,1524,1527,1530,1532,1535,1538],{"class":57,"line":222},[55,1525,1526],{"class":61},"  const",[55,1528,1529],{"class":89}," location",[55,1531,93],{"class":61},[55,1533,1534],{"class":65}," gps.",[55,1536,1537],{"class":99},"getLocation",[55,1539,600],{"class":65},[55,1541,1542],{"class":57,"line":228},[55,1543,80],{"emptyLinePlaceholder":79},[55,1545,1546,1549,1552,1554,1556],{"class":57,"line":254},[55,1547,1548],{"class":65},"  device.",[55,1550,1551],{"class":99},"emit",[55,1553,543],{"class":65},[55,1555,184],{"class":72},[55,1557,1558],{"class":65},", {\n",[55,1560,1561,1564,1567],{"class":57,"line":259},[55,1562,1563],{"class":65},"    vehicleId: ",[55,1565,1566],{"class":89},"DEVICE_ID",[55,1568,164],{"class":65},[55,1570,1571],{"class":57,"line":265},[55,1572,1573],{"class":65},"    latitude: location.lat,\n",[55,1575,1576],{"class":57,"line":271},[55,1577,1578],{"class":65},"    longitude: location.lng,\n",[55,1580,1581],{"class":57,"line":307},[55,1582,1583],{"class":65},"    heading: location.heading,\n",[55,1585,1586],{"class":57,"line":335},[55,1587,1588],{"class":65},"    speed: location.speed,\n",[55,1590,1591,1594,1597],{"class":57,"line":552},[55,1592,1593],{"class":65},"    timestamp: Date.",[55,1595,1596],{"class":99},"now",[55,1598,600],{"class":65},[55,1600,1601],{"class":57,"line":589},[55,1602,755],{"class":65},[55,1604,1605,1608,1611],{"class":57,"line":603},[55,1606,1607],{"class":65},"}, ",[55,1609,1610],{"class":89},"5000",[55,1612,549],{"class":65},[45,1614,1616],{"className":836,"code":1615,"filename":838,"language":839,"meta":51,"style":51},"import asyncio\nimport time\nfrom nolag import NoLag\n\nAPP_SLUG = 'fleet-tracker-a3f9'  # the slug returned when you created the app\nDEVICE_ID = 'truck-42'\n\n# On the IoT device: its own device actor\nclient = NoLag('truck_42_access_token')\nawait client.connect()\n\ndevice = client.set_app(APP_SLUG).set_room('vehicles')\n\n# Publish location updates every 5 seconds\nasync def publish_location():\n    while True:\n        location = gps.get_location()\n\n        await device.emit('location', {\n            'vehicleId': DEVICE_ID,\n            'latitude': location.lat,\n            'longitude': location.lng,\n            'heading': location.heading,\n            'speed': location.speed,\n            'timestamp': int(time.time() * 1000)\n        })\n\n        await asyncio.sleep(5)\n",[33,1617,1618,1623,1628,1632,1636,1640,1645,1649,1654,1659,1663,1667,1672,1676,1681,1686,1691,1696,1700,1705,1710,1715,1720,1725,1730,1735,1739,1743],{"__ignoreMap":51},[55,1619,1620],{"class":57,"line":58},[55,1621,1622],{},"import asyncio\n",[55,1624,1625],{"class":57,"line":76},[55,1626,1627],{},"import time\n",[55,1629,1630],{"class":57,"line":83},[55,1631,846],{},[55,1633,1634],{"class":57,"line":116},[55,1635,80],{"emptyLinePlaceholder":79},[55,1637,1638],{"class":57,"line":121},[55,1639,855],{},[55,1641,1642],{"class":57,"line":127},[55,1643,1644],{},"DEVICE_ID = 'truck-42'\n",[55,1646,1647],{"class":57,"line":133},[55,1648,80],{"emptyLinePlaceholder":79},[55,1650,1651],{"class":57,"line":155},[55,1652,1653],{},"# On the IoT device: its own device actor\n",[55,1655,1656],{"class":57,"line":167},[55,1657,1658],{},"client = NoLag('truck_42_access_token')\n",[55,1660,1661],{"class":57,"line":178},[55,1662,874],{},[55,1664,1665],{"class":57,"line":196},[55,1666,80],{"emptyLinePlaceholder":79},[55,1668,1669],{"class":57,"line":202},[55,1670,1671],{},"device = client.set_app(APP_SLUG).set_room('vehicles')\n",[55,1673,1674],{"class":57,"line":217},[55,1675,80],{"emptyLinePlaceholder":79},[55,1677,1678],{"class":57,"line":222},[55,1679,1680],{},"# Publish location updates every 5 seconds\n",[55,1682,1683],{"class":57,"line":228},[55,1684,1685],{},"async def publish_location():\n",[55,1687,1688],{"class":57,"line":254},[55,1689,1690],{},"    while True:\n",[55,1692,1693],{"class":57,"line":259},[55,1694,1695],{},"        location = gps.get_location()\n",[55,1697,1698],{"class":57,"line":265},[55,1699,80],{"emptyLinePlaceholder":79},[55,1701,1702],{"class":57,"line":271},[55,1703,1704],{},"        await device.emit('location', {\n",[55,1706,1707],{"class":57,"line":307},[55,1708,1709],{},"            'vehicleId': DEVICE_ID,\n",[55,1711,1712],{"class":57,"line":335},[55,1713,1714],{},"            'latitude': location.lat,\n",[55,1716,1717],{"class":57,"line":552},[55,1718,1719],{},"            'longitude': location.lng,\n",[55,1721,1722],{"class":57,"line":589},[55,1723,1724],{},"            'heading': location.heading,\n",[55,1726,1727],{"class":57,"line":603},[55,1728,1729],{},"            'speed': location.speed,\n",[55,1731,1732],{"class":57,"line":608},[55,1733,1734],{},"            'timestamp': int(time.time() * 1000)\n",[55,1736,1737],{"class":57,"line":640},[55,1738,1299],{},[55,1740,1741],{"class":57,"line":645},[55,1742,80],{"emptyLinePlaceholder":79},[55,1744,1745],{"class":57,"line":651},[55,1746,1747],{},"        await asyncio.sleep(5)\n",[45,1749,1751],{"className":1001,"code":1750,"filename":1003,"language":1004,"meta":51,"style":51},"package main\n\nimport (\n    \"log\"\n    \"time\"\n\n    nolag \"github.com/NoLagApp/go-sdk\"\n)\n\nconst appSlug = \"fleet-tracker-a3f9\" // the slug returned when you created the app\nconst deviceID = \"truck-42\"\n\nfunc main() {\n    // On the IoT device: its own device actor\n    client := nolag.New(\"truck_42_access_token\")\n    if err := client.Connect(); err != nil {\n        log.Fatal(err)\n    }\n\n    device := client.SetApp(appSlug).SetRoom(\"vehicles\")\n\n    // Publish location updates every 5 seconds\n    ticker := time.NewTicker(5 * time.Second)\n    for range ticker.C {\n        location := gps.GetLocation()\n\n        device.Emit(\"location\", map[string]any{\n            \"vehicleId\": deviceID,\n            \"latitude\":  location.Lat,\n            \"longitude\": location.Lng,\n            \"heading\":   location.Heading,\n            \"speed\":     location.Speed,\n            \"timestamp\": time.Now().UnixMilli(),\n        })\n    }\n}\n",[33,1752,1753,1757,1761,1765,1769,1774,1778,1782,1786,1790,1794,1799,1803,1807,1812,1817,1821,1825,1829,1833,1838,1842,1847,1852,1857,1862,1866,1871,1876,1881,1886,1891,1896,1901,1905,1909],{"__ignoreMap":51},[55,1754,1755],{"class":57,"line":58},[55,1756,1011],{},[55,1758,1759],{"class":57,"line":76},[55,1760,80],{"emptyLinePlaceholder":79},[55,1762,1763],{"class":57,"line":83},[55,1764,1020],{},[55,1766,1767],{"class":57,"line":116},[55,1768,1025],{},[55,1770,1771],{"class":57,"line":121},[55,1772,1773],{},"    \"time\"\n",[55,1775,1776],{"class":57,"line":127},[55,1777,80],{"emptyLinePlaceholder":79},[55,1779,1780],{"class":57,"line":133},[55,1781,1034],{},[55,1783,1784],{"class":57,"line":155},[55,1785,549],{},[55,1787,1788],{"class":57,"line":167},[55,1789,80],{"emptyLinePlaceholder":79},[55,1791,1792],{"class":57,"line":178},[55,1793,1047],{},[55,1795,1796],{"class":57,"line":196},[55,1797,1798],{},"const deviceID = \"truck-42\"\n",[55,1800,1801],{"class":57,"line":202},[55,1802,80],{"emptyLinePlaceholder":79},[55,1804,1805],{"class":57,"line":217},[55,1806,1191],{},[55,1808,1809],{"class":57,"line":222},[55,1810,1811],{},"    // On the IoT device: its own device actor\n",[55,1813,1814],{"class":57,"line":228},[55,1815,1816],{},"    client := nolag.New(\"truck_42_access_token\")\n",[55,1818,1819],{"class":57,"line":254},[55,1820,1215],{},[55,1822,1823],{"class":57,"line":259},[55,1824,1220],{},[55,1826,1827],{"class":57,"line":265},[55,1828,1173],{},[55,1830,1831],{"class":57,"line":271},[55,1832,80],{"emptyLinePlaceholder":79},[55,1834,1835],{"class":57,"line":307},[55,1836,1837],{},"    device := client.SetApp(appSlug).SetRoom(\"vehicles\")\n",[55,1839,1840],{"class":57,"line":335},[55,1841,80],{"emptyLinePlaceholder":79},[55,1843,1844],{"class":57,"line":552},[55,1845,1846],{},"    // Publish location updates every 5 seconds\n",[55,1848,1849],{"class":57,"line":589},[55,1850,1851],{},"    ticker := time.NewTicker(5 * time.Second)\n",[55,1853,1854],{"class":57,"line":603},[55,1855,1856],{},"    for range ticker.C {\n",[55,1858,1859],{"class":57,"line":608},[55,1860,1861],{},"        location := gps.GetLocation()\n",[55,1863,1864],{"class":57,"line":640},[55,1865,80],{"emptyLinePlaceholder":79},[55,1867,1868],{"class":57,"line":645},[55,1869,1870],{},"        device.Emit(\"location\", map[string]any{\n",[55,1872,1873],{"class":57,"line":651},[55,1874,1875],{},"            \"vehicleId\": deviceID,\n",[55,1877,1878],{"class":57,"line":666},[55,1879,1880],{},"            \"latitude\":  location.Lat,\n",[55,1882,1883],{"class":57,"line":679},[55,1884,1885],{},"            \"longitude\": location.Lng,\n",[55,1887,1888],{"class":57,"line":684},[55,1889,1890],{},"            \"heading\":   location.Heading,\n",[55,1892,1893],{"class":57,"line":690},[55,1894,1895],{},"            \"speed\":     location.Speed,\n",[55,1897,1898],{"class":57,"line":719},[55,1899,1900],{},"            \"timestamp\": time.Now().UnixMilli(),\n",[55,1902,1903],{"class":57,"line":728},[55,1904,1299],{},[55,1906,1907],{"class":57,"line":734},[55,1908,1173],{},[55,1910,1911],{"class":57,"line":740},[55,1912,472],{},[18,1914,1916],{"id":1915},"use-cases","Use Cases",[1918,1919,1920,1928,1934,1940,1946],"ul",{},[1921,1922,1923,1927],"li",{},[1924,1925,1926],"strong",{},"Fleet management"," - Track vehicles, deliveries, and drivers",[1921,1929,1930,1933],{},[1924,1931,1932],{},"Asset tracking"," - Monitor equipment and inventory location",[1921,1935,1936,1939],{},[1924,1937,1938],{},"Sensor networks"," - Collect data from environmental sensors",[1921,1941,1942,1945],{},[1924,1943,1944],{},"Smart home"," - Control and monitor IoT devices",[1921,1947,1948,1951],{},[1924,1949,1950],{},"Wearables"," - Stream health and fitness data",[18,1953,1955],{"id":1954},"best-practices","Best Practices",[1918,1957,1958,1964,1967,1975,2005],{},[1921,1959,1960,1961,1963],{},"Use one ",[33,1962,35],{}," actor per device, and a separate actor for anything that needs to see what the devices publish",[1921,1965,1966],{},"Batch telemetry data to reduce message frequency; the broker accepts 50 publishes per second per connection",[1921,1968,1969,1970],{},"QoS 1, the default, acknowledges each publish on the broker hop. It is not an end-to-end guarantee, so deduplicate on a reading's timestamp if a message must not be applied twice. See ",[1971,1972,1974],"a",{"href":1973},"/docs/concepts/qos","Quality of Service",[1921,1976,1977,1978,1981,1982,1985,1986,1989,1990,1993,1994,1989,1997,2000,2001,2004],{},"Reconnection is built in. Every SDK reconnects automatically after a drop (",[33,1979,1980],{},"reconnect"," defaults to true) and the broker restores the connection's subscriptions. Tune the cadence for unreliable networks instead of writing your own loop: ",[33,1983,1984],{},"reconnectInterval"," in JavaScript (milliseconds, with backoff up to 30 seconds), ",[33,1987,1988],{},"reconnect_interval"," and ",[33,1991,1992],{},"max_reconnect_attempts"," in Python, ",[33,1995,1996],{},"ReconnectInterval",[33,1998,1999],{},"MaxReconnectAttempts"," in Go (",[33,2002,2003],{},"-1"," retries forever). The default is 5 seconds and 10 attempts",[1921,2006,2007,2008,2012],{},"Consider data retention and historical storage needs. NoLag delivers live readings and does not keep a history for you; a ",[1971,2009,2011],{"href":2010},"/docs/concepts/webhooks","trigger webhook"," receives every publish and can write it to your own store",[18,2014,2016],{"id":2015},"next-steps","Next Steps",[1918,2018,2019,2023,2029],{},[1921,2020,2021],{},[1971,2022,1974],{"href":1973},[1921,2024,2025],{},[1971,2026,2028],{"href":2027},"/docs/authentication","Device Authentication",[1921,2030,2031],{},[1971,2032,2033],{"href":2010},"Webhooks",[2035,2036,2037],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":51,"searchDepth":76,"depth":76,"links":2039},[2040,2041,2042,2043,2044,2045,2046],{"id":20,"depth":76,"text":21},{"id":27,"depth":76,"text":28},{"id":345,"depth":76,"text":346},{"id":1384,"depth":76,"text":1385},{"id":1915,"depth":76,"text":1916},{"id":1954,"depth":76,"text":1955},{"id":2015,"depth":76,"text":2016},"Build IoT applications and real-time tracking systems with NoLag.","md",{},"/docs/guides/iot",{"title":5,"description":2047},"docs/guides/iot","kQ_4Mr2B62ZWle46x-vxDEkPOeTKkX1u2NG7jHQteq4",1789869419987]