# Unifi Protect Alarm to Discord Using Webhook
> This article will teach you how to post Unifi Protect alerts to Discord using Webhook
> [name=John @ 崑山科技大學 光達實驗室 KSU Eilidar Lab][time=Thursday, September 26, 2024]
[TOC]
## Why?
Because I want to receive notifications on my computer without using an Android emulator to install and run the Unifi Protect app.
I spent all night researching this because my friend, who is ten times smarter than I am, keeps calling me "dumb," "lazy," and "useless" :D
I hope this information provides what you need and saves you some sleep!
## How?
We need to set up a "UniFi Protect to Discord webhook data conversion server" on a computer using Python to reroute the alert data to Discord.
## 1) Get your webhook link from Discord
- In Discord, navigate to your `Server Settings` -> `Apps` -> `Integrations` -> `Webhooks`, and click on `New Webhook`
- Change the profile picture, name, and the channel where you want to post your message by selecting the appropriate channel
- Copy the webhook URL by clicking on `Copy Webhook URL`
## 2) Set up a python server
- Create a Python file and name it whatever you prefer
- Open the Python file with your favorite text editor
- Copy and paste the code below into the file
```py
from flask import Flask, request, jsonify
import requests
from datetime import datetime
app = Flask(__name__)
# Replace this with your Discord webhook URL
DISCORD_WEBHOOK_URL = 'YOUR_WEBHOOK_URL'
# Device ID to device name mapping
# Left column is the MAC adders of the device, and the right column is the name you want to convert it to.
DEVICE_NAME_MAPPING = {
'CAMERA_MAC_ADDERS': 'CAMERA_NAME',
'CAMERA_MAC_ADDERS': 'CAMERA_NAME',
'CAMERA_MAC_ADDERS': 'CAMERA_NAME'
}
@app.route('/data', methods=['POST'])
def data():
if request.is_json:
data = request.get_json()
# Extract necessary fields from the received data
if 'alarm' in data:
alarm = data['alarm']
triggers = alarm.get('triggers', [])
# Access the timestamp from the root of the JSON (not inside the alarm object)
timestamp = data.get('timestamp', None)
# Convert timestamp to human-readable format
readable_timestamp = convert_timestamp(timestamp)
# Prepare data to send to the create_discord_embed function
for trigger in triggers:
key = trigger.get('key', 'Unknown trigger')
device = trigger.get('device', 'Unknown device')
device_name = DEVICE_NAME_MAPPING.get(device, device)
# Call create_discord_embed with the key, device, and readable timestamp
discord_message = create_discord_embed(key, device_name, readable_timestamp)
# Send the embed to Discord
response = post_to_discord(discord_message)
return jsonify({"message": "JSON received and posted to Discord"}), 200
else:
return jsonify({"error": "Invalid JSON structure"}), 400
else:
return jsonify({"error": "Request must be JSON"}), 400
def post_to_discord(embed_message):
# Send the embed to Discord webhook
response = requests.post(DISCORD_WEBHOOK_URL, json=embed_message)
if response.status_code == 204:
return "Success"
else:
return f"Failed to post to Discord. Status code: {response.status_code}"
def create_discord_embed(trigger, device, timestamp):
# Create an embed for Discord
embed = {
"embeds": [
{
"title": "Alert Triggered :camera_with_flash: ",
"color": 16711680, # Red color
"fields": [
{
"name": "Trigger",
"value": trigger,
"inline": True
},
{
"name": "Device",
"value": device,
"inline": True
},
{
"name": "Timestamp",
"value": timestamp,
"inline": False
}
],
"footer": {
"text": "Unifi Protect",
"icon_url": "https://pbs.twimg.com/profile_images/1610157462321254402/tMCv8T-y_400x400.png" # Replace with your own icon URL
},
"timestamp": datetime.utcnow().isoformat() # Adds current time in ISO format for Discord
}
]
}
return embed
def convert_timestamp(timestamp):
# Convert the timestamp to a human-readable format
if timestamp:
try:
# Convert from milliseconds to seconds and format
dt_object = datetime.utcfromtimestamp(timestamp / 1000)
return dt_object.strftime('%Y-%m-%d %H:%M:%S UTC')
except Exception as e:
return "Invalid timestamp"
return "No timestamp available"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
```
- Edit `DISCORD_WEBHOOK_URL` at line 8 to include the Discord webhook link that you obtained in step one
- Edit `DEVICE_NAME_MAPPING` at line 12; the left column should contain your camera's MAC address without the colons (:), and the right column should be the name you want it to display. You can add as many entries as you like
- Change the `port` at line 107 to any available port that is not being used by another process
- Start the server with Python using the following command:
```shell
python3 ./<your python file name>.py
```
## 3) Add a webhook action in Unifi Protect
- Go to your UniFi Protect Alarm panel
- Create an alarm and give it a name
- Select what you want the alarm to send to the webhook
- Change the action from `Send Notification` to `Webhook`
- Select `Custom Webhook`
- Enter the IP address of the computer hosting the Python server created in step two into the `Delivery URL` input field like this: `http://<your_ip>:<your_port>/data`
- Check `Advanced Settings` and change the method to `POST`
- Test it out, and you're all done!

## Where to find me?
- Email: enderdragonep@gmail.com
- Discord: noobienoodle89
###### tags: Unifi, Unifi Protect, Discord, Webhook