Livestock monitoring IoT systems give farmers eyes on animals, water and housing conditions without driving every paddock twice a day. In this guide you will design a complete setup: LoRaWAN collars and sensors in the field, a network server that decodes uplinks, and an MQTT broker that turns those readings into a topic tree your dashboards and alerts can use. You will also get a working Python bridge and an alerting pattern you can test today on a free public broker.
What Livestock Monitoring IoT Actually Measures
Most herd problems show up first as a change in a few simple signals. A good system does not try to measure everything; it measures the handful of things that would otherwise require a person on a quad bike.
| What you monitor | Typical sensor | Why it matters | Reporting interval |
|---|---|---|---|
| Animal position | LoRaWAN GPS collar or ear tag | Escaped animals, grazing patterns, finding a calving cow | 15–60 min, faster on movement |
| Activity | Accelerometer in collar or tag | Heat detection, lameness, illness (reduced movement) | Aggregated per 15–60 min |
| Water trough level | Ultrasonic or pressure level sensor | A dry trough in summer is an emergency | 10–30 min |
| Float valve / flow | Pulse flow meter on supply line | Detects broken valves and leaks | 15 min totals |
| Barn temperature and humidity | Climate sensor (often with THI calc) | Heat stress in dairy and poultry housing | 5–10 min |
| Ammonia / CO2 | Gas sensor in barn | Ventilation problems, respiratory health | 5–10 min |
| Fence voltage | Electric fence monitor | A shorted fence lets animals out | 15 min |
The intervals matter because almost all of these devices run on batteries and LoRaWAN duty-cycle limits. A collar that reports every minute will drain its battery quickly, and in many regions it will also exceed what the network should carry. Plan for slow, regular uplinks plus event-triggered messages when something changes.
Why LoRaWAN in the Field and MQTT Behind It
Pastures are big and rarely have Wi-Fi or reliable cellular coverage at ground level. LoRaWAN fits well because one gateway on a barn roof or a pole can cover a large area, and sensors can run for a long time on a battery. The trade-off is bandwidth: payloads are tiny, typically a dozen bytes of packed binary.
LoRaWAN does not deliver data directly to your application. The chain looks like this:
- The collar or trough sensor sends an uplink over radio.
- One or more gateways forward it to a LoRaWAN network server, such as The Things Stack or ChirpStack.
- The network server decodes the payload with a codec (a small JavaScript function) and publishes a JSON event.
- Your integration takes that event and makes it available to dashboards, alerts and storage.
Both major network servers expose uplinks over MQTT, but their topics are network-specific and full of radio metadata. A practical pattern is to run a small bridge that subscribes to the network server and republishes a clean, farm-oriented message to your own MQTT broker. Everything downstream (dashboards, Home Assistant, Node-RED, a mobile app) then talks to one stable topic tree that does not change if you switch network servers. The guides on The Things Network MQTT integration and ChirpStack MQTT cover the network-server side in detail.
If you are new to the concept of a central message hub, the short explanation of what an MQTT broker does is worth reading before you go further.
Designing the Topic Tree
Name topics after the farm, not after the radio. A tree that follows site, area and asset is easy to read and easy to subscribe to with wildcards:
farm1/pasture-north/animals/cow-0412/position
farm1/pasture-north/animals/cow-0412/activity
farm1/pasture-north/troughs/trough-03/level
farm1/barn-a/climate/env-01/telemetry
farm1/barn-a/fence/energizer-1/voltage
farm1/status/bridge
A few rules keep this maintainable:
- Use stable IDs (ear tag number, trough number) in topics, not DevEUIs. Keep the DevEUI in the payload for troubleshooting.
- Retain the last reading for troughs, climate and fence voltage, so a dashboard that opens at 5 a.m. immediately shows the current state.
- Do not retain alarms as commands. Alerts are events; a retained alarm that replays on every reconnect causes confusion.
- Keep payloads small JSON with a timestamp from the network server, because the uplink time is what matters, not the time your bridge processed it.
Example trough message:
{
"ts": "2026-10-16T05:42:10Z",
"level_pct": 18,
"level_cm": 9.4,
"battery_v": 3.52,
"rssi": -112,
"snr": -4.5,
"dev_eui": "a84041000181c2f1"
}
Building the Bridge: Network Server to MQTT
The bridge below subscribes to ChirpStack v4 uplink events, picks out the decoded object field, maps each device to a farm topic and republishes it. For the first test it publishes to the public area of broker.connectmq.com, which needs no account but is readable by anyone, so use a random prefix and test data only.
Install the library:
pip install "paho-mqtt>=2.0"
import json
import time
import uuid
import paho.mqtt.client as mqtt
# ChirpStack v4 (local or hosted) - adjust to your network server
LNS_HOST = "chirpstack.local"
LNS_PORT = 1883
LNS_TOPIC = "application/+/device/+/event/up"
# Destination broker - public test area first, credentials later
DEST_HOST = "broker.connectmq.com"
DEST_PORT = 1883
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:8]}/farm1"
# DevEUI -> (area, kind, asset id)
DEVICES = {
"a84041000181c2f1": ("pasture-north", "troughs", "trough-03"),
"70b3d57ed005a1b2": ("pasture-north", "animals", "cow-0412"),
"a84041000181d004": ("barn-a", "climate", "env-01"),
}
dest = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"farm-bridge-{uuid.uuid4().hex[:6]}")
dest.will_set(f"{PREFIX}/status/bridge", "offline", qos=1, retain=True)
dest.connect(DEST_HOST, DEST_PORT, keepalive=60)
dest.loop_start()
dest.publish(f"{PREFIX}/status/bridge", "online", qos=1, retain=True)
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected to network server:", reason_code)
client.subscribe(LNS_TOPIC, qos=1)
def on_message(client, userdata, msg):
try:
event = json.loads(msg.payload)
except json.JSONDecodeError:
return
dev_eui = event.get("deviceInfo", {}).get("devEui", "").lower()
if dev_eui not in DEVICES:
print("Unknown device", dev_eui)
return
area, kind, asset = DEVICES[dev_eui]
decoded = event.get("object") or {}
rx = (event.get("rxInfo") or [{}])[0]
out = dict(decoded)
out["ts"] = event.get("time")
out["dev_eui"] = dev_eui
out["rssi"] = rx.get("rssi")
out["snr"] = rx.get("snr")
leaf = {"troughs": "level", "animals": "position",
"climate": "telemetry"}.get(kind, "telemetry")
topic = f"{PREFIX}/{area}/{kind}/{asset}/{leaf}"
retain = kind != "animals"
dest.publish(topic, json.dumps(out), qos=1, retain=retain)
print("->", topic, out)
lns = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"farm-lns-{uuid.uuid4().hex[:6]}")
lns.on_connect = on_connect
lns.on_message = on_message
lns.connect(LNS_HOST, LNS_PORT, keepalive=60)
print("Publishing under", PREFIX)
try:
lns.loop_forever()
except KeyboardInterrupt:
dest.publish(f"{PREFIX}/status/bridge", "offline", qos=1, retain=True)
time.sleep(0.5)
Watch the result from any machine:
mosquitto_sub -h broker.connectmq.com -p 1883 -i farm-viewer-7731 -t "connectmq/demo/<your-id>/farm1/#" -v
The public test broker allows 8 topic levels, so connectmq/demo/<id>/farm1/pasture-north/troughs/trough-03/level at exactly 8 levels is the maximum; for deeper trees drop the farm1 level during tests. The public MQTT test broker article lists the other limits.
Alerts That Farmers Actually Act On
Dashboards are useful, but on a farm the value is in alerts. Start with a short list and tune it so people do not learn to ignore notifications.
- Trough level below 25 percent for two consecutive readings (one reading may be an animal drinking).
- No uplink from a trough or fence sensor for 3 intervals, which usually means a dead battery or a damaged sensor.
- Fence voltage under your threshold (many farmers use a few kilovolts) for two readings.
- Animal outside a geofence, evaluated on position messages.
- Barn temperature-humidity index above your heat-stress limit for dairy or poultry housing.
- Activity drop compared with the animal's own recent average, flagged for inspection rather than as an emergency.
For numeric thresholds such as trough level or barn temperature, the ConnectMQ portal includes threshold alert rules and an alerts log, so you can configure "level_pct below 25" on a topic without writing code. Geofences and "no data for 3 intervals" checks need some logic, which you can run in Node-RED or a small Python subscriber that connects as an ordinary MQTT client:
def inside_fence(lat, lon, fence):
# fence = (min_lat, min_lon, max_lat, max_lon) - simple bounding box
return fence[0] <= lat <= fence[2] and fence[1] <= lon <= fence[3]
A bounding box is crude but robust; polygon geofences are better for irregular paddocks, and a library such as Shapely makes that straightforward.
Field Pitfalls and How to Avoid Them
- GPS accuracy and battery. Collars that fix position on every uplink drain fast. Prefer devices that report less often while resting and more often when the accelerometer detects movement.
- Gateway placement. Height beats everything else. A gateway on the barn ridge with a proper outdoor antenna usually covers far more than one inside a building.
- Codec drift. If a vendor changes firmware, the decoded field names may change. Keep the bridge's mapping in one place and log unknown fields.
- Clock trust. Use the network server's timestamp. Bridges that restart can otherwise create gaps or duplicates in your history.
- Storage. The broker is a real-time hub, not a historian. Send readings to a database with Telegraf or Node-RED if you need season-long history for grazing analysis.
- Do not publish farm data publicly. Animal locations reveal where valuable stock is. The public broker is for testing only.
Moving From a Test to a Farm Deployment
Once the bridge works, switch the destination to a private broker with credentials and TLS. With a fully managed MQTT service you do not run or patch the broker yourself, which matters when the person responsible for the system is also responsible for calving. In ConnectMQ, create a broker in the portal, copy the generated username, password and client ID, and change the destination connection:
DEST_HOST = "broker.connectmq.com" # or the host shown in your portal
DEST_PORT = 8883
dest = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
dest.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
dest.tls_set() # system CA bundle validates the Let's Encrypt certificate
The free Serverless plan supports up to 25 connections, which comfortably covers a bridge, a dashboard, a Node-RED instance and a few phones. Larger operations with many sites can move to a paid plan with more connections and shared subscriptions for load-balanced consumers. For the wider picture of farm automation, including irrigation and greenhouses, see the smart agriculture IoT guide and the IoT automation guide.
Connect Your Farm Sensors to ConnectMQ
ConnectMQ gives your LoRaWAN bridge, dashboards and alerting tools one secure place to meet, with TLS, generated credentials and threshold alerts built into the portal. Create a free Serverless broker at app.connectmq.com, no credit card required, and point your bridge at it in a few minutes.
Frequently Asked Questions
Do I need LoRaWAN for livestock monitoring IoT?
Not always. Barns with Wi-Fi can use Wi-Fi or Ethernet sensors that publish MQTT directly, but for open pasture LoRaWAN or cellular IoT is usually the only practical option because of distance and battery life.
Can GPS collars publish MQTT directly?
Most LoRaWAN collars cannot; they send uplinks to a network server, which then publishes MQTT. Cellular collars sometimes publish MQTT or HTTP directly, and in both cases a bridge can normalize the data into your topic tree.
How often should trough sensors report?
Every 10 to 30 minutes is a common balance between battery life and early warning. Combine it with an alert on two consecutive low readings to avoid false alarms when animals drink.
Is the public test broker safe for real farm data?
No. The public area of broker.connectmq.com is readable by anyone and intended for testing. Use a private broker with credentials and TLS for production data, especially animal locations.



