diff --git a/dashboards/PROD/PROD_Pit_Crew_Brightside.json b/dashboards/PROD/PROD_Pit_Crew_Brightside.json index 65175052..f46e5629 100644 --- a/dashboards/PROD/PROD_Pit_Crew_Brightside.json +++ b/dashboards/PROD/PROD_Pit_Crew_Brightside.json @@ -23,13 +23,225 @@ "links": [], "liveNow": false, "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "P951FEA4DE68E13C5" + }, + "description": "Firmware commit (first 8 hex digits of git SHA) and dirty flag each Cascadia board reports in its CommitHash CAN message (CommitDirty = built with uncommitted changes, set at compile time). All boards should run the same clean release commit: Match = OK when a board's hash equals the most common hash AND it is clean; dirty or 'unknown' (board sent 0) = MISMATCH. Looks back 7 days regardless of dashboard time range.", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Commit" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + }, + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "unknown": { + "color": "orange", + "index": 0 + } + } + }, + { + "type": "value", + "options": { + "not seen (7d)": { + "color": "#808080", + "index": 1 + } + } + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "DIRTY": { + "color": "red", + "index": 0 + }, + "clean": { + "color": "green", + "index": 1 + } + } + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Match" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "MISMATCH": { + "color": "red", + "index": 0 + }, + "OK": { + "color": "green", + "index": 1 + } + } + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Last seen" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "mappings", + "value": [ + { + "type": "value", + "options": { + "0": { + "text": "-", + "index": 0 + } + } + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 105, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P951FEA4DE68E13C5" + }, + "query": "import \"array\"\nimport \"strings\"\n\n// Every CommitHash message in dbc/cascadia.dbc (measurement = sending board)\n// Own 7-day lookback: the dashboard range (now-1m) is too short for infrequent hash frames.\nhexd = \"0123456789abcdef\"\nnib = (n, d) => strings.substring(v: hexd, start: (n / d) % 16, end: (n / d) % 16 + 1)\nhex8 = (n) => nib(n: n, d: 268435456) + nib(n: n, d: 16777216) + nib(n: n, d: 1048576) + nib(n: n, d: 65536) + nib(n: n, d: 4096) + nib(n: n, d: 256) + nib(n: n, d: 16) + nib(n: n, d: 1)\n\nseen = from(bucket: \"CAN_prod\")\n |> range(start: -7d)\n |> filter(fn: (r) => r[\"_field\"] =~ /^(MST|HVC|DIST|DRD|MDI|STR|TEL)Commit(Hash|Dirty)$/)\n |> last()\n |> map(fn: (r) => ({Board: r._measurement, k: strings.trimPrefix(v: r._field, prefix: r._measurement), v: int(v: r._value), t: r._time}))\n |> group(columns: [\"Board\"])\n |> reduce(\n identity: {hash: -1, dirty: -1, t: time(v: 0)},\n fn: (r, accumulator) => ({\n hash: if r.k == \"CommitHash\" then r.v else accumulator.hash,\n dirty: if r.k == \"CommitDirty\" then r.v else accumulator.dirty,\n t: if r.t > accumulator.t then r.t else accumulator.t,\n }),\n )\n\nall = array.from(rows: [{Board: \"MST\", hash: -1, dirty: -1, t: time(v: 0)}, {Board: \"HVC\", hash: -1, dirty: -1, t: time(v: 0)}, {Board: \"DIST\", hash: -1, dirty: -1, t: time(v: 0)}, {Board: \"DRD\", hash: -1, dirty: -1, t: time(v: 0)}, {Board: \"MDI\", hash: -1, dirty: -1, t: time(v: 0)}, {Board: \"STR\", hash: -1, dirty: -1, t: time(v: 0)}, {Board: \"TEL\", hash: -1, dirty: -1, t: time(v: 0)}])\n\nrows = union(tables: [seen, all])\n |> group(columns: [\"Board\"])\n |> sort(columns: [\"t\"], desc: true)\n |> first(column: \"Board\")\n |> group()\n |> map(fn: (r) => ({\n Board: r.Board,\n Commit: if r.hash < 0 then \"not seen (7d)\" else if r.hash == 0 then \"unknown\" else hex8(n: r.hash),\n Dirty: if r.dirty < 0 then \"\" else if r.dirty > 0 then \"DIRTY\" else \"clean\",\n seen: r.hash >= 0,\n \"Last seen\": int(v: r.t) / 1000000,\n }))\n\n// Reference = the commit hash most boards report. OK = same hash AND clean build (dirty never matches).\ncounted = rows\n |> filter(fn: (r) => r.seen)\n |> group(columns: [\"Commit\"])\n |> count(column: \"Board\")\n |> group()\n |> sort(columns: [\"Board\"], desc: true)\ncommon = counted |> findColumn(fn: (key) => true, column: \"Commit\")\nn = counted |> findColumn(fn: (key) => true, column: \"Board\")\n// No reference when the top commit is tied (e.g. every board different): then nobody is OK.\nref = if length(arr: common) == 0 then \"\" else if length(arr: common) > 1 and n[0] == n[1] then \"\" else common[0]\n\nrows\n |> map(fn: (r) => ({\n Board: r.Board,\n Commit: r.Commit,\n Dirty: r.Dirty,\n Match: if not r.seen then \"\" else if r.Commit == ref and r.Commit != \"unknown\" and r.Dirty == \"clean\" then \"OK\" else \"MISMATCH\",\n \"Last seen\": r[\"Last seen\"],\n }))\n |> sort(columns: [\"Board\"])\n |> yield(name: \"commits\")", + "refId": "A" + } + ], + "title": "Cascadia Firmware Commit Hashes", + "type": "table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "renameByName": {}, + "indexByName": { + "Board": 0, + "Commit": 1, + "Dirty": 2, + "Match": 3, + "Last seen": 4 + } + } + } + ] + }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 0 + "y": 9 }, "id": 102, "panels": [], @@ -136,7 +348,7 @@ "h": 7, "w": 24, "x": 0, - "y": 1 + "y": 10 }, "id": 103, "options": { @@ -173,7 +385,7 @@ "h": 1, "w": 24, "x": 0, - "y": 8 + "y": 17 }, "id": 41, "panels": [], @@ -262,7 +474,7 @@ "h": 7, "w": 9, "x": 0, - "y": 9 + "y": 18 }, "id": 68, "options": { @@ -350,7 +562,7 @@ "h": 7, "w": 4, "x": 9, - "y": 9 + "y": 18 }, "id": 52, "options": { @@ -438,7 +650,7 @@ "h": 7, "w": 4, "x": 13, - "y": 9 + "y": 18 }, "id": 24, "options": { @@ -512,7 +724,7 @@ "h": 7, "w": 4, "x": 17, - "y": 9 + "y": 18 }, "id": 90, "options": { @@ -586,7 +798,7 @@ "h": 7, "w": 3, "x": 21, - "y": 9 + "y": 18 }, "id": 26, "options": { @@ -699,7 +911,7 @@ "h": 7, "w": 9, "x": 0, - "y": 16 + "y": 25 }, "id": 66, "options": { @@ -790,7 +1002,7 @@ "h": 14, "w": 15, "x": 9, - "y": 16 + "y": 25 }, "id": 30, "options": { @@ -891,7 +1103,7 @@ "h": 7, "w": 9, "x": 0, - "y": 23 + "y": 32 }, "id": 48, "options": { @@ -981,7 +1193,7 @@ "h": 7, "w": 10, "x": 0, - "y": 30 + "y": 39 }, "id": 45, "options": { @@ -1038,7 +1250,7 @@ "h": 7, "w": 4, "x": 10, - "y": 30 + "y": 39 }, "id": 69, "options": { @@ -1158,7 +1370,7 @@ "h": 7, "w": 10, "x": 14, - "y": 30 + "y": 39 }, "id": 53, "options": { @@ -1193,7 +1405,7 @@ "h": 1, "w": 24, "x": 0, - "y": 37 + "y": 46 }, "id": 6, "panels": [ @@ -1243,7 +1455,7 @@ "h": 6, "w": 4, "x": 6, - "y": 140 + "y": 149 }, "id": 27, "options": { @@ -1320,7 +1532,7 @@ "h": 6, "w": 4, "x": 10, - "y": 140 + "y": 149 }, "id": 25, "options": { @@ -1378,7 +1590,7 @@ "h": 6, "w": 4, "x": 14, - "y": 140 + "y": 149 }, "id": 46, "options": { @@ -1490,7 +1702,7 @@ "h": 6, "w": 12, "x": 0, - "y": 146 + "y": 155 }, "id": 67, "options": { @@ -1579,7 +1791,7 @@ "h": 6, "w": 12, "x": 12, - "y": 146 + "y": 155 }, "id": 28, "options": { @@ -1617,7 +1829,7 @@ "h": 1, "w": 24, "x": 0, - "y": 38 + "y": 47 }, "id": 70, "panels": [], @@ -1738,7 +1950,7 @@ "h": 7, "w": 10, "x": 0, - "y": 39 + "y": 48 }, "id": 74, "options": { @@ -1991,7 +2203,7 @@ "h": 7, "w": 11, "x": 10, - "y": 39 + "y": 48 }, "id": 75, "options": { @@ -2054,7 +2266,7 @@ "h": 7, "w": 3, "x": 21, - "y": 39 + "y": 48 }, "id": 76, "options": { @@ -2118,7 +2330,7 @@ "h": 4, "w": 4, "x": 0, - "y": 46 + "y": 55 }, "id": 77, "options": { @@ -2213,7 +2425,7 @@ "h": 4, "w": 4, "x": 4, - "y": 46 + "y": 55 }, "id": 73, "options": { @@ -2317,7 +2529,7 @@ "h": 8, "w": 4, "x": 8, - "y": 46 + "y": 55 }, "id": 97, "options": { @@ -2482,7 +2694,7 @@ "h": 8, "w": 12, "x": 12, - "y": 46 + "y": 55 }, "id": 72, "options": { @@ -2543,7 +2755,7 @@ "h": 4, "w": 4, "x": 0, - "y": 50 + "y": 59 }, "id": 78, "options": { @@ -2607,7 +2819,7 @@ "h": 4, "w": 4, "x": 4, - "y": 50 + "y": 59 }, "id": 71, "options": { @@ -3062,7 +3274,7 @@ "h": 8, "w": 24, "x": 0, - "y": 54 + "y": 63 }, "id": 79, "options": { @@ -3101,7 +3313,7 @@ "h": 1, "w": 24, "x": 0, - "y": 62 + "y": 71 }, "id": 54, "panels": [], @@ -3140,7 +3352,7 @@ "h": 6, "w": 8, "x": 0, - "y": 63 + "y": 72 }, "id": 59, "options": { @@ -3214,7 +3426,7 @@ "h": 6, "w": 8, "x": 8, - "y": 63 + "y": 72 }, "id": 65, "options": { @@ -3302,7 +3514,7 @@ "h": 6, "w": 8, "x": 16, - "y": 63 + "y": 72 }, "id": 104, "options": { @@ -3363,7 +3575,7 @@ "h": 7, "w": 5, "x": 0, - "y": 69 + "y": 78 }, "id": 58, "options": { @@ -3437,7 +3649,7 @@ "h": 7, "w": 4, "x": 5, - "y": 69 + "y": 78 }, "id": 64, "options": { @@ -3588,7 +3800,7 @@ "h": 7, "w": 7, "x": 9, - "y": 69 + "y": 78 }, "id": 89, "options": { @@ -3679,7 +3891,7 @@ "h": 7, "w": 4, "x": 16, - "y": 69 + "y": 78 }, "id": 88, "options": { @@ -3753,7 +3965,7 @@ "h": 7, "w": 4, "x": 20, - "y": 69 + "y": 78 }, "id": 87, "options": { @@ -3816,7 +4028,7 @@ "h": 8, "w": 5, "x": 0, - "y": 76 + "y": 85 }, "id": 57, "options": { @@ -3890,7 +4102,7 @@ "h": 4, "w": 6, "x": 5, - "y": 76 + "y": 85 }, "id": 84, "options": { @@ -4029,7 +4241,7 @@ "h": 8, "w": 8, "x": 11, - "y": 76 + "y": 85 }, "id": 98, "options": { @@ -4104,7 +4316,7 @@ "h": 8, "w": 5, "x": 19, - "y": 76 + "y": 85 }, "id": 86, "options": { @@ -4178,7 +4390,7 @@ "h": 4, "w": 6, "x": 5, - "y": 80 + "y": 89 }, "id": 85, "options": { @@ -4241,7 +4453,7 @@ "h": 7, "w": 5, "x": 0, - "y": 84 + "y": 93 }, "id": 60, "options": { @@ -4315,7 +4527,7 @@ "h": 7, "w": 4, "x": 5, - "y": 84 + "y": 93 }, "id": 61, "options": { @@ -4393,7 +4605,7 @@ "h": 7, "w": 3, "x": 9, - "y": 84 + "y": 93 }, "id": 80, "options": { @@ -4471,7 +4683,7 @@ "h": 7, "w": 3, "x": 12, - "y": 84 + "y": 93 }, "id": 81, "options": { @@ -4549,7 +4761,7 @@ "h": 7, "w": 3, "x": 15, - "y": 84 + "y": 93 }, "id": 91, "options": { @@ -4622,7 +4834,7 @@ "h": 7, "w": 3, "x": 18, - "y": 84 + "y": 93 }, "id": 82, "options": { @@ -4691,7 +4903,7 @@ "h": 7, "w": 3, "x": 21, - "y": 84 + "y": 93 }, "id": 83, "options": { @@ -4728,7 +4940,7 @@ "h": 1, "w": 24, "x": 0, - "y": 91 + "y": 100 }, "id": 29, "panels": [], @@ -4796,7 +5008,7 @@ "h": 7, "w": 24, "x": 0, - "y": 92 + "y": 101 }, "id": 32, "options": { @@ -4830,7 +5042,7 @@ "h": 1, "w": 24, "x": 0, - "y": 99 + "y": 108 }, "id": 92, "panels": [], @@ -4894,7 +5106,7 @@ "h": 7, "w": 12, "x": 0, - "y": 100 + "y": 109 }, "id": 94, "options": { @@ -4980,7 +5192,7 @@ "h": 7, "w": 12, "x": 12, - "y": 100 + "y": 109 }, "id": 95, "options": { @@ -5091,7 +5303,7 @@ "h": 7, "w": 12, "x": 0, - "y": 107 + "y": 116 }, "id": 93, "options": { @@ -5177,7 +5389,7 @@ "h": 7, "w": 12, "x": 12, - "y": 107 + "y": 116 }, "id": 96, "options": {