Skip to content

Commit 6b873ac

Browse files
committed
Some refinements
1 parent fe4732d commit 6b873ac

31 files changed

+170
-156
lines changed

README.md

+50-50
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ Telegram Bot which sends snapshots from your Hikvision cameras.
44
Version: 1.5. [Release details](releases/release_1.5.md).
55

66
## Features
7-
1. Send full/resized pictures on request
8-
2. Auto-send pictures on **Motion**, **Line Crossing** and **Intrusion (Field) Detection**
9-
3. Send so-called Telegram video-gifs on request and alert events from previous paragraph
10-
4. YouTube, Telegram and Icecast direct or re-encoded livestreams
11-
5. DVR to local storage with upload to Telegram group
12-
6. SRS re-stream server
7+
1. Send full/resized pictures on request.
8+
2. Auto-send pictures on **Motion**, **Line Crossing** and **Intrusion (Field) Detection**.
9+
3. Send so-called Telegram video-gifs on request and alert events from the previous paragraph.
10+
4. YouTube, Telegram, and Icecast direct or re-encoded livestreams.
11+
5. DVR to local storage with upload to Telegram group.
12+
6. SRS re-stream server.
1313

1414

1515
![frames](img/screenshot-1.png)
@@ -23,13 +23,13 @@ cd hikvision-camera-bot
2323
```
2424

2525
# Configuration
26-
Configuration files are stored in JSON format and can be found in `configs` directory.
26+
Configuration files are stored in JSON format and can be found in the `configs` directory.
2727

2828
## Quick Setup
2929
1. [Create and start Telegram Bot](https://core.telegram.org/bots#6-botfather)
3030
and get its API token
31-
2. [Get your own Telegram API key](https://my.telegram.org/apps) (`api_id` and `api_hash`)
32-
3. Copy 3 default configuration files with predefined templates in `configs` directory:
31+
2. [Get your Telegram API key](https://my.telegram.org/apps) (`api_id` and `api_hash`)
32+
3. Copy 3 default configuration files with predefined templates in the `configs` directory:
3333

3434
```bash
3535
cd configs
@@ -38,21 +38,21 @@ Configuration files are stored in JSON format and can be found in `configs` dire
3838
cp livestream_templates-template.json livestream_templates.json
3939
```
4040
4. Edit **config.json**:
41-
1. Put the obtained `api_id` and `api_hash` strings to same keys
42-
2. Put the obtained bot API token string to `token` key
41+
1. Put the obtained `api_id` and `api_hash` strings to the same keys
42+
2. Put the obtained bot API token string to the `token` key
4343
3. [Find](https://stackoverflow.com/a/32777943) your Telegram user id
4444
and put it to `chat_users`, `alert_users` and `startup_message_users` lists as
4545
integer value. Multiple ids can be used, just separate them with a comma.
46-
4. Hikvision camera settings are placed inside the `camera_list` section. Template
46+
4. Hikvision camera settings are placed inside the `camera_list` section. The template
4747
comes with two cameras
4848

49-
**Camera names should start with `cam_` prefix and end with
49+
**Camera names should start with the `cam_` prefix and end with
5050
digit suffix**: `cam_1`, `cam_2`, `cam_<digit>` with any description.
5151

5252
5. Write authentication credentials in `user` and `password` keys for every camera
53-
6. Same for `host`, which should include protocol, e.g. `http://192.168.1.1`
54-
7. In `alert` section you can enable sending picture on alert (Motion,
55-
Line Crossing and Intrusion (Field) Detection). Configure `delay` setting
53+
6. Same for `host`, which should include protocol e.g., `http://192.168.1.1`
54+
7. In the `alert` section you can enable sending pictures on alert (Motion,
55+
Line Crossing and Intrusion (Field) Detection). Configure the `delay` setting
5656
in seconds between pushing alert pictures. To send resized picture change
5757
`fullpic` to `false`
5858

@@ -188,10 +188,10 @@ Configuration files are stored in JSON format and can be found in `configs` dire
188188

