{"id":20161567,"url":"https://github.com/openipc/python-dvr","last_synced_at":"2025-04-10T00:14:24.764Z","repository":{"id":205054827,"uuid":"713299595","full_name":"OpenIPC/python-dvr","owner":"OpenIPC","description":"python-dvr - library for configuring a wide range of IP cameras that use the NETsurveillance ActiveX plugin XMeye SDK","archived":false,"fork":false,"pushed_at":"2025-04-01T13:54:02.000Z","size":5081,"stargazers_count":32,"open_issues_count":0,"forks_count":7,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-10T00:14:19.199Z","etag":null,"topics":["openipc","python-dvr"],"latest_commit_sha":null,"homepage":"https://openipc.org","language":"Python","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenIPC.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"open_collective":"openipc"}},"created_at":"2023-11-02T08:41:42.000Z","updated_at":"2025-04-06T01:50:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"4fba4736-518e-4fe6-998c-60ceb811d15e","html_url":"https://github.com/OpenIPC/python-dvr","commit_stats":{"total_commits":11,"total_committers":4,"mean_commits":2.75,"dds":0.4545454545454546,"last_synced_commit":"e5976ab5d43664a83884441e30a696de5321dcd7"},"previous_names":["openipc/python-dvr"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenIPC%2Fpython-dvr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenIPC%2Fpython-dvr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenIPC%2Fpython-dvr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenIPC%2Fpython-dvr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenIPC","download_url":"https://codeload.github.com/OpenIPC/python-dvr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248131315,"owners_count":21052819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["openipc","python-dvr"],"created_at":"2024-11-14T00:19:34.156Z","updated_at":"2025-04-10T00:14:24.741Z","avatar_url":"https://github.com/OpenIPC.png","language":"Python","readme":"# python-dvr\n\nPython library for configuring a wide range of IP cameras that use the NETsurveillance ActiveX plugin\nXMeye SDK\n\n![screenshot](images/xm.jpg)\n\n## DeviceManager.py\n\nDeviceManager.py is a standalone Tkinter and console interface program such as the original DeviceManager.exe\nit possible to work on both systems, if there is no Tkinter it starts with a console interface\n\n## DVR-IP, NetSurveillance or \"Sofia\" Protocol\n\nThe NETSurveillance ActiveX plugin uses a TCP based protocol referred to simply as the \"Digital Video Recorder Interface Protocol\" by the \"Hangzhou male Mai Information Co\".\n\nThere is very little software support or documentation other than through tools provided by the manufacturers of these cameras, which leaves many configuration options inaccessible.\n\n- [Command and response codes](https://gist.github.com/ekwoodrich/a6d7b8db8f82adf107c3c366e61fd36f)\n\n- [Xiongmai DVR API v1.0, Russian](https://github.com/OpenIPC/python-dvr/blob/master/doc/Соглашение%20о%20интерфейсе%20цифрового%20видеорегистратора%20XiongmaiV1.0.doc)\n\n- [Xiongmai DVR API, 2013-01-11, Chinese](doc/雄迈数字视频录像机接口协议_V1.0.0.pdf)\n\n- [DVR API, brief description, Chinese](doc/配置交换格式V2.0.pdf)\n\n- [NETIP video/audio payload protocol, Chinese](doc/码流帧格式文档.pdf)\n\n### Similar projects\n\n- [sofiactl](https://github.com/667bdrm/sofiactl)\n\n- [DVRIP library and tools](https://github.com/alexshpilkin/dvrip)\n\n- [numenworld-ipcam](https://github.com/johndoe31415/numenworld-ipcam)\n\n### Server implementations\n\n* [OpenIPC](https://openipc.org/firmware/)\n\n## Basic usage\n\n```python\nfrom dvrip import DVRIPCam\nfrom time import sleep\n\nhost_ip = '192.168.1.10'\n\ncam = DVRIPCam(host_ip, user='admin', password='')\nif cam.login():\n\tprint(\"Success! Connected to \" + host_ip)\nelse:\n\tprint(\"Failure. Could not connect.\")\n\nprint(\"Camera time:\", cam.get_time())\n\n# Reboot camera\ncam.reboot()\nsleep(60) # wait while camera starts\n\n# Login again\ncam.login()\n# Sync camera time with PC time\ncam.set_time()\n# Disconnect\ncam.close()\n```\n\n## AsyncIO usage\n```python\nfrom asyncio_dvrip import DVRIPCam\nimport asyncio\nimport traceback\n\ndef stop(loop):\n  tasks = asyncio.gather(*asyncio.Task.all_tasks(loop=loop), loop=loop, return_exceptions=True)\n  tasks.add_done_callback(lambda t: loop.stop())\n  tasks.cancel()\n\nloop = asyncio.get_event_loop()\n\ndef onAlert(event, sequence_number):\n  print(event, sequence_number)\n\nasync def some_test_worker():\n  while True:\n    print(\"do some important work...\")\n\n    await asyncio.sleep(3)\n\nasync def main(loop):\n  host_ip = '192.168.1.10'\n  cam = DVRIPCam(host_ip, user='admin', password='')\n  try:\n    if not await cam.login():\n      raise Exception(\"Failure. Could not connect.\")\n\n    # -------------------------------\n\n    # take snapshot\n    image = await cam.snapshot()\n    # save it\n    with open(\"snap.jpeg\", \"wb\") as fp:\n      fp.write(image)\n\n    # -------------------------------\n\n    # write video\n    with open(\"datastream.h265\", \"wb\") as f:\n      await cam.start_monitor(lambda frame, meta, user: f.write(frame))\n\n    # -------------------------------\n\n    # or get alarms\n    cam.setAlarm(onAlert)\n    # will create new task\n    await cam.alarmStart(loop)\n\n    # so just wait or something else\n    while True:\n      await asyncio.sleep(1)\n\n    # -------------------------------\n\n  except:\n    pass\n  finally:\n    cam.close()\n\ntry:\n  loop.create_task(main(loop))\n  loop.create_task(some_test_worker())\n\n  loop.run_forever()\nexcept Exception as err:\n  msg = ''.join(traceback.format_tb(err.__traceback__) + [str(err)])\n  print(msg)\nfinally:\n  cam.close()\n  stop(loop)\n```\n\n## Camera settings\n\n```python\nparams = cam.get_general_info()\n```\n\nReturns general camera information (timezones, formats, auto reboot policy,\nsecurity options):\n\n```json\n{\n  \"AppBindFlag\": {\n    \"BeBinded\": false\n  },\n  \"AutoMaintain\": {\n    \"AutoDeleteFilesDays\": 0,\n    \"AutoRebootDay\": \"Tuesday\",\n    \"AutoRebootHour\": 3\n  },\n  \"DSTState\": {\n    \"InNormalState\": true\n  },\n  \"General\": {\n    \"AutoLogout\": 0,\n    \"FontSize\": 24,\n    \"IranCalendarEnable\": 0,\n    \"LocalNo\": 0,\n    \"MachineName\": \"LocalHost\",\n    \"OverWrite\": \"OverWrite\",\n    \"ScreenAutoShutdown\": 10,\n    \"ScreenSaveTime\": 0,\n    \"VideoOutPut\": \"Auto\"\n  },\n  \"Location\": {\n    \"DSTEnd\": {\n      \"Day\": 1,\n      \"Hour\": 1,\n      \"Minute\": 1,\n      \"Month\": 10,\n      \"Week\": 0,\n      \"Year\": 2021\n    },\n    \"DSTRule\": \"Off\",\n    \"DSTStart\": {\n      \"Day\": 1,\n      \"Hour\": 1,\n      \"Minute\": 1,\n      \"Month\": 5,\n      \"Week\": 0,\n      \"Year\": 2021\n    },\n    \"DateFormat\": \"YYMMDD\",\n    \"DateSeparator\": \"-\",\n    \"IranCalendar\": 0,\n    \"Language\": \"Russian\",\n    \"TimeFormat\": \"24\",\n    \"VideoFormat\": \"PAL\",\n    \"Week\": null,\n    \"WorkDay\": 62\n  },\n  \"OneKeyMaskVideo\": null,\n  \"PwdSafety\": {\n    \"PwdReset\": [\n      {\n        \"QuestionAnswer\": \"\",\n        \"QuestionIndex\": 0\n      },\n      {\n        \"QuestionAnswer\": \"\",\n        \"QuestionIndex\": 0\n      },\n      {\n        \"QuestionAnswer\": \"\",\n        \"QuestionIndex\": 0\n      },\n      {\n        \"QuestionAnswer\": \"\",\n        \"QuestionIndex\": 0\n      }\n    ],\n    \"SecurityEmail\": \"\",\n    \"TipPageHide\": false\n  },\n  \"ResumePtzState\": null,\n  \"TimingSleep\": null\n}\n```\n\n```python\nparams = cam.get_system_info()\n```\n\nReturns hardware specific settings, camera serial number, current software\nversion and firmware type:\n\n```json\n{\n  \"AlarmInChannel\": 2,\n  \"AlarmOutChannel\": 1,\n  \"AudioInChannel\": 1,\n  \"BuildTime\": \"2020-01-08 11:05:18\",\n  \"CombineSwitch\": 0,\n  \"DeviceModel\": \"HI3516EV300_85H50AI\",\n  \"DeviceRunTime\": \"0x0001f532\",\n  \"DigChannel\": 0,\n  \"EncryptVersion\": \"Unknown\",\n  \"ExtraChannel\": 0,\n  \"HardWare\": \"HI3516EV300_85H50AI\",\n  \"HardWareVersion\": \"Unknown\",\n  \"SerialNo\": \"a166379674a3b447\",\n  \"SoftWareVersion\": \"V5.00.R02.000529B2.10010.040600.0020000\",\n  \"TalkInChannel\": 1,\n  \"TalkOutChannel\": 1,\n  \"UpdataTime\": \"\",\n  \"UpdataType\": \"0x00000000\",\n  \"VideoInChannel\": 1,\n  \"VideoOutChannel\": 1\n}\n```\n\n```python\nparams = cam.get_system_capabilities()\n```\n\nReturns capabilities for the camera software (alarms and detection,\ncommunication protocols and hardware specific features):\n\n```json\n{\n  \"AlarmFunction\": {\n    \"AlarmConfig\": true,\n    \"BlindDetect\": true,\n    \"HumanDection\": true,\n    \"HumanPedDetection\": true,\n    \"LossDetect\": true,\n    \"MotionDetect\": true,\n    \"NetAbort\": true,\n    \"NetAlarm\": true,\n    \"NetIpConflict\": true,\n    \"NewVideoAnalyze\": false,\n    \"PEAInHumanPed\": true,\n    \"StorageFailure\": true,\n    \"StorageLowSpace\": true,\n    \"StorageNotExist\": true,\n    \"VideoAnalyze\": false\n  },\n  \"CommFunction\": {\n    \"CommRS232\": true,\n    \"CommRS485\": true\n  },\n  \"EncodeFunction\": {\n    \"DoubleStream\": true,\n    \"SmartH264\": true,\n    \"SmartH264V2\": false,\n    \"SnapStream\": true\n  },\n  \"NetServerFunction\": {\n    \"IPAdaptive\": true,\n    \"Net3G\": false,\n    \"Net4GSignalLevel\": false,\n    \"NetAlarmCenter\": true,\n    \"NetDAS\": false,\n    \"NetDDNS\": false,\n    \"NetDHCP\": true,\n    \"NetDNS\": true,\n    \"NetEmail\": true,\n    \"NetFTP\": true,\n    \"NetIPFilter\": true,\n    \"NetMutlicast\": false,\n    \"NetNTP\": true,\n    \"NetNat\": true,\n    \"NetPMS\": true,\n    \"NetPMSV2\": true,\n    \"NetPPPoE\": false,\n    \"NetRTSP\": true,\n    \"NetSPVMN\": false,\n    \"NetUPNP\": true,\n    \"NetWifi\": false,\n    \"OnvifPwdCheckout\": true,\n    \"RTMP\": false,\n    \"WifiModeSwitch\": false,\n    \"WifiRouteSignalLevel\": true\n  },\n  \"OtherFunction\": {\n    \"NOHDDRECORD\": false,\n    \"NoSupportSafetyQuestion\": false,\n    \"NotSupportAutoAndIntelligent\": false,\n    \"SupportAdminContactInfo\": true,\n    \"SupportAlarmRemoteCall\": false,\n    \"SupportAlarmVoiceTipInterval\": true,\n    \"SupportAlarmVoiceTips\": true,\n    \"SupportAlarmVoiceTipsType\": true,\n    \"SupportAppBindFlag\": true,\n    \"SupportBT\": true,\n    \"SupportBallTelescopic\": false,\n    \"SupportBoxCameraBulb\": false,\n    \"SupportCamareStyle\": true,\n    \"SupportCameraWhiteLight\": false,\n    \"SupportCfgCloudupgrade\": true,\n    \"SupportChangeLanguageNoReboot\": true,\n    \"SupportCloseVoiceTip\": false,\n    \"SupportCloudUpgrade\": true,\n    \"SupportCommDataUpload\": true,\n    \"SupportCorridorMode\": false,\n    \"SupportCustomizeLpRect\": false,\n    \"SupportDNChangeByImage\": false,\n    \"SupportDimenCode\": true,\n    \"SupportDoubleLightBoxCamera\": false,\n    \"SupportDoubleLightBulb\": false,\n    \"SupportElectronicPTZ\": false,\n    \"SupportFTPTest\": true,\n    \"SupportFaceDetectV2\": false,\n    \"SupportFaceRecognition\": false,\n    \"SupportMailTest\": true,\n    \"SupportMusicBulb433Pair\": false,\n    \"SupportMusicLightBulb\": false,\n    \"SupportNetWorkMode\": false,\n    \"SupportOSDInfo\": false,\n    \"SupportOneKeyMaskVideo\": false,\n    \"SupportPCSetDoubleLight\": true,\n    \"SupportPTZDirectionControl\": false,\n    \"SupportPTZTour\": false,\n    \"SupportPWDSafety\": true,\n    \"SupportParkingGuide\": false,\n    \"SupportPtz360Spin\": false,\n    \"SupportRPSVideo\": false,\n    \"SupportSetBrightness\": false,\n    \"SupportSetDetectTrackWatchPoint\": false,\n    \"SupportSetHardwareAbility\": false,\n    \"SupportSetPTZPresetAttribute\": false,\n    \"SupportSetVolume\": true,\n    \"SupportShowH265X\": true,\n    \"SupportSnapCfg\": false,\n    \"SupportSnapV2Stream\": true,\n    \"SupportSnapshotConfigV2\": false,\n    \"SupportSoftPhotosensitive\": true,\n    \"SupportStatusLed\": false,\n    \"SupportTextPassword\": true,\n    \"SupportTimeZone\": true,\n    \"SupportTimingSleep\": false,\n    \"SupportWebRTCModule\": false,\n    \"SupportWriteLog\": true,\n    \"SuppportChangeOnvifPort\": true\n  },\n  \"PreviewFunction\": {\n    \"Talk\": true,\n    \"Tour\": false\n  },\n  \"TipShow\": {\n    \"NoBeepTipShow\": true\n  }\n}\n```\n\n## Camera video settings/modes\n\n```python\nparams = cam.get_info(\"Camera\")\n# Returns data like this:\n# {'ClearFog': [{'enable': 0, 'level': 50}], 'DistortionCorrect': {'Lenstype': 0, 'Version': 0},\n# 'FishLensParam': [{'CenterOffsetX': 300, 'CenterOffsetY': 300, 'ImageHeight': 720,\n# 'ImageWidth': 1280, 'LensType': 0, 'PCMac': '000000000000', 'Radius': 300, 'Version': 1,\n# 'ViewAngle': 0, 'ViewMode': 0, 'Zoom': 100}], 'FishViCut': [{'ImgHeight': 0, 'ImgWidth': 0,\n# 'Xoffset': 0, 'Yoffset': 0}], 'Param': [{'AeSensitivity': 5, 'ApertureMode': '0x00000000',\n# 'BLCMode': '0x00000000', 'DayNightColor': '0x00000000', 'Day_nfLevel': 3, 'DncThr': 30,\n# 'ElecLevel': 50, 'EsShutter': '0x00000002', 'ExposureParam': {'LeastTime': '0x00000100',\n# 'Level': 0, 'MostTime': '0x00010000'}, 'GainParam': {'AutoGain': 1, 'Gain': 50},\n# 'IRCUTMode': 0, 'IrcutSwap': 0, 'Night_nfLevel': 3, 'PictureFlip': '0x00000000',\n# 'PictureMirror': '0x00000000', 'RejectFlicker': '0x00000000', 'WhiteBalance': '0x00000000'}],\n# 'ParamEx': [{'AutomaticAdjustment': 3, 'BroadTrends': {'AutoGain': 0, 'Gain': 50},\n# 'CorridorMode': 0, 'ExposureTime': '0x100', 'LightRestrainLevel': 16, 'LowLuxMode': 0,\n# 'PreventOverExpo': 0, 'SoftPhotosensitivecontrol': 0, 'Style': 'type1'}], 'WhiteLight':\n# {'MoveTrigLight': {'Duration': 60, 'Level': 3}, 'WorkMode': 'Auto', 'WorkPeriod':\n# {'EHour': 6, 'EMinute': 0, 'Enable': 1, 'SHour': 18, 'SMinute': 0}}}\n\n# Get current encoding settings\nenc_info = cam.get_info(\"Simplify.Encode\")\n# Returns data like this:\n# [{'ExtraFormat': {'AudioEnable': False, 'Video': {'BitRate': 552, 'BitRateControl': 'VBR',\n# 'Compression': 'H.265', 'FPS': 20, 'GOP': 2, 'Quality': 3, 'Resolution': 'D1'},\n# 'VideoEnable': True}, 'MainFormat': {'AudioEnable': False, 'Video': {'BitRate': 2662,\n# 'BitRateControl': 'VBR', 'Compression': 'H.265', 'FPS': 25, 'GOP': 2, 'Quality': 4,\n# 'Resolution': '1080P'}, 'VideoEnable': True}}]\n\n# Change bitrate\nNewBitrate = 7000\nenc_info[0]['MainFormat']['Video']['BitRate'] = NewBitrate\ncam.set_info(\"Simplify.Encode\", enc_info)\n\n# Get videochannel color parameters\ncolors = cam.get_info(\"AVEnc.VideoColor.[0]\")\n# Returns data like this:\n# [{'Enable': True, 'TimeSection': '0 00:00:00-24:00:00', 'VideoColorParam': {'Acutance': 3848,\n# 'Brightness': 50, 'Contrast': 50, 'Gain': 0, 'Hue': 50, 'Saturation': 50, 'Whitebalance': 128}},\n# {'Enable': False, 'TimeSection': '0 00:00:00-24:00:00', 'VideoColorParam': {'Acutance': 3848,\n# 'Brightness': 50, 'Contrast': 50, 'Gain': 0, 'Hue': 50, 'Saturation': 50, 'Whitebalance': 128}}]\n\n# Change IR Cut\ncam.set_info(\"Camera.Param.[0]\", { \"IrcutSwap\" : 0 })\n\n# Change WDR settings\nWDR_mode = True\ncam.set_info(\"Camera.ParamEx.[0]\", { \"BroadTrends\" : { \"AutoGain\" : int(WDR_mode) } })\n\n# Get network settings\nnet = cam.get_info(\"NetWork.NetCommon\")\n# Turn on adaptive IP mode\ncam.set_info(\"NetWork.IPAdaptive\", { \"IPAdaptive\": True })\n# Set camera hostname\ncam.set_info(\"NetWork.NetCommon.HostName\", \"IVG-85HG50PYA-S\")\n# Set DHCP mode (turn on in this case)\ndhcpst = cam.get_info(\"NetWork.NetDHCP\")\ndhcpst[0]['Enable'] = True\ncam.set_info(\"NetWork.NetDHCP\", dhcpst)\n\n# Enable/disable cloud support\ncloudEnabled = False\ncam.set_info(\"NetWork.Nat\", { \"NatEnable\" : cloudEnabled })\n```\n\n## Add user and change password\n\n```python\n#User \"test2\" with pssword \"123123\"\ncam.addUser(\"test2\",\"123123\")\n#Bad password, change it\ncam.changePasswd(\"321321\",cam.sofia_hash(\"123123\"),\"test2\")\n#And delete user \"test2\"\nif cam.delUser(\"test2\"):\n    print(\"User deleted\")\nelse:\n    print(\"Can not delete it\")\n#System users can not be deleted\nif cam.delUser(\"admin\"):\n    print(\"You do it! How?\")\nelse:\n    print(\"It system reserved user\")\n```\n\n## Investigate more settings\n\nSuggested approach will help understand connections between camera UI and API\nsettings. Fell free to send PR to the document to update information.\n\n```python\nfrom deepdiff import DeepDiff\nfrom pprint import pprint\n\nlatest = None\nwhile True:\n    current = cam.get_info(\"Camera\") # or \"General\", \"Simplify.Encode\", \"NetWork\"\n    if latest:\n        diff = DeepDiff(current, latest)\n        if diff == {}:\n            print(\"Nothing changed\")\n        else:\n            pprint(diff['values_changed'], indent = 2)\n    latest = current\n    input(\"Change camera setting via UI and then press Enter,\"\n          \" or double Ctrl-C to exit\\n\")\n```\n\n## Get JPEG snapshot\n\n```python\nwith open(\"snap.jpg\", \"wb\") as f:\n    f.write(cam.snapshot())\n```\n\n## Get video/audio bitstream\n\nVideo-only writing to file (using simple lambda):\n\n```python\nwith open(\"datastream.h265\", \"wb\") as f:\n    cam.start_monitor(lambda frame, meta, user: f.write(frame))\n```\n\nWriting datastream with additional filtering (capture first 100 frames):\n\n```python\nclass State:\n    def __init__(self):\n        self.counter = 0\n\n    def count(self):\n        return self.counter\n\n    def inc(self):\n        self.counter += 1\n\nwith open(\"datastream.h265\", \"wb\") as f:\n    state = State()\n    def receiver(frame, meta, state):\n        if 'frame' in meta:\n            f.write(frame)\n            state.inc()\n            print(state.count())\n            if state.count() == 100:\n                cam.stop_monitor()\n\n    cam.start_monitor(receiver, state)\n```\n\n## Set camera title\n\n```python\n# Simple way to change picture title\ncam.channel_title([\"Backyard\"])\n\n# Use unicode font from host computer to compose bitmap for title\nfrom PIL import Image, ImageDraw, ImageFont\n\nw_disp   = 128\nh_disp   =  64\nfontsize =  32\ntext     =  \"Туалет\"\n\nimageRGB = Image.new('RGB', (w_disp, h_disp))\ndraw  = ImageDraw.Draw(imageRGB)\nfont  = ImageFont.truetype(\"/Library/Fonts/Arial Unicode.ttf\", fontsize)\nw, h  = draw.textsize(text, font=font)\ndraw.text(((w_disp - w)/2, (h_disp - h)/2), text, font=font)\nimage1bit = imageRGB.convert(\"1\")\ndata = image1bit.tobytes()\ncam.channel_bitmap(w_disp, h_disp, data)\n\n# Use your own logo on picture\nimg = Image.open('vixand.png')\nwidth, height = img.size\ndata = img.convert(\"1\").tobytes()\ncam.channel_bitmap(width, height, data)\n```\n\n![screenshot](images/vixand.jpg)\n\n```sh\n# Show current temperature, velocity, GPS coordinates, etc\n# Use the same method to draw text to bitmap and transmit it to camera\n# but consider place internal bitmap storage to RAM:\nmount -t tmpfs -o size=100k tmpfs /mnt/mtd/tmpfs\nln -sf /mnt/mtd/tmpfs/0.dot /mnt/mtd/Config/Dot/0.dot\n```\n\n## OSD special text displaying\n\n```python\ncam.set_info(\"fVideo.OSDInfo\", {\"Align\": 2, \"OSDInfo\": [\n    {\n        \"Info\": [\n            \"АБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЭЮЯ\",\n            \"абвгдеёжзиклмеопрстуфхцчшщэюя\",\n            \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n            \"abcdefghijklmnopqrstuvwxyz\",\n            \"«»©°\\\"'()[]{}$%^\u0026*_+=0123456789\"\n        ],\n        \"OSDInfoWidget\": {\n            \"BackColor\": \"0x00000000\",\n            \"EncodeBlend\": True,\n            \"FrontColor\": \"0xD000FF00\",\n            \"PreviewBlend\": True,\n            \"RelativePos\": [20, 50, 0, 0]\n        }\n    }\n], \"strEnc\": \"UTF-8\"})\n```\n\n![screenshot](images/osd-new.png)\n\n## Upgrade camera firmware\n\n```python\n# Optional: get information about upgrade parameters\nprint(cam.get_upgrade_info())\n\n# Do upgrade\ncam.upgrade(\"General_HZXM_IPC_HI3516CV300_50H20L_AE_S38_V4.03.R12.Nat.OnvifS.HIK.20181126_ALL.bin\")\n```\n\n## Monitor Script\n\nThis script will persistently attempt to connect to camera at `CAMERA_IP`, will create a directory named `CAMERA_NAME` in `FILE_PATH` and start writing separate video and audio streams in files chunked in 10-minute clips, arranged in folders structured as `%Y/%m/%d`. It will also log what it does.\n\n```sh\n./monitor.py \u003cCAMERA_IP\u003e \u003cCAMERA_NAME\u003e \u003cFILE_PATH\u003e\n```\n\n## OPFeederFunctions\n\nThese functions are to handle the pet food dispenser when available.\nYou can see it with :\n\n```python\n\u003e\u003e\u003e cam.get_system_capabilities()['OtherFunction']['SupportFeederFunction']\nTrue\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eOPFeedManual\u003c/summary\u003e\n  \n  ```python\n  \u003e\u003e\u003e cam.set_command(\"OPFeedManual\", {\"Servings\": 1})\n  {'Name': 'OPFeedManual', 'OPFeedManual': {'Feeded': 1, 'NotFeeding': 0}, 'Ret': 100, 'SessionID': '0x38'}\n  ```\n  \n  Servings is the number of portions\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eOPFeedBook\u003c/summary\u003e\n  \n  ```python\n  \u003e\u003e\u003e cam.get_command(\"OPFeedBook\")\n  {'FeedBook': [{'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '03:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '09:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '06:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '15:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '12:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '21:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '18:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 1, 'Time': '00:00:00'}, {'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 5, 'Time': '01:00:00'}]}\n  ```\n\n  ```python\n  \u003e\u003e\u003e cam.set_command(\"OPFeedBook\", {\"Action\": \"Delete\", \"FeedBook\": [{'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 5, 'Time': '01:00:00'}]})\n  {'Name': 'OPFeedBook', 'Ret': 100, 'SessionID': '0x00000018'}\n  ```\n\n  ```python\n  \u003e\u003e\u003e cam.set_command(\"OPFeedBook\", {\"Action\": \"Add\", \"FeedBook\": [{'Enable': 1, 'RecDate': '2018-04-01', 'RecTime': '12:19:18', 'Servings': 5, 'Time': '01:00:00'}]})\n  {'Name': 'OPFeedBook', 'Ret': 100, 'SessionID': '0x00000018'}\n  ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eOPFeedHistory\u003c/summary\u003e\n  \n  ```python\n  \u003e\u003e\u003e cam.get_command(\"OPFeedHistory\")\n  {'FeedHistory': [{'Date': '2022-08-29', 'Servings': 1, 'Time': '18:49:45', 'Type': 2}, {'Date': '2022-08-26', 'Servings': 3, 'Time': '07:30:12', 'Type': 1}]}\n  ```\n  \n  Type 1 : automatic\n\n  Type 2 : manual\n\n  ```python\n  \u003e\u003e\u003e cam.set_command(\"OPFeedHistory\", {\"Action\": \"Delete\", \"FeedHistory\": [{'Date': '2022-08-29', 'Servings': 1, 'Time': '19:40:01', 'Type': 2}]})\n  {'Name': 'OPFeedHistory', 'Ret': 100, 'SessionID': '0x00000027'}\n  ```\n\n\u003c/details\u003e\n\n## Troubleshooting\n\n```python\ncam.debug()\n# or to enable non-standard format\ncam.debug('%(asctime)s - %(name)s - %(levelname)s - %(message)s')\n```\n\n## Acknowledgements\n\n_Telnet access creds from gabonator_\n\nhttps://gist.github.com/gabonator/74cdd6ab4f733ff047356198c781f27d\n","funding_links":["https://opencollective.com/openipc"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenipc%2Fpython-dvr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenipc%2Fpython-dvr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenipc%2Fpython-dvr/lists"}