jsonjqgpsd

Using jq to count number of satellites used and in view from gpsd output


Consider this JSON:

{"class":"POLL","time":"2020-08-24T07:01:31.690Z","active":1,"tpv":[{"class":"TPV","tag":"ID8fac","device":"/dev/ttyM1","mode":3,"time":"2020-08-24T07:01:31.000Z","ept":0.005,"lat":-37.043028622,"lon":145.984996786,"alt":708.492,"epx":9.963,"epy":14.642,"epv":0.000,"speed":0.000,"climb":0.000,"eps":29.28}],"gst":[{"class":"GST","tag":"ID8fac","device":"/dev/ttyM1","time":"1970-01-01T00:00:00.000Z","rms":0.000,"major":0.000,"minor":0.000,"orient":0.000,"lat":0.000,"lon":0.000,"alt":0.000}],"sky":[{"class":"SKY","tag":"ID8fac","device":"/dev/ttyM1","xdop":0.66,"ydop":0.98,"vdop":0.00,"tdop":1.00,"hdop":0.00,"gdop":1.00,"pdop":0.00,"satellites":[{"PRN":17,"el":42,"az":137,"ss":43,"used":true},{"PRN":12,"el":27,"az":241,"ss":44,"used":true},{"PRN":24,"el":53,"az":247,"ss":46,"used":true},{"PRN":6,"el":55,"az":54,"ss":36,"used":true},{"PRN":15,"el":10,"az":307,"ss":40,"used":true},{"PRN":2,"el":31,"az":358,"ss":37,"used":true},{"PRN":28,"el":20,"az":89,"ss":35,"used":true},{"PRN":7,"el":10,"az":52,"ss":31,"used":false},{"PRN":19,"el":64,"az":148,"ss":45,"used":true},{"PRN":13,"el":10,"az":338,"ss":29,"used":false},{"PRN":15,"el":18,"az":297,"ss":33,"used":true},{"PRN":22,"el":10,"az":17,"ss":39,"used":false}]}]}

I'm interested in parsing the satellites array in the above JSON (extracted below) and returning two numbers: The number of satellites, and the number of satellites used. For example: 7 12

[
  {
    "PRN": 17,
    "el": 42,
    "az": 137,
    "ss": 43,
    "used": true
  },
  {
    "PRN": 12,
    "el": 27,
    "az": 241,
    "ss": 44,
    "used": true
  },
  {
    "PRN": 24,
    "el": 53,
    "az": 247,
    "ss": 46,
    "used": true
  },
  {
    "PRN": 6,
    "el": 55,
    "az": 54,
    "ss": 36,
    "used": true
  },
  {
    "PRN": 15,
    "el": 10,
    "az": 307,
    "ss": 40,
    "used": true
  },
  {
    "PRN": 2,
    "el": 31,
    "az": 358,
    "ss": 37,
    "used": true
  },
  {
    "PRN": 28,
    "el": 20,
    "az": 89,
    "ss": 35,
    "used": true
  },
  {
    "PRN": 7,
    "el": 10,
    "az": 52,
    "ss": 31,
    "used": false
  },
  {
    "PRN": 19,
    "el": 64,
    "az": 148,
    "ss": 45,
    "used": true
  },
  {
    "PRN": 13,
    "el": 10,
    "az": 338,
    "ss": 29,
    "used": false
  },
  {
    "PRN": 15,
    "el": 18,
    "az": 297,
    "ss": 33,
    "used": true
  },
  {
    "PRN": 22,
    "el": 10,
    "az": 17,
    "ss": 39,
    "used": false
  }
]

Currently I've only been able to figure out how to parse one value not both in one go; this is what I have:

jq -r '[ .sky[] | .satellites[]| select(.used == true )| "\( .PRN )" ] |length'

Which outputs the number of satellites used, e.g., 7.

For the sake of completeness and on the off chance it might help someone, I'm polling gpsd in bash as follows. This returns a JSON structure as seen at the start of this post:

timeout 1 grep -m1 satellites < <(printf '%s\n' '?WATCH={"enable":true,"json":true};?POLL;' | nc 127.0.0.1 2947) 

Solution

  • For the presented input:

    $ jq -r '.sky[].satellites | ( [ .[] | select(.used == true) ] | length ), length'
    9
    12
    

    Or maybe (but you could also pipe it to paste -sd" "):

    $ jq -r '.sky[].satellites | ( [ .[] | select(.used == true) ] | length | tostring) + " " + (length|tostring)'
    9 12