AndiHub

Code-Outlet von Andreas Bahr, Zürich

Cloudfree Online-Camera

Webkamera Hardware & Software zur Einbindung der Bilder in Webseiten

Demo

< Play Pause >

Klassische Online-Kamera

Diese Kamera postet Fotos via FTP auf einen Webserver. Der Webserver kann irgendwo im Internet stehen... oder auch direkt im eigenen LAN/WLAN. Das wäre dann quasi ein CCC - eine Closed Circuit Camera. So wie damals, vor dem Internetz...

Keine Clouddienste, keine Plattform-Abhängigkeit, keine AGB

Moderne "Internet of Things"-Produkte stellen typischerweise nach einigen Jahren Ihren Betrieb ein, weil die genutzten Cloud-Ressourcen ausgeschaltet werden. Ebenfalls problematisch sind nachträgliche Änderungen der Funktionsweise sowie "Zwangs-Updates" die Geld kosten. Aber das schlimmste Problem sind vermutlich die sich ständig ändernden AGB's, deren Regeln oft sehr unfair sind, oder gegen lokale Gesetze verstossen.

Webseiten-Toolkit

Das Toolkit für die Einbindung auf dem Webserver ist für die Verwendung mit Fotos ausgelegt. Bei der Entwicklung wurde darauf geachtet, sehr schnelle Bildwechsel zu ermöglichen, ohne Flimmern, Flackern oder Aussetzer. Das gilt auch für grosse Bilder-Sammlungen. Allerdings ist es sinnvoll, nicht mehr als 1000 Bilder gleichzeitig zu laden, der Aufruf der Seite kann sonst mehrere Sekunden dauern.

Web-Toolkit: Download

Bitte beachten Sie die Anleitung in Setup.txt

Heavy-Load Version für Martin: Download

Bilder-Administration: Download

Ein kleines Programm für unkompliziertes löschen einzelner oder mehrerer Bilder auf dem Webserver

Kamera-Hardware

Für die Kamera empfehle ich Original Maker-Komponenten von Raspberry Pi und Zubehör-Lieferanten. Je nach Anforderung, kann auch eine andere Kamera, oder ein alternativer Computer, verwendet werden. Datenübertragung via LAN / WLAN.

Standart-Konfiguration:

  • Raspberry Pi 3A oder B
  • Raspberry Pi Camera V2 oder HQ*
  • Passendes Gehäuse
  • Passendes Netzteil 5V, 2.5A
* Die HQ-Kamera benötigt zusätzlich ein passendes Objektiv

Situation 2022: Wegen der eingeschränkten Verfügbarkeit der Produkte von Raspberry Pi, bieten die Konkurrenten aus Asien eine gute Alternative. Die aus Hong Kong kommenden Kameras von ArduCam haben interessante Features wie Autofokus und mehr Megapixels...

Einfacher Prototyp einer kabellosen Kamera

Einfacher Prototyp einer kabellosen Kamera

Kamera-Software

Auf dem Kamera-Computer läuft motionEyeOS, eine Open-Source Software. Diese Software kostet keine Lizenzgebühr. Prinzipiell kann jede Software verwendet werden, die für Linux geschrieben wurde und auf ARM-Prozessoren kompiliert werden kann.

motionEyeOS: Website

Einige deutsche Webseiten mit Information zur Software:
Raspberry Pi Geek
Stefan's Weblog
Electreeks.de

Weitere Anwendungen

Eine Besonderheit der verwendeten Hardware ist die besonders einfache Programmierbarkeit in Python. Das ermöglicht vielfältige Anwendungen für Kameras, die durch Timer oder Sensoren gesteuert werden. Bilder können lokal gespeichert, über Netzwerke übertragen, oder auf Bildschirmen angezeigt werden.

 

Beispiel Python-Script

Das folgende Listing zeigt ein Script, das alle 30 Minuten ein Bild via FTP auf einen Server überträgt. Es prüft dabei zuerst, ob das Bild eine gewisse Helligkeit besitzt, um Nacht-Bilder auszuschliessen.

 
# foto-feeder FTP v0.1.2
# with luminance-check to avoid black pics
# Raspberry Pi and the Original V2 & HQ cameras
# 2021 Andreas Bahr
# license: GPL3

from picamera import PiCamera
import numpy as np
from time import sleep, localtime, strftime
import ftplib

# configuration
pixfolder = "/home/pi/DCIM/foto-feeder/"
minLuminance = 8 # 0...99, 0 = no luminance-threshold, max.: 255
ftpDomain = ""
ftpUser = ""
ftpPass = ""

def triggerCondition1():
    nowtime = localtime()
    # compare minutes from struct_time
    if(nowtime[4] == 0 or nowtime[4] == 30):
        return True
    else:
        return False

# https://picamera.readthedocs.io
# chapter 4.3 ... at the end
def captureLuminance():
    global camera
    y_data = np.empty((240, 320), dtype=np.uint8)
    try:
        camera.capture(y_data, 'yuv')
    except IOError:
        pass
    return int(np.mean(y_data))

def simpleLogger(text):
    global logfilename
    timestamp = strftime("%Y%m%d-%H%M%S: ", localtime())
    log = open(logfilename, "a")
    log.write(timestamp + text + "\n")
    log.close()

def singleFTPupload(filename, localFolder, ftpFolder, ftpDomain, ftpUser, ftpPass):
    # connect to ftp-host
    print("connect FTP host: " + ftpDomain + "...")
    with ftplib.FTP(ftpDomain, ftpUser, ftpPass) as ftp:
        #print(ftp.getwelcome())
        #ftp.dir()
        
        # change/make folder
        if(ftpFolder == "" or ftpFolder == "." or ftpFolder == "/"):
            pathReady = True
        else:
            pathReady = False
            try:
                ftp.cwd(ftpFolder)
                print("entered folder: " + ftpFolder)
                pathReady = True
            except ftplib.all_errors as e:
                print("FTP error while entering folder")
            if(not pathReady):
                try:
                    ftp.mkd(ftpFolder)
                    print("created folder: " + ftpFolder)
                except ftplib.all_errors as e:
                    print("FTP error: ", e)
                sleep(2)
                try:
                    ftp.cwd(ftpFolder)
                    pathReady = True
                except ftplib.all_errors as e:
                    print("FTP error while entering folder, again")
        
        # binary upload
        if(pathReady):
            try:
                with open(localFolder + filename, "rb") as fp:
                    res = ftp.storbinary("STOR " + filename, fp)
                    print(res)
                    if not res.startswith("226"):
                        simpleLogger("ERROR: FTP upload failed")
                    else:
                        simpleLogger("FTP upload successful")
            except ftplib.all_errors as e:
                print("FTP error: ", e)
        else:
            print("ERROR: FTP upload not possible!")
            simpleLogger("ERROR: FTP upload not possible!")

        ftp.quit()
        print("FTP disconnected")

# logfile
logfilename = strftime("ffeedr-log-%Y%m%d.txt", localtime())
print("foto-feeder FTP 2021 Andreas Bahr")
print("picture-folder: " + pixfolder)
simpleLogger("--------------------")
simpleLogger("foto-feeder FTP start")
simpleLogger("picture-folder: " + pixfolder)

# camera setup
simpleLogger("camera setup")
camera = PiCamera()
#camera.resolution = (4056, 3040) # HQ max. resolution, needs 256MB gpu-ram
#camera.resolution = (3280, 2464) # V2 max. resolution, needs 256MB gpu-ram
#camera.resolution = (2028, 1520) # matches HQ-sensor-mode 2
#camera.resolution = (1640, 1232)
#camera.resolution = (1920, 1080)
#camera.resolution = (1280, 960)
camera.resolution = (1024, 768)
#camera.resolution = (640, 480)
#camera.rotation = 180 # 0/90/180/270
print("capture device:", camera.revision)
print("----------------------------------------------------------")
simpleLogger("--------------------")

# main loop
simpleLogger("start preview")
camera.start_preview(alpha=128,resolution=(640,480))
sleep(3)
while True:
    if(triggerCondition1()):
        lumival = captureLuminance()
        print("luminance:", lumival)
        simpleLogger("luminance: " + str(lumival))
        if(minLuminance == 0 or lumival >= minLuminance):
            pixname = strftime("%H-%M-%S.jpg", localtime())
            camera.capture(pixfolder + pixname)
            print("new picture:", pixname)
            simpleLogger("captured " + pixname)
            dailyFolder = strftime("%Y-%m-%d", localtime())
            singleFTPupload(pixname, pixfolder, dailyFolder, ftpDomain, ftpUser, ftpPass)
        else:
            print("dark-mode: no picture captured")
            simpleLogger("dark-mode: no picture captured")
        print("----------------------------------------------------------")
    sleep(60)
camera.stop_preview()
camera.close()