Webhook pending status

Can someone please advise: How do I get it to “attempt its first regular request attempt”?
Screenshot from 2021-12-31 17-03-34

Hello Paul,

I have 3 custom Webhooks running and have the same message. I do not encounter any problems. One of the Webhooks is running for half a year.
If you experience some problems: In your config it looks like your base URL is the total URL?
In your Base URL you set somethings like https://api.server.co.uk
and in your Enabled Messages something like:

image

In your case /ttn.php in the Enabled Messages (at least one, uplink is the most common)
and http://www.xxxxxxx.co.uk in your base URL.

With regards,

Leo.

Thanks Leo, will give that a try.

…unfortunately the status is still pending.

My endpoint does not seem to be receiving any messages.

Screenshot from 2021-12-31 22-20-53

Try this, known good starter:

Just in case, put a / at the end of the base URL and remove it from the Uplink box - which is how I have it. You can put the whole URL in the Base URL and leave the Uplink box empty, but still checked.

I can’t be 100% sure the new Webhook functionality has had all it’s wrinkles taken out, as I’ve seen a bunch of status messages that don’t add up but the acid test is that if you put your URL in a browser, it comes back with anything other than an error and does it quickly, ie before it times out at the Application Server (TTN) end. Sorry, not figured what the timeout is yet, not a problem in the UK for me, client in Australia gets a timeout on every webhook back to my UK server, so must be about 1s or thereabouts.

And yes, there isn’t that much on TV this evening.

Cheers Nick.

That php is much more complex than my own, which is simply this:

ttn.php:

<?php
$json = json_decode(file_get_contents('php://input'), true);
#$payload = explode('=', base64_decode($json['payload_raw'])); // TTN V2
$payload = explode('=', base64_decode($json['frm_payload'])); // TTN V3
$_GET['sensor'] = $payload[0];
$_GET['value'] = $payload[1];
include('script.php');
?> 

script.php:

<?php
$sensor=explode(",", $_GET["sensor"]);
$value=explode(",", $_GET["value"]);
$servername = "www.XXX.co.uk";
$username = "XXX";
$password = "XXX";
$dbname = "XXX";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

$stmt = $conn->prepare("INSERT INTO granary_sensors (sensor_name, sensor_value) VALUES (?, ?)");


for ($i = 0; $i < count($sensor); $i++) {

	$stmt->bind_param("sd", $sensor[$i], $value[$i]);
	$stmt->execute();
	echo "New record created successfully: ", $sensor[$i], "=", $value[$i], "\n";
}

$conn->close();
?> 

script.php is the endpoint I originally made for my non-LORAWAN sensors, which connect directly to the server through my home WiFi router, not via TTN. This endpoint expects to be invoked with POST http://www.XXX.co.uk/script.php?sensor=A,B,C&value=1,2,3 where A, B, C are sensor names and 1, 2, 3 are the values from those sensors.

When I made my first LORAWAN-based sensors, I wrote ttn.php to translate the TTN uplink POST format into the format used by the WIFI-based sensors. The payload coming from the LORAWAN sensors is simply the text A,B,C=1,2,3.

However, comparing my php to the example you linked, I realise that, in addition to the JSON field name changing from ‘payload_raw’ to ‘frm_payload’, it is also now inside the ‘uplink_message’ field which is inside the ‘data’ field, and my ttn.php does not expect this. I can’t remember the old V2 JSON format exactly, perhaps the structure was simpler than it is in V3. I will try amending my ttn.php accordingly.

Success!

Updated ttn.php:

<?php
$json = json_decode(file_get_contents('php://input'), true);
#$payload = explode('=', base64_decode($json['payload_raw'])); // TTN V2
$payload = explode('=', base64_decode($json['uplink_message']['frm_payload'])); // TTN V3
$_GET['sensor'] = $payload[0];
$_GET['value'] = $payload[1];
include('script.php');
?> 

(the only addition is the extra ['uplink_message'] reference)

So it seems my endpoint was receiving the uplink messages since I ticked “Uplink Message Enabled” in the console, but silently failing (nothing is showing in my php error log). I was assuming the endpoint was not receiving anything because no new data was getting inserted into the database :man_facepalming:

Something I still don’t understand is why adding the ['uplink_message'] reference was enough to make it work? The ‘uplink_message’ field is inside the ‘data’ field, but it seems I don’t need to reference that, and neither does the example code @descartes gave the link to.

@PaulRB2 I also wondered about this, and the core team answered me:

Think of it as an envelope - or an inner box.

You get your shipping box of “SomeJSON” and inside that are some smaller boxes with different parts of your shipment:

  • end_device_ids
  • uplink_message
  • correlation_ids

plus a standalone item of received_at.

Inside those boxes there are some standalone items plus more boxes/Jiffy bags/envelopes.

LOL, just confuse us instead!

Thanks Nick, I’m quite familiar with nested/hierarchical data structures!

but the fields you listed are not at the top/outer level of the structure. They are all contained within the container field/“box”, named ‘data’. At the same level as ‘data’ there are other fields such as ‘identifiers’, ‘correlation_ids’ (a different one), ‘context’ and ‘visibility’ as well as standalone items ‘name’, ‘time’, ‘origin’ and ‘unique_id’.

So my question is this: I had to specify that the field ‘frm_payload’ was within the container ‘uplink_message’, otherwise it could not be found inside the structure. But why did I also not have to specify that ‘uplink_messsage’ was within the container ‘data’? How come ‘uplink_message’ was found without having to specify that it is within the ‘data’ container field?

