1
0
mirror of synced 2026-03-31 23:03:42 +00:00
This commit is contained in:
Cam Soper
2022-02-10 14:38:53 -06:00
6 changed files with 107 additions and 16 deletions

View File

@@ -12,17 +12,16 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2.3.4 uses: actions/checkout@v2.4.0
- name: Bump version - name: Bump version
uses: remorses/bump-version@js uses: remorses/bump-version@js
id: version id: version
with: with:
version_file: ./VERSION version_file: ./VERSION
github_token: ${{ secrets.GITHUB_TOKEN }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2.3.4 uses: actions/checkout@v2.4.0
with: with:
ref: main ref: main
- name: Set up QEMU - name: Set up QEMU
@@ -30,14 +29,14 @@ jobs:
with: with:
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1.5.1 uses: docker/setup-buildx-action@v1.6.0
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1.10.0 uses: docker/login-action@v1.12.0
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v2.6.1 uses: docker/build-push-action@v2.7.0
with: with:
context: . context: .
push: true push: true

View File

@@ -8,6 +8,7 @@ COPY requirements.txt /
RUN pip install --no-warn-script-location --prefix=/install -r /requirements.txt RUN pip install --no-warn-script-location --prefix=/install -r /requirements.txt
FROM base FROM base
STOPSIGNAL SIGINT
COPY --from=builder /install /usr/local COPY --from=builder /install /usr/local
COPY src /app COPY src /app
COPY VERSION /app COPY VERSION /app

View File

@@ -22,6 +22,7 @@ It supports the following environment variables:
- `HOME_ASSISTANT` (optional, default = false) - `HOME_ASSISTANT` (optional, default = false)
- `HOME_ASSISTANT_PREFIX` (optional, default = 'homeassistant') - `HOME_ASSISTANT_PREFIX` (optional, default = 'homeassistant')
- `STORAGE_POLL_INTERVAL` (optional, default = 3600) - how often to fetch storage data (in seconds) - `STORAGE_POLL_INTERVAL` (optional, default = 3600) - how often to fetch storage data (in seconds)
- `DEVICE_NAME` (optional) - override the default device name used in the Amcrest app
It exposes events to the following topics: It exposes events to the following topics:
@@ -29,6 +30,7 @@ It exposes events to the following topics:
- `amcrest2mqtt/[SERIAL_NUMBER]/doorbell` - doorbell status (if AD110 or AD410) - `amcrest2mqtt/[SERIAL_NUMBER]/doorbell` - doorbell status (if AD110 or AD410)
- `amcrest2mqtt/[SERIAL_NUMBER]/human` - human detection (if AD410) - `amcrest2mqtt/[SERIAL_NUMBER]/human` - human detection (if AD410)
- `amcrest2mqtt/[SERIAL_NUMBER]/motion` - motion events (if supported) - `amcrest2mqtt/[SERIAL_NUMBER]/motion` - motion events (if supported)
- `amcrest2mqtt/[SERIAL_NUMBER]/config` - device configuration information
## Device Support ## Device Support
@@ -63,7 +65,7 @@ services:
### Multiple Devices ### Multiple Devices
The app will not support multiple devices. You can run multiple instances of the app if you need to expose events for multiple devies. The app will not support multiple devices. You can run multiple instances of the app if you need to expose events for multiple devices.
### Non-Docker Environments ### Non-Docker Environments

View File

@@ -1 +1 @@
1.0.9 1.0.15

View File

@@ -1,3 +1,3 @@
amcrest==1.8.0 amcrest==1.9.3
paho-mqtt==1.5.1 paho-mqtt==1.6.1
python-slugify==5.0.2 python-slugify==5.0.2

View File

@@ -17,8 +17,10 @@ amcrest_host = os.getenv("AMCREST_HOST")
amcrest_port = int(os.getenv("AMCREST_PORT") or 80) amcrest_port = int(os.getenv("AMCREST_PORT") or 80)
amcrest_username = os.getenv("AMCREST_USERNAME") or "admin" amcrest_username = os.getenv("AMCREST_USERNAME") or "admin"
amcrest_password = os.getenv("AMCREST_PASSWORD") amcrest_password = os.getenv("AMCREST_PASSWORD")
storage_poll_interval = int(os.getenv("STORAGE_POLL_INTERVAL") or 3600) storage_poll_interval = int(os.getenv("STORAGE_POLL_INTERVAL") or 3600)
camera_ping_enabled = os.getenv("CAMERA_PING_ENABLED") == "true" camera_ping_enabled = os.getenv("CAMERA_PING_ENABLED") == "true"
device_name = os.getenv("DEVICE_NAME")
mqtt_host = os.getenv("MQTT_HOST") or "localhost" mqtt_host = os.getenv("MQTT_HOST") or "localhost"
mqtt_qos = int(os.getenv("MQTT_QOS") or 0) mqtt_qos = int(os.getenv("MQTT_QOS") or 0)
@@ -93,12 +95,16 @@ def refresh_storage_sensors():
try: try:
storage = camera.storage_all storage = camera.storage_all
mqtt_publish(topics["storage_used_percent"], str(storage["used_percent"])) mqtt_publish(topics["storage_used_percent"], str(storage["used_percent"]))
mqtt_publish(topics["storage_used"], str(storage["used"][0])) mqtt_publish(topics["storage_used"], to_gb(storage["used"]))
mqtt_publish(topics["storage_total"], str(storage["total"][0])) mqtt_publish(topics["storage_total"], to_gb(storage["total"]))
except AmcrestError as error: except AmcrestError as error:
log(f"Error fetching storage information {error}", level="WARNING") log(f"Error fetching storage information {error}", level="WARNING")
def to_gb(total):
return str(round(float(total[0]) / 1024 / 1024 / 1024, 2))
def ping_camera(): def ping_camera():
Timer(30, ping_camera).start() Timer(30, ping_camera).start()
response = os.system(f"ping -c1 -W100 {amcrest_host} >/dev/null 2>&1") response = os.system(f"ping -c1 -W100 {amcrest_host} >/dev/null 2>&1")
@@ -150,9 +156,16 @@ try:
is_ad110 = device_type == "AD110" is_ad110 = device_type == "AD110"
is_ad410 = device_type == "AD410" is_ad410 = device_type == "AD410"
is_doorbell = is_ad110 or is_ad410 is_doorbell = is_ad110 or is_ad410
serial_number = camera.serial_number.strip() serial_number = camera.serial_number
if not isinstance(serial_number, str):
log(f"Error fetching serial number", level="ERROR")
exit_gracefully(1)
sw_version = camera.software_information[0].replace("version=", "").strip() sw_version = camera.software_information[0].replace("version=", "").strip()
if not device_name:
device_name = camera.machine_name.replace("name=", "").strip() device_name = camera.machine_name.replace("name=", "").strip()
device_slug = slugify(device_name, separator="_") device_slug = slugify(device_name, separator="_")
except AmcrestError as error: except AmcrestError as error:
log(f"Error fetching camera details", level="ERROR") log(f"Error fetching camera details", level="ERROR")
@@ -174,13 +187,27 @@ topics = {
"storage_used": f"amcrest2mqtt/{serial_number}/storage/used", "storage_used": f"amcrest2mqtt/{serial_number}/storage/used",
"storage_used_percent": f"amcrest2mqtt/{serial_number}/storage/used_percent", "storage_used_percent": f"amcrest2mqtt/{serial_number}/storage/used_percent",
"storage_total": f"amcrest2mqtt/{serial_number}/storage/total", "storage_total": f"amcrest2mqtt/{serial_number}/storage/total",
"home_assistant": { "home_assistant_legacy": {
"doorbell": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/{device_slug}_doorbell/config", "doorbell": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/{device_slug}_doorbell/config",
"human": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/{device_slug}_human/config", "human": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/{device_slug}_human/config",
"motion": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/{device_slug}_motion/config", "motion": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/{device_slug}_motion/config",
"storage_used": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_storage_used/config", "storage_used": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_storage_used/config",
"storage_used_percent": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_storage_used_percent/config", "storage_used_percent": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_storage_used_percent/config",
"storage_total": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_storage_total/config", "storage_total": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_storage_total/config",
"version": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_version/config",
"host": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_host/config",
"serial_number": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/{device_slug}_serial_number/config",
},
"home_assistant": {
"doorbell": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/doorbell/config",
"human": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/human/config",
"motion": f"{home_assistant_prefix}/binary_sensor/amcrest2mqtt-{serial_number}/motion/config",
"storage_used": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/storage_used/config",
"storage_used_percent": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/storage_used_percent/config",
"storage_total": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/storage_total/config",
"version": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/version/config",
"host": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/host/config",
"serial_number": f"{home_assistant_prefix}/sensor/amcrest2mqtt-{serial_number}/serial_number/config",
}, },
} }
@@ -236,6 +263,9 @@ if home_assistant:
} }
if is_doorbell: if is_doorbell:
doorbell_name = "Doorbell" if device_name == "Doorbell" else f"{device_name} Doorbell"
mqtt_publish(topics["home_assistant_legacy"]["doorbell"], "")
mqtt_publish( mqtt_publish(
topics["home_assistant"]["doorbell"], topics["home_assistant"]["doorbell"],
base_config base_config
@@ -243,13 +273,15 @@ if home_assistant:
"state_topic": topics["doorbell"], "state_topic": topics["doorbell"],
"payload_on": "on", "payload_on": "on",
"payload_off": "off", "payload_off": "off",
"name": f"{device_name} Doorbell", "icon": "mdi:doorbell",
"name": doorbell_name,
"unique_id": f"{serial_number}.doorbell", "unique_id": f"{serial_number}.doorbell",
}, },
json=True, json=True,
) )
if is_ad410: if is_ad410:
mqtt_publish(topics["home_assistant_legacy"]["human"], "")
mqtt_publish( mqtt_publish(
topics["home_assistant"]["human"], topics["home_assistant"]["human"],
base_config base_config
@@ -264,6 +296,7 @@ if home_assistant:
json=True, json=True,
) )
mqtt_publish(topics["home_assistant_legacy"]["motion"], "")
mqtt_publish( mqtt_publish(
topics["home_assistant"]["motion"], topics["home_assistant"]["motion"],
base_config base_config
@@ -278,7 +311,56 @@ if home_assistant:
json=True, json=True,
) )
mqtt_publish(topics["home_assistant_legacy"]["version"], "")
mqtt_publish(
topics["home_assistant"]["version"],
base_config
| {
"state_topic": topics["config"],
"value_template": "{{ value_json.sw_version }}",
"icon": "mdi:package-up",
"name": f"{device_name} Version",
"unique_id": f"{serial_number}.version",
"entity_category": "diagnostic",
"enabled_by_default": False
},
json=True,
)
mqtt_publish(topics["home_assistant_legacy"]["serial_number"], "")
mqtt_publish(
topics["home_assistant"]["serial_number"],
base_config
| {
"state_topic": topics["config"],
"value_template": "{{ value_json.serial_number }}",
"icon": "mdi:alphabetical-variant",
"name": f"{device_name} Serial Number",
"unique_id": f"{serial_number}.serial_number",
"entity_category": "diagnostic",
"enabled_by_default": False
},
json=True,
)
mqtt_publish(topics["home_assistant_legacy"]["host"], "")
mqtt_publish(
topics["home_assistant"]["host"],
base_config
| {
"state_topic": topics["config"],
"value_template": "{{ value_json.host }}",
"icon": "mdi:ip-network",
"name": f"{device_name} Host",
"unique_id": f"{serial_number}.host",
"entity_category": "diagnostic",
"enabled_by_default": False
},
json=True,
)
if storage_poll_interval > 0: if storage_poll_interval > 0:
mqtt_publish(topics["home_assistant_legacy"]["storage_used_percent"], "")
mqtt_publish( mqtt_publish(
topics["home_assistant"]["storage_used_percent"], topics["home_assistant"]["storage_used_percent"],
base_config base_config
@@ -287,11 +369,14 @@ if home_assistant:
"unit_of_measurement": "%", "unit_of_measurement": "%",
"icon": "mdi:micro-sd", "icon": "mdi:micro-sd",
"name": f"{device_name} Storage Used %", "name": f"{device_name} Storage Used %",
"object_id": f"{device_slug}_storage_used_percent",
"unique_id": f"{serial_number}.storage_used_percent", "unique_id": f"{serial_number}.storage_used_percent",
"entity_category": "diagnostic",
}, },
json=True, json=True,
) )
mqtt_publish(topics["home_assistant_legacy"]["storage_used"], "")
mqtt_publish( mqtt_publish(
topics["home_assistant"]["storage_used"], topics["home_assistant"]["storage_used"],
base_config base_config
@@ -301,10 +386,12 @@ if home_assistant:
"icon": "mdi:micro-sd", "icon": "mdi:micro-sd",
"name": f"{device_name} Storage Used", "name": f"{device_name} Storage Used",
"unique_id": f"{serial_number}.storage_used", "unique_id": f"{serial_number}.storage_used",
"entity_category": "diagnostic",
}, },
json=True, json=True,
) )
mqtt_publish(topics["home_assistant_legacy"]["storage_total"], "")
mqtt_publish( mqtt_publish(
topics["home_assistant"]["storage_total"], topics["home_assistant"]["storage_total"],
base_config base_config
@@ -314,6 +401,7 @@ if home_assistant:
"icon": "mdi:micro-sd", "icon": "mdi:micro-sd",
"name": f"{device_name} Storage Total", "name": f"{device_name} Storage Total",
"unique_id": f"{serial_number}.storage_total", "unique_id": f"{serial_number}.storage_total",
"entity_category": "diagnostic",
}, },
json=True, json=True,
) )
@@ -326,6 +414,7 @@ mqtt_publish(topics["config"], {
"device_name": device_name, "device_name": device_name,
"sw_version": sw_version, "sw_version": sw_version,
"serial_number": serial_number, "serial_number": serial_number,
"host": amcrest_host,
}, json=True) }, json=True)
if storage_poll_interval > 0: if storage_poll_interval > 0: