Thanks @James_Y for this. I managed to acquire a VS-DBC250-110 model (aka V-DBC2S) and have spent the last several days playing around with it.
Couple of things I can add to this thread:
-
I was able to solve the problem concerning having to re-mount after a reboot/restart.
I will say I looked for other ways to detect the doorbell button being pressed. I thought for sure that there was a configurable parameter somewhere that said what to do when the doorbell button was pressed. It appears that the play_sound
script is called from the init daemon, but nowhere could I find a parameter in the daemonâs config to tell it to do this. I next investigated whether or not the Vivotek software could detect a button push as an event. If it could, then one could also create actions (using the GUI) such as sending http notifications to a destination of your choice. I found where there was actually an event being defined in one of Vivotekâs xml files for a button press, but apparently it was not integrated in with the rest of the Vivotek software. So in the end, I came back to the solution everyone else uses, that is to mount the play_sound
script on a writable filesystem so that it could be modified.
-
http client - the camera has an http client, so it is possible to send an http based webhook directly to HA. To be honest, Iâm surprised the telnet solution worked, as from my understanding HA only has a single socket and its configured to run either http or https, but anyway glad it worked out.
-
http to https (essentially a proxy) - The camera also has a SSL Tunnel client/server that in theory could be used for carrying http, but I could not get it to work with my Home Assistant setup. As I use https (secured), I had to come up with another way to send a webhook to HA, and I ended up writing some simple python code that receives http GETs from the vivint doorbell, and relays a POST to HA using https.
-
HA Vivotek Integration - If you werenât aware, there is a vivotek camera integration for HA. I managed to get it working with the doorbell camera for streaming video (unfortunately there is no audio, and as I understand it, audio has yet to be incorporated in to HA streaming) and have gotten the snap shot to work so that you can actually take a picture of whoever presses the doorbell buttonâŚ
Remounting after reboot
I first tried the normal way which is to add an entry in /etc/fstab
. However after a reboot, what I found out was that the device blows away any changes that were made. In fact several files and directories in /etc/
are blown away and re-written. What I managed to figure out was that after the device reboots, Linux/Busybox calls a few init scripts, and one in particular is /etc/init.d/rcS
. Towards the end of it, it in turn calls all the scripts in /etc/rcS.d/
. Luckily this directory actually resides in /mnt/flash/etc/rcS.d/
which is writable and does not get blown away after reboot.
So in /mnt/flash/etc/rcS.d, add a file named say mount_doorbell
that will do the mount. Here is what is in mine::
#!/bin/sh
mount --bind /mnt/flash2/play_sound /usr/bin/play_sound
You can modify it if you put your play_sound script somewhere else. I put mine in the flash2 filesystem since it has lots of empty space.
HTTP Client
Within the play_sound script I added the following to it (within the else
statement):
if [ $1 == $DOORBELL_CHIME ] ; then
#httpclient -M POST -m ' ' -S HA_IPADDRESS 8123 "" "" -U /api/webhook/XXXX
httpclient -M GET -r "./temp" -S HA_IPADDRESS 8080 "" "" -U /api/webhook/XXXX
fi
The commented out httpclient
does a POST and the one you would need to send directly to HA. Iâve not been able to test this completely so it may not work exactly. The other httpclient
is the one I use to send to my python code.
Python Code
Its a work in progress, but I do have a working version I can share later. It will be standalone code that will need to be started using the method of your choice.
EDIT: Finally getting around to posting the http to https relay code.
This code will take the URL received from the vivint cameraâs http GET, which contains â/api/webhook/XXXXâ (where XXXX is the webhook) and relay it to HA using http POST and passing the â/api/webhook/XXXXâ to HA.
#!/usr/bin/python3
from http.server import BaseHTTPRequestHandler,HTTPServer
import requests
import logging
import logging.handlers #Needed for Syslog
import sys
#Change the following to fit your needs:
HA_URL1 = "https://<IPADDRESS_OR_DNS_OF_HA>:<HA_PORT>"
PORT_NUMBER = <PORT_TO_LISTEN_TO_FROM_VIVINT>
# Setup Logger for this server.
# If you want to see output to the Console, set CONSOLE = 1
# Otherwise logs go to local syslog server.
# If you want debug level output, then change the last two lines
# _LOGGER.setLevel from NOTSET to DEBUG.
CONSOLE = 0
_LOGGER = logging.getLogger(__name__)
if CONSOLE:
formatter = \
logging.Formatter('%(message)s')
handler1 = logging.StreamHandler(sys.stdout)
handler1.setFormatter(formatter)
handler1.setLevel(logging.NOTSET)
_LOGGER.addHandler(handler1)
else:
formatter2 = \
logging.Formatter('%(levelname)s %(asctime)s %(filename)s - %(message)s')
handler2 = logging.handlers.SysLogHandler(address = '/dev/log')
handler2.setFormatter(formatter2)
handler2.setLevel(logging.NOTSET)
_LOGGER.addHandler(handler2)
#_LOGGER.setLevel(logging.DEBUG)
_LOGGER.setLevel(logging.NOTSET)
def HAPost(url, path):
"""Send http/https POST to home assistant with api """
url = url + path
try:
response = requests.post(url)
#print(url, response)
_LOGGER.debug("Sending URL: %s", url)
_LOGGER.debug("Response: %s", response)
if str(response) == '<Response [201]>':
return 1
except(requests.exceptions.Timeout):
#HA is slow, just keep retrying
#print('requests.exceptions.Timeout')
_LOGGER.error("REQUESTS.TIMEOUT")
pass #do nothing
except(requests.exceptions.ConnectionError):
#print('REQUESTS.CONNECTION_ERROR to ',url)
_LOGGER.error("REQUESTS.CONNECTION_ERROR to %s",url)
return 1
#Handle an incoming request
class myHandler(BaseHTTPRequestHandler):
"""Handle the incoming HTTP GET or POST Request."""
def process_incoming(self):
"""Process the incoming request."""
#print("Path ", self.path)
#print("Headers: ", self.headers)
_LOGGER.debug("Received Path: %s", self.path)
_LOGGER.debug("Received Headers: %s", self.headers)
sendReply = False
position = self.path.find("/api/webhook/")
if position == -1:
#print("api/webhook/ portion of URL Not Found")
_LOGGER.warning("/api/webhook/ portion of URL Not Found")
else:
sendReply = True
url = HA_URL1
HAPost(url, self.path)
if sendReply == True:
#self.send_response(204) #Vivent doesn't like
self.send_response(200)
#Must return something to vivint even if null.
mimetype='text/html'
self.send_header('Content-type',mimetype)
self.end_headers()
self.wfile.write(str.encode('')) #encode string to bytes
else:
self.send_error(404,'The requested URL was not found: %s' % self.path)
return
def do_GET(self):
"""Process incoming GET requests."""
return self.process_incoming()
def do_POST(self):
"""Process incoming POST requests."""
return self.process_incoming()
def log_message(self, format, *args):
"""
Remove this method if you want to see
normal http.server output, otherwise
override the http.server output with
your own logger.
"""
_LOGGER.debug("%s - - [%s] %s\n" %
(self.client_address[0],
self.log_date_time_string(),
format%args))
return
try:
#Create and startup the server and define the handler to manage
# the incoming http requests.
server = HTTPServer(('', PORT_NUMBER), myHandler)
#print('Started httpserver on port ', PORT_NUMBER)
_LOGGER.info("Started http server on port: %s", PORT_NUMBER)
#Run forever
server.serve_forever()
except KeyboardInterrupt:
#print(' received, shutting down the server')
_LOGGER.info(' received, shutting down the server')
#print( '^C received, shutting down the server')
finally:
#print("Closing the socket. We're Done!")
_LOGGER.info("Closing the socket. We're Done!")
server.socket.close()