SenseCAP T1000 support

Joshua Dunhama year ago

@axelT, yeah that totally works for me, and that would be awesome! I have an MQTT server, and I'll look into setting up a Geolocate or Elevate API account. Fingers crossed, they have a free option! ;)

axelTa year ago

Here goes! There are 2 NodeRed flows:

SenseCAP to MQTT: will get MQTT messages from SenseCAP, process them and formats a "standard" payload which is sent to an MQTT server
https://codefile.io/f/moV93KgdTj

MQTT to Traccar: receives a "standard" payload and ads the postion to Traccar using the OsmAnd protocol. This flow is generic, there is nothing specific to SenseCAP in this flow so it can be reused. Lon, lat, id and timestamp must be defined in the payload, speed, batt, altitude and hdop are optional.
https://codefile.io/f/OdPDeRl343

A few notes:

  1. IMPORTANT: you have to create a device in Traccar with the device ID as the Node EUI in SenseCAP (in all caps)
  2. You will have to add some environment variables in Node Red:
    host: hostname of your Traccar server (eg. http://198.162.1.1)
    portOsmand: OsmAnd port for Traccar (eg. 5055)
    googleToken: your Google API key
  3. You will have to edit the MQTT related nodes to set:
    SenseCAP credentials
    SenseCAP organization ID (in the topic)
    Your MQTT server details (you can also change the topics if you want of course)
  4. When location is determined using WiFi access points, the "hdop" parameter is set to 1000 and sent to Traccar. This is not necessary, I use this information in another application that reads location data from Traccar so feel free to edit the flow accordingly if you have no need for this.
  5. There are a few inject nodes for testing. The WiFi MAC addresses are dummy ones, replace them with ones that are known by Google of you want to test (fun fact, the MAC addresses in the Google API example do not work.....). Also, as SenseCAP sends longitude and latitude in separate MQTT messages, there is an inject node for each. When testing, you have to inject both one after the other (in any order). You can add debug nodes where you need to, there are none in the flows.

Hope the above is clear, good luck and let me know if it works!

Joshua Dunhama year ago

Thank you so much for your help @axelT. After a whole lot of messing around I ended up with a simpler Node-RED flow. I just did this
TTN MQTT - mqtt in
Parse for OsmAnd - formula (I borrowed a lot from your "Set URL" formula)
Create position in Traccar - http request
Debug - debug (so I can watch to make sure it works)

Now it works great to give Latitude/Longitude/Altitude/Battery. And I was able to get it into Home Assistant because it now works in Traccar!

axelTa year ago

Hi! Glad it works! Indeed, my flow was a bit complex, mainly due to the SenseCAP's MQTT messages which are not ideal.
I take it you were able to get the T1000 working with TTN. Did you have to do anything special? I have not been able to get it to work properly.... Any tips welcome, thanks!

GPS-911a year ago

There is PHP API sending data from things network to traccar https://www.reddit.com/r/Traccar/comments/e4lu6g/lora_gps_tracker_to_traccar/

Not sure if it still works.

axelTa year ago

@GPS-911, were you able to get the T1000 to work with things network? I was unable to get it working on The Things Stack (neither Community nor Cloud). Did you have any issues? Thanks!

GPS-911a year ago

I have no device, I ordered one and hopefully it should be delivered in week or two. I ordered dev kit from seed studio website.

I am very interested in Lora GPS tracker but idk how it's going to work in USA.

Joshua Dunhama year ago

@axelT I did get it to work with TTN directly but I think that's because I have a TTN gateway in my house. I noticed that accessible TTN gateways are few and far between in my city. So I might migrate to Helium, since Helium gateways seem more plentiful where I am.

Joshua Dunhama year ago

@axelT and now I'm having trouble with my node-red workflow because node-red says msg.url has been depricated. So now gotta learn what is supposed to replace that.

GPS-911a year ago

I purchased the Wio Tracker 1110 Dev Board for testing with SenseCAP on the Helium network. Although it shows online in the SenseCAP app, it fails to display location data. How can I troubleshoot this issue without a gateway?

axelTa year ago

@Joshua, which node is generating this error? The http request node? That would be very strange as the msg.url is the standard input. If you share some logs, might be able to help. Let me know!

PK3 months ago

When using this method, does Sensecap still require to pay subscription for the T1000? I understand that their server is not used, so there should be no reason for subscription. Does the device continue to transmit data even without subscription?

alphil3 months ago

Yes, the Sensecap T1000 still works even if you don't have an active subscription. However, to route the beacons emitted by the T1000 to your Traccar server, you need to use a TTN or Helium network.

PK3 months ago

Thanks @alphil.
The T1000 also seems to support Amazon Sidewalk, which claims to have better coverage than Helium. I wonder if this method possible with that network too? I don't know if Sidewalk allows us to set the webhook like Helium/TTN to our own server.

kromhout2 months ago

I have made a Node-Red to decode raw data. You can use a HTTP endpoint. msg.payload needs the raw value. Here in Holland i have KPN but i am sure it will work also with TTN. Wordmap node you can delete or installate.
Screenshot 2024-10-31 at 11-13-38 Node-RED node.electronixs.eu.png

[{"id":"4beb8d32c4bc97a5","type":"http in","z":"b965e30758bc3beb","name":"Example of KPN (Dutch lora provider)","url":"kpn","method":"post","upload":false,"swaggerDoc":"","x":190,"y":60,"wires":[["5df8889ae30f32de","81ad4b1836e2cdd5"]]},{"id":"81ad4b1836e2cdd5","type":"change","z":"b965e30758bc3beb","name":"Change Lora payload to msg.payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload[0].vs","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":120,"wires":[["00394b77d7ede445"]]},{"id":"5df8889ae30f32de","type":"http response","z":"b965e30758bc3beb","name":"Respond + Key (KPN)","statusCode":"200","headers":{"sharedSecret":"Key for KPN Lora provider"},"x":520,"y":60,"wires":[]},{"id":"00394b77d7ede445","type":"function","z":"b965e30758bc3beb","name":"Decode data V3","func":"// Sample function for multiple packet types processing\nlet rawData = msg.payload;\n\n// Basic check to ensure rawData is a string with at least the minimum length\nif (typeof rawData !== 'string' || rawData.length < 10) {\n node.error(\"Invalid payload format\", msg);\n return null;\n}\n\n// Packet Parsing\nlet packetType = rawData.substring(0, 2);\nlet output = {};\n\nswitch (packetType) {\n case \"08\":\n // Event Status Packet (as example from provided hex)\n // Extract event status from bytes 2-4\n let eventStatusHex = rawData.substring(2, 8);\n let eventStatus = parseInt(eventStatusHex, 16);\n\n output.eventStatus = {\n StartMoving: (eventStatus & 0x000001) !== 0,\n EndMovement: (eventStatus & 0x000002) !== 0,\n Motionless: (eventStatus & 0x000004) !== 0,\n Shock: (eventStatus & 0x000008) !== 0,\n Temperature: (eventStatus & 0x000010) !== 0,\n Light: (eventStatus & 0x000020) !== 0,\n SOS: (eventStatus & 0x000040) !== 0,\n PressOnce: (eventStatus & 0x000080) !== 0\n };\n\n output.packetType = \"Event Status\";\n break;\n\n case \"05\":\n // Heartbeat Packet\n let batteryHex = rawData.substring(2, 4);\n let workModeHex = rawData.substring(4, 6);\n let positioningStrategyHex = rawData.substring(6, 8);\n let sosModeHex = rawData.substring(8, 10);\n\n output.packetType = \"Heartbeat Packet\";\n output.batteryLevel = parseInt(batteryHex, 16);\n output.workMode = parseInt(workModeHex, 16);\n output.positioningStrategy = parseInt(positioningStrategyHex, 16);\n output.sosMode = sosModeHex === \"00\" ? \"Single Mode\" : \"Continuous Mode\";\n break;\n\n case \"09\":\n // Location Data Packet\n let utcHex = rawData.substring(10, 18);\n let lonHex = rawData.substring(18, 26);\n let latHex = rawData.substring(26, 34);\n let batteryLocationHex = rawData.substring(34, 36);\n\n const utcTime = parseInt(utcHex, 16);\n const longitude = parseInt(lonHex, 16) / 1000000.0;\n const latitude = parseInt(latHex, 16) / 1000000.0;\n const batteryLevelLocation = parseInt(batteryLocationHex, 16);\n\n const date = new Date(utcTime * 1000);\n const europeanTime = new Date(date.toLocaleString(\"en-US\", {timeZone: \"Europe/Berlin\"}));\n\n output.packetType = \"Location Data\";\n output.latitude = latitude;\n output.longitude = longitude;\n output.time = europeanTime.toISOString();\n output.batteryLevel = batteryLevelLocation;\n break;\n\n default:\n node.error(\"Unsupported packet ID\", msg);\n return null;\n}\n\n// Assign to the message payload\nmsg.payload = output;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":120,"wires":[["227f7ece9bd9cbf6"]]},{"id":"227f7ece9bd9cbf6","type":"function","z":"b965e30758bc3beb","name":"Split message","func":"var name = 'Demo-Tracker' //ID for traccar or name a msg.XXXXX like DEVEUI\nvar lat = msg.payload.latitude\nvar lon = msg.payload.longitude\nvar batt = msg.payload.batteryLevel\nmsg.payload = {\"name\": name, \"lat\": lat, \"lon\": lon}\nmsg.name = name\nmsg.lat = lat\nmsg.lon = lon\nmsg.batt = batt\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":660,"y":120,"wires":[["5aef9f880b516752","fb4af264393580cb","6bb8470cb66903a6","20dd6747aa80f20a"]]},{"id":"20dd6747aa80f20a","type":"http request","z":"b965e30758bc3beb","name":"Traccer Server","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.0.9:5055/?id={{{name}}}&lat={{{lat}}}&lon={{{lon}}}&batt={{{batt}}}","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":860,"y":140,"wires":[[]]},{"id":"fb4af264393580cb","type":"worldmap-tracks","z":"b965e30758bc3beb","name":"","depth":20,"layer":"combined","smooth":false,"x":870,"y":100,"wires":[["6bb8470cb66903a6"]]},{"id":"6bb8470cb66903a6","type":"worldmap","z":"b965e30758bc3beb","name":"","lat":"13.607495","lon":"12.772265","zoom":"","layer":"OSMC","cluster":"","maxage":"","usermenu":"show","layers":"show","panit":"false","panlock":"false","zoomlock":"false","hiderightclick":"false","coords":"none","showgrid":"false","showruler":"false","allowFileDrop":"false","path":"/worldmap","overlist":"DR,CO,RA,DN","maplist":"OSMG,OSMC,EsriC,EsriS,UKOS","mapname":"","mapurl":"","mapopt":"","mapwms":false,"x":1020,"y":120,"wires":[]},{"id":"5aef9f880b516752","type":"debug","z":"b965e30758bc3beb","name":"debug 278","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":890,"y":60,"wires":[]}]