189189
# Usage
190190
## Launch by using Docker and Docker Compose
191-
1. Set your timezone by editing `.env` file (`TZ=Europe/Kiev`).
192-
Currently, there is Ukrainian timezone because I live there.
191+
1. Set your timezone by editing the `.env` file (`TZ=Europe/Kiev`).
192+
Currently, there is a Ukrainian timezone because I live there.
193193
Look for your timezone here [http://www.timezoneconverter.com/cgi-bin/zoneinfo](http://www.timezoneconverter.com/cgi-bin/zoneinfo).
194-
If you want to use default UTC time format, set Greenwich Mean Time timezone `TZ=GMT`
194+
If you want to use the default UTC time format, set Greenwich Mean Time timezone `TZ=GMT`
195195

196196
2. Build an image and run a container in a detached mode
197197
```bash
@@ -201,12 +201,12 @@ If you want to use default UTC time format, set Greenwich Mean Time timezone `TZ
201201
# Commands
202202
| Command | Description |
203203
|---|---|
204-
| `/start` | Start the bot (one-time action during first start) and show help |
204+
| `/start` | Start the bot (one-time action during the first start) and show help |
205205
| `/help` | Show help message |
206206
| `/list_cams` | List all your cameras |
207207
| `/cmds_cam_*` | List commands for particular camera |
208208
| `/getpic_cam_*` | Get resized picture from your Hikvision camera |
209-
| `/getfullpic_cam_*` | Get full-sized picture from your Hikvision camera |
209+
| `/getfullpic_cam_*` | Get a full-sized picture from your Hikvision camera |
210210
| `/ir_on_cam_*` | Turn on Infrared mode |
211211
| `/ir_off_cam_*` | Turn off Infrared mode |
212212
| `/ir_auto_cam_*` | Turn on Infrared auto mode |
@@ -216,61 +216,61 @@ If you want to use default UTC time format, set Greenwich Mean Time timezone `TZ
216216
| `/ld_off_cam_*` | Disable Line Crossing Detection |
217217
| `/intr_on_cam_*` | Enable Intrusion (Field) Detection |
218218
| `/intr_off_cam_*` | Disable Intrusion (Field) Detection |
219-
| `/alert_on_cam_*` | Enable Alert (Alarm) mode. It means it will send respective alert to your account in Telegram |
220-
| `/alert_off_cam_*` | Disable Alert (Alarm) mode, no alerts will be sent when something detected |
219+
| `/alert_on_cam_*` | Enable Alert (Alarm) mode. It means it will send a respective alert to your account in Telegram |
220+
| `/alert_off_cam_*` | Disable Alert (Alarm) mode, no alerts will be sent when something is detected |
221221
| `/yt_on_cam_*` | Enable YouTube stream |
222222
| `/yt_off_cam_*` | Disable YouTube stream |
223223
| `/icecast_on_cam_*` | Enable Icecast stream |
224224
| `/icecast_off_cam_*` | Disable Icecast stream |
225225

226-
`*` - camera digit id, e.g. `cam_1`.
226+
`*` - camera digit id e.g., `cam_1`.
227227

228228
# Advanced Configuration
229229
## SRS
230-
[SRS](https://github.com/ossrs/srs/tree/4.0release) (Simple Realtime Server) is a re-stream server which takes a stream from your camera and re-streams it
231-
to any destination without touching native camera stream multiple times.
232-
SRS release version used in the bot is `4.0`.
230+
[SRS](https://github.com/ossrs/srs/tree/4.0release) (Simple Realtime Server) is a re-stream server that takes a stream from your camera and re-streams it
231+
to any destination without touching the native camera stream multiple times.
232+
The SRS release version used in the bot is `4.0`.
233233

234234
SRS decreases CPU time and network load on the camera when you enable something like DVR,
235235
YouTube Livestream or try to get Video GIF at the same time. Pictures are taken
236236
directly from the camera stream, not from the SRS.
237237

238238
How it works - if you have two cameras with enabled SRS for both, there will be two
239239
running 24/7 bot tasks taking streams from the cameras to the SRS server. Eventually, when you
240-
request Video Gif, or it's triggered by some alert, video will be taken from SRS server.
240+
request Video Gif, or it's triggered by some alert, the video will be taken from the SRS server.
241241
242-
You can also connect to SRS server with any video player like VLC and watch the stream
242+
You can also connect to the SRS server with any video player like VLC and watch the stream
243243
without any interruptions. URL looks like this: `rtmp://192.168.1.100/live/livestream_101_cam_2`,
244244
where:
245245
1. `192.168.1.100` is an IP address or a host of your server.
246-
2. `101` is camera's configured stream channel.
247-
3. `cam_2` is ID of your second configured camera.
246+
2. `101` is the camera's configured stream channel.
247+
3. `cam_2` is the ID of your second configured camera.
248248

249249
SRS runs in a separate docker container. SRS config and `Dockerfile` are placed
250-
in `srs_prod` directory. Service name is `hikvision-srs-server` in `docker-compose.yml`.
250+
in the `srs_prod` directory. The service name is `hikvision-srs-server` in `docker-compose.yml`.
251251

252252

253253

254254
If `docker-compose.yml` is a list of forwarded and open SRS ports to the world:
255255
```yaml
256256
# If you don't plan to use anything from this, just comment out the whole section.
257257
ports:
258-
- "1935:1935" # SRS RTMP port, if you comment this out, you won't be able to connect with video player
258+
- "1935:1935" # SRS RTMP port, if you comment this out, you won't be able to connect with the video player
259259
- "1985:1985" # SRS API port, can be commented out since not used
260260
- "8080:8080" # SRS WebUI port
261261
```
262262

263263
## DVR
264-
You can record your videos from the camera to a local storage mounted as volume in
264+
You can record your videos from the camera to local storage mounted as a volume in
265265
volumes section of `hikvision-camera-bot` service in `docker-compose.yml`.
266266

267267
DVR configuration is per camera in `config.json` with livestream template name from `livestream_templates.json`.
268268

269269
It's very simple:
270-
1. Use `enabled` key to turn on/off this feature.
270+
1. Use the `enabled` key to turn on/off this feature.
271271
2. `local_storage_path` is a path inside the container to which videos will be recorded.
272272
Don't change this default value (`/data/dvr`) since it's written in the volumes mapping section.
273-
If you need to change it for some reason - you need to change both here and in the volumes mapping.
273+
If you need to change it for some reason - you must change it both here and in the volumes mapping.
274274
3. `livestream_template` has a template name located inside the `livestream_templates.json`
275275
file with DVR stream settings:
276276
```json
@@ -284,11 +284,11 @@ file with DVR stream settings:
284284
}
285285
}
286286
```
287-
a) `segment_time` is time in seconds when DVR record file will be split to a new one.
287+
a) `segment_time` is the time in seconds when the DVR record file will be split into a new one.
288288
289289
b) `1800` seconds mean every file will have 30 minutes of video recording.
290290
291-
c) File is named as `cam_1_101_1800_2022-04-15_21-19-32.mp4` with cam ID, channel name, segment time, and record start datetime.
291+
c) File is named `cam_1_101_1800_2022-04-15_21-19-32.mp4` with cam ID, channel name, segment time, and record start datetime.
292292
293293
4. Configuration part from the `config.json`:
294294
```json
@@ -308,12 +308,12 @@ file with DVR stream settings:
308308
}
309309
}
310310
```
311-
Recorded files can be uploaded to Telegram group. Right now upload will work only
312-
if `delete_after_upload` is set to `true` meaning uploaded file will be deleted
311+
Recorded files can be uploaded to the Telegram group. Right now, the upload will work only
312+
if `delete_after_upload` is set to `true` meaning the uploaded file will be deleted
313313
from the local storage. You need to make sure your file size will be up to 2GB since
314314
Telegram rejects larger ones. Just experiment with segment time.
315315
5. Local storage (the real one, not in the container) by default is `/data/dvr` in volumes mapping (the first path string, not the last).
316-
Change it to any location you need, e.g. to `- "D:\Videos:/data/dvr"` if you're on Windows.
316+
Change it to any location you need e.g., `- "D:\Videos:/data/dvr"` if you're on Windows.
317317
```yaml
318318
volumes:
319319
- "/data/dvr:/data/dvr"
@@ -332,22 +332,22 @@ To enable YouTube Live Stream enable it in the `youtube` key.
332332

333333
**Livestream templates**
334334

335-
To start particular livestream, user needs to set both *livestream* and
335+
To start a particular livestream, a user needs to set both *livestream* and
336336
*encoding* templates with stream settings and encoding type/arguments.
337337

338338
Encoding templates
339339

340-
`direct` means that video stream will not be re-encoded (transcoded) and will
340+
`direct` means that the video stream will not be re-encoded (transcoded) and will
341341
be sent to YouTube/Icecast servers "as is", only audio can be disabled.
342342

343-
`x264` or `vp9` means that video stream will be re-encoded on your machine/server
344-
where bot is running using respective encoding codecs.
343+
`x264` or `vp9` means that the video stream will be re-encoded on your machine/server
344+
where the bot is running using respective encoding codecs.
345345

346-
User can create its own templates in file named `livestream_templates.json`
346+
User can create their templates in a file named `livestream_templates.json`
347347
and `encoding_templates.json`.
348348

349-
Default dummy template file is named `livestream_templates_template.json`
350-
(not very funny name but anyway) which should be copied or renamed to
349+
The default dummy template file is named `livestream_templates_template.json`
350+
(not a very funny name but anyway) which should be copied or renamed to
351351
`livestream_templates.json`.
352352

353353
Same for `encoding_templates-template.json` -> `encoding_templates.json`
@@ -411,7 +411,7 @@ Where:
411411

412412
| Parameter | Value | Description |
413413
|---|---|---|
414-
| `channel` | `101` | camera channel. 101 is main stream, 102 is substream. |
414+
| `channel` | `101` | camera channel. 101 is the main stream, and 102 is the substream. |
415415
| `restart_period` | `39600` | stream restart period in seconds |
416416
| `restart_pause` | `10` | stream pause before starting on restart |
417417
| `url` | `"rtmp://a.rtmp.youtube.com/live2"` | YouTube rtmp server |
@@ -420,7 +420,7 @@ Where:
420420
| `ice_name` | `"Default"` | Icecast stream name |
421421
| `ice_description` | `"Default"` | Icecast stream description |
422422
| `ice_public` | `0` | Icecast public switch, default 0 |
423-
| `url` | `"icecast://source@x.x.x.x:8000/video.webm"` | Icecast server URL, Port and media mount point |
423+
| `url` | `"icecast://source@x.x.x.x:8000/video.webm"` | Icecast server URL, Port, and media mount point |
424424
| `password` | `"xxxx"` | Icecast authentication password |
425425
| `content_type` | `"video/webm"` | FFMPEG content-type for Icecast stream |
426426

bot.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import asyncio
55

66
from hikcamerabot.launcher import BotLauncher
7-
from hikcamerabot.utils.utils import setup_logging
7+
from hikcamerabot.utils.shared import setup_logging
88

99

1010
async def main() -> None:

hikcamerabot/bot_setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from hikcamerabot.camerabot import CameraBot
1111
from hikcamerabot.commands import setup_commands
1212
from hikcamerabot.config.config import get_main_config
13-
from hikcamerabot.utils.utils import build_command_presentation
13+
from hikcamerabot.utils.shared import build_command_presentation
1414

1515

1616
class BotSetup:

hikcamerabot/callbacks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from hikcamerabot.camera import HikvisionCam
77
from hikcamerabot.camerabot import CameraBot
8-
from hikcamerabot.clients.github_version.version_checker import (
8+
from hikcamerabot.clients.github.version_checker import (
99
HikCameraBotVersionChecker,
1010
)
1111
from hikcamerabot.clients.hikvision.enums import IrcutFilterType
@@ -19,7 +19,7 @@
1919
IrcutConfEvent,
2020
StreamEvent,
2121
)
22-
from hikcamerabot.utils.utils import bold, send_text
22+
from hikcamerabot.utils.shared import bold, send_text
2323

2424
log = logging.getLogger(__name__)
2525

hikcamerabot/camera.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def __init__(self, id: str, conf: Dict, bot: 'CameraBot') -> None:
102102
self.hashtag = f'#{conf.hashtag.lower() if conf.hashtag else self.id}'
103103
self.group = conf.group or 'Default group'
104104
self.bot = bot
105-
self._log.debug('Initializing %s', self.description)
105+
self._log.debug('Initializing camera %s', self.description)
106106
self._api = HikvisionAPI(api_client=HikvisionAPIClient(conf=conf.api))
107107
self._img_processor = ImageProcessor()
108108

@@ -119,7 +119,7 @@ def __init__(self, id: str, conf: Dict, bot: 'CameraBot') -> None:
119119
self._videogif = VideoGifRecorder(cam=self)
120120

121121
def __repr__(self) -> str:
122-
return f'<HikvisionCam desc="{self.description}">'
122+
return f'<HikvisionCam id="{self.id}" desc="{self.description}">'
123123

124124
async def start_videogif_record(
125125
self,

hikcamerabot/clients/github_version/version_checker.py hikcamerabot/clients/github/version_checker.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
@dataclass
1010
class BotVersion:
11+
"""Bot version DTO class."""
12+
1113
current: str
1214
latest: str
1315

@@ -27,11 +29,12 @@ def get_current_version(self) -> str:
2729
return __version__
2830

2931
async def get_latest_version(self) -> str:
32+
"""Get latest version number from latest GitHub tag URL."""
3033
self._log.info('Get latest hikvision-camera-bot version number')
3134
client: AsyncClient
3235
async with AsyncClient() as client:
3336
response = await client.head(self.LATEST_TAG_URL)
34-
version = response.headers.get('location').split('/')[-1]
37+
version: str = response.headers.get('location').split('/')[-1]
3538
self._log.info('Latest hikvision-camera-bot version number: %s', version)
3639
return version
3740

hikcamerabot/clients/hikvision/api_client.py

+3-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""Hikvision camera API client module."""
2-
import abc
32
import logging
43
from typing import Any
54
from urllib.parse import urljoin
@@ -13,29 +12,13 @@
1312
from hikcamerabot.exceptions import APIBadResponseCodeError, APIRequestError
1413

1514

16-
class AbstractHikvisionAPIClient(metaclass=abc.ABCMeta):
15+
class HikvisionAPIClient:
16+
"""Hikvision API Class."""
17+
1718
def __init__(self, conf: Dict) -> None:
1819
self._log = logging.getLogger(self.__class__.__name__)
1920
self._conf = conf
2021
self.host: str = self._conf.host
21-
22-
@abc.abstractmethod
23-
async def request(
24-
self,
25-
endpoint: str,
26-
data: Any = None,
27-
headers: dict = None,
28-
method: str = 'GET',
29-
timeout: float = CONN_TIMEOUT,
30-
) -> Any:
31-
pass
32-
33-
34-
class HikvisionAPIClient(AbstractHikvisionAPIClient):
35-
"""Hikvision API Class."""
36-
37-
def __init__(self, conf: Dict) -> None:
38-
super().__init__(conf)
3922
self.session = httpx.AsyncClient(
4023
auth=DigestAuthCached(
4124
username=self._conf.auth.user,
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22

3-
from hikcamerabot.clients.hikvision.api_client import AbstractHikvisionAPIClient
3+
from hikcamerabot.clients.hikvision import HikvisionAPIClient
44
from hikcamerabot.clients.hikvision.endpoints.endpoints import (
55
AlertStreamEndpoint,
66
ExposureEndpoint,
@@ -13,12 +13,12 @@
1313
class HikvisionAPI:
1414
"""Hikvision API Wrapper. API methods are Endpoint instances."""
1515

16-
def __init__(self, api_client: AbstractHikvisionAPIClient) -> None:
16+
def __init__(self, api_client: HikvisionAPIClient) -> None:
1717
self._log = logging.getLogger(self.__class__.__name__)
1818
self._api_client = api_client
1919

20-
self.alert_stream = AlertStreamEndpoint(self._api_client)
21-
self.take_snapshot = TakeSnapshotEndpoint(self._api_client)
22-
self.set_ircut_filter = IrcutFilterEndpoint(self._api_client)
23-
self.set_exposure = ExposureEndpoint(self._api_client)
24-
self.switch = SwitchEndpoint(self._api_client)
20+
self.alert_stream = AlertStreamEndpoint(api_client)
21+
self.take_snapshot = TakeSnapshotEndpoint(api_client)
22+
self.set_ircut_filter = IrcutFilterEndpoint(api_client)
23+
self.set_exposure = ExposureEndpoint(api_client)
24+
self.switch = SwitchEndpoint(api_client)

0 commit comments

Comments
 (0)