I’m just curious what the rules are about accessing fields within JSON data structures are, because they seem inconsistent to me. Sometimes fields cannot be found without specifying their containing field (like ‘frm_payload’ within ‘uplink_message’), and sometimes they can be found without specifying their containing field (like ‘uplink_message’ within ‘data’).

Here’s an example of the full structure.

{
  "name": "as.up.data.forward",
  "time": "2022-01-01T15:38:11.351655459Z",
  "identifiers": [
    {
      "device_ids": {
        "device_id": "jim-test-node",
        "application_ids": {
          "application_id": "granary-sensors"
        }
      }
    },
    {
      "device_ids": {
        "device_id": "jim-test-node",
        "application_ids": {
          "application_id": "granary-sensors"
        },
        "dev_eui": "00BC857ED3F12702",
        "join_eui": "70B3D57ED0008B27",
        "dev_addr": "26011A7D"
      }
    }
  ],
  "data": {
    "@type": "type.googleapis.com/ttn.lorawan.v3.ApplicationUp",
    "end_device_ids": {
      "device_id": "jim-test-node",
      "application_ids": {
        "application_id": "granary-sensors"
      },
      "dev_eui": "00BC857ED3F12702",
      "join_eui": "70B3D57ED0008B27",
      "dev_addr": "26011A7D"
    },
    "correlation_ids": [
      "as:up:01FRB4N30MAW4F9GBE4WMZA132",
      "gs:conn:01FR647Y69XYD9XDV25WDH37SH",
      "gs:up:host:01FR647Y6WGR9TNJJM65MTHK2P",
      "gs:uplink:01FRB4N2T37PCWX1E7MY8SBNAB",
      "ns:uplink:01FRB4N2T4EKKXH56NQ74VZFBF",
      "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01FRB4N2T48FZHQVEFXWED2GDC",
      "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01FRB4N30KCKXJYFC0YSWMR6ZH"
    ],
    "received_at": "2022-01-01T15:38:11.349955361Z",
    "uplink_message": {
      "f_port": 1,
      "f_cnt": 12106,
      "frm_payload": "VDUsSDUsTDUsQjUsQTU9MTEuMDcsOTYuOTIsMTE5Ni4xOCwzLjcwLDkuNzQ=",
      "rx_metadata": [
        {
          "gateway_ids": {
            "gateway_id": "granary-gateway",
            "eui": "3338333045003200"
          },
          "timestamp": 3217892827,
          "rssi": -78,
          "channel_rssi": -78,
          "snr": 7.2,
          "location": {
            "latitude": 53.55383279504398,
            "longitude": -1.6947779059410095,
            "altitude": 300,
            "source": "SOURCE_REGISTRY"
          },
          "uplink_token": "Ch0KGwoPZ3JhbmFyeS1nYXRld2F5EggzODMwRQAyABDby7T+CxoLCOPqwY4GENPku0Ig+L7vytPoJg==",
          "channel_index": 2
        }
      ],
      "settings": {
        "data_rate": {
          "lora": {
            "bandwidth": 125000,
            "spreading_factor": 7
          }
        },
        "coding_rate": "4/5",
        "frequency": "868500000",
        "timestamp": 3217892827
      },
      "received_at": "2022-01-01T15:38:11.140745903Z",
      "consumed_airtime": "0.107776s",
      "network_ids": {
        "net_id": "000013",
        "tenant_id": "ttn",
        "cluster_id": "ttn-eu1"
      }
    }
  },
  "correlation_ids": [
    "as:up:01FRB4N30MAW4F9GBE4WMZA132",
    "gs:conn:01FR647Y69XYD9XDV25WDH37SH",
    "gs:up:host:01FR647Y6WGR9TNJJM65MTHK2P",
    "gs:uplink:01FRB4N2T37PCWX1E7MY8SBNAB",
    "ns:uplink:01FRB4N2T4EKKXH56NQ74VZFBF",
    "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01FRB4N2T48FZHQVEFXWED2GDC",
    "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01FRB4N30KCKXJYFC0YSWMR6ZH"
  ],
  "origin": "ip-10-100-14-196.eu-west-1.compute.internal",
  "context": {
    "tenant-id": "CgN0dG4="
  },
  "visibility": {
    "rights": [
      "RIGHT_APPLICATION_TRAFFIC_READ",
      "RIGHT_APPLICATION_TRAFFIC_READ"
    ]
  },
  "unique_id": "01FRB4N30Q226H8AK1BG344TA7"
}

In a similar vein, I’m quite familiar with the JSON :wink: - except that’s been taken from the console or from an event stream and not from a webhook submission which doesn’t have a data element, a webhook gets sent everything inside data.

So the top level elements of the JSON a webhook gets is:

  • end_device_ids
  • uplink_message
  • correlation_ids

plus a standalone item of received_at.

Déjà vu?

I guess to use my CS 101 analogy, it’s actually three boxes tapped together with a small bottle of timestamp, so you can access the three boxes directly.

But in the event stream format, it’s wrapped up so other information can be added.

See Data Formats | The Things Stack for LoRaWAN for the official uplink format.

Ah, that’s why! Thanks Nick. Well, I fell into that trap too, like the “gateway_id” != “gateway_id” one before. So when you click on “Forward data uplink message” in the console, the JSON you see isn’t actually the JSON you get…

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.