OpenALPR Webhook Processor for IP Cameras

tech101

Known around here
Joined
Mar 30, 2015
Messages
1,474
Reaction score
2,130
Location
SF BayArea, USA
Thank you so much @mlapaglia for this... This is pretty darn amazing I love it..


Quick question I have two LPRs.. Do I just add another camera in config file ?
 

biggen

Known around here
Joined
May 6, 2018
Messages
2,563
Reaction score
2,837
Yeah this is really the answer here. OpenALPR already sends this stuff anywhere you want via webhooks and its payload. To be able to parse .json as it comes in and inject the bits you want directly to the DB... Man that is sweet!
 

tech101

Known around here
Joined
Mar 30, 2015
Messages
1,474
Reaction score
2,130
Location
SF BayArea, USA
Just noticed, Since I am running Windows Docker version. When I sign out seems like it stops working. Anything I can do when Signed out the thing still can keep working Seems like the container/app stops upon signing out windows account.
 

mlapaglia

Getting comfortable
Joined
Apr 6, 2016
Messages
849
Reaction score
506
running the windows version should quit working when you log out too, right?
 

mlapaglia

Getting comfortable
Joined
Apr 6, 2016
Messages
849
Reaction score
506
or you could install unraid on your server, virtualize windows/blue iris, and slip the surly bonds of microsoft :)

1609804625930.png
 

mlapaglia

Getting comfortable
Joined
Apr 6, 2016
Messages
849
Reaction score
506
i have added a swagger endpoint to the service, go to `ipaddress:5000`to get to it:

1609822180168.png

Now that the plates are saving to the database this get method should return them in the call. no need to install a sql engine or run a bunch of sprocs, it's all handled by the service.
 

biggen

Known around here
Joined
May 6, 2018
Messages
2,563
Reaction score
2,837
Very cool! Is there anyway to make the port configurable? I'm already running a service on port 5000 on that machine. Also, is it possible to make this db searchable? Like for a given day or time?

This is amazing work. Seriously. The community will love this here.
 
Last edited:

biggen

Known around here
Joined
May 6, 2018
Messages
2,563
Reaction score
2,837
I'm getting an Exit 139 when trying to fire it up with the new image. Is that processor.db supposed to be a file? Because its actually creating it as a directory called processor.db and not a file. The directory inside is empty. Here are my settings:

Bash:
#!/bin/bash
docker run -d \
--name=openalprwebhookprocessor \
--net=bridge \
-v /home/joe/webhook_alpr/app/appsettings.json:/app/appsettings.json \
-v /home/joe/webhook_alpr/app/processor.db:/app/processor.db \
-p 3859:80 \
mlapaglia/openalprwebhookprocessor
JSON:
{
  "AllowedHosts": "*",
  "Cameras": {
    "Cameras": [
      {
        "Manufacturer": "Dahua",
        "OpenAlprCameraId": 123456789,
        "Password": "password",
        "UpdateOverlayTextUrl": "http://10.200.200.14/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=",
        "Username": "admin"
      }
    ]
  },
  "ConnectionStrings": {
    "ProcessorContext": "Data Source=processor.db"
  },
  "WebRequestLoggingEnabled": false
}
JSON:
{"log":"[12:51:33 WRN] 'AddEntityFramework*' was called on the service provider, but 'UseInternalServiceProvider' wasn't called in the DbContext options configuration. Remove the 'AddEntityFramework*' call as in most cases it's not needed and might cause conflicts with other products and services registered in the same service provider.\n","stream":"stdout","time":"2021-01-05T12:51:33.500913201Z"}
{"log":"[12:51:34 INF] Entity Framework Core 3.1.10 initialized 'ProcessorContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None\n","stream":"stdout","time":"2021-01-05T12:51:34.05881382Z"}
{"log":"[12:51:34 FTL] Application startup exception\n","stream":"stdout","time":"2021-01-05T12:51:34.235941313Z"}
{"log":"Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 10: 'disk I/O error'.\n","stream":"stdout","time":"2021-01-05T12:51:34.235988251Z"}
{"log":"   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)\n","stream":"stdout","time":"2021-01-05T12:51:34.235997163Z"}
{"log":"   at Microsoft.Data.Sqlite.SqliteConnection.Open()\n","stream":"stdout","time":"2021-01-05T12:51:34.236004498Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(Boolean errorsExpected)\n","stream":"stdout","time":"2021-01-05T12:51:34.236012511Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)\n","stream":"stdout","time":"2021-01-05T12:51:34.236019163Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal.SqliteDatabaseCreator.Exists()\n","stream":"stdout","time":"2021-01-05T12:51:34.236025584Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()\n","stream":"stdout","time":"2021-01-05T12:51:34.236032089Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()\n","stream":"stdout","time":"2021-01-05T12:51:34.236038568Z"}
{"log":"   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetAppliedMigrations(DatabaseFacade databaseFacade)\n","stream":"stdout","time":"2021-01-05T12:51:34.236045129Z"}
{"log":"   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetPendingMigrations(DatabaseFacade databaseFacade)\n","stream":"stdout","time":"2021-01-05T12:51:34.236051676Z"}
{"log":"   at OpenAlprWebhookProcessor.Startup.MigrateDb(IApplicationBuilder app) in /src/OpenAlprWebhookProcessor/Startup.cs:line 97\n","stream":"stdout","time":"2021-01-05T12:51:34.236058512Z"}
{"log":"   at OpenAlprWebhookProcessor.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in /src/OpenAlprWebhookProcessor/Startup.cs:line 73\n","stream":"stdout","time":"2021-01-05T12:51:34.236065356Z"}
{"log":"   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)\n","stream":"stdout","time":"2021-01-05T12:51:34.236074459Z"}
{"log":"   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\n","stream":"stdout","time":"2021-01-05T12:51:34.236081306Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)\n","stream":"stdout","time":"2021-01-05T12:51:34.236088195Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.\u003c\u003ec__DisplayClass4_0.\u003cBuild\u003eb__0(IApplicationBuilder builder)\n","stream":"stdout","time":"2021-01-05T12:51:34.236094966Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.\u003c\u003ec__DisplayClass13_0.\u003cUseStartup\u003eb__2(IApplicationBuilder app)\n","stream":"stdout","time":"2021-01-05T12:51:34.23610533Z"}
{"log":"   at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.\u003c\u003ec__DisplayClass0_0.\u003cConfigure\u003eg__MiddlewareFilterBuilder|0(IApplicationBuilder builder)\n","stream":"stdout","time":"2021-01-05T12:51:34.236112875Z"}
{"log":"   at Microsoft.AspNetCore.HostFilteringStartupFilter.\u003c\u003ec__DisplayClass0_0.\u003cConfigure\u003eb__0(IApplicationBuilder app)\n","stream":"stdout","time":"2021-01-05T12:51:34.236121639Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)\n","stream":"stdout","time":"2021-01-05T12:51:34.236150155Z"}
{"log":"Unhandled exception. Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 10: 'disk I/O error'.\n","stream":"stderr","time":"2021-01-05T12:51:34.246509833Z"}
{"log":"   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)\n","stream":"stderr","time":"2021-01-05T12:51:34.246539389Z"}
{"log":"   at Microsoft.Data.Sqlite.SqliteConnection.Open()\n","stream":"stderr","time":"2021-01-05T12:51:34.246544685Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(Boolean errorsExpected)\n","stream":"stderr","time":"2021-01-05T12:51:34.246548684Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)\n","stream":"stderr","time":"2021-01-05T12:51:34.246552633Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal.SqliteDatabaseCreator.Exists()\n","stream":"stderr","time":"2021-01-05T12:51:34.246557296Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()\n","stream":"stderr","time":"2021-01-05T12:51:34.246563737Z"}
{"log":"   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()\n","stream":"stderr","time":"2021-01-05T12:51:34.246570218Z"}
{"log":"   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetAppliedMigrations(DatabaseFacade databaseFacade)\n","stream":"stderr","time":"2021-01-05T12:51:34.246576675Z"}
{"log":"   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetPendingMigrations(DatabaseFacade databaseFacade)\n","stream":"stderr","time":"2021-01-05T12:51:34.246582661Z"}
{"log":"   at OpenAlprWebhookProcessor.Startup.MigrateDb(IApplicationBuilder app) in /src/OpenAlprWebhookProcessor/Startup.cs:line 97\n","stream":"stderr","time":"2021-01-05T12:51:34.246590031Z"}
{"log":"   at OpenAlprWebhookProcessor.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in /src/OpenAlprWebhookProcessor/Startup.cs:line 73\n","stream":"stderr","time":"2021-01-05T12:51:34.246597118Z"}
{"log":"   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)\n","stream":"stderr","time":"2021-01-05T12:51:34.246603986Z"}
{"log":"   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\n","stream":"stderr","time":"2021-01-05T12:51:34.246610478Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)\n","stream":"stderr","time":"2021-01-05T12:51:34.246619058Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.\u003c\u003ec__DisplayClass4_0.\u003cBuild\u003eb__0(IApplicationBuilder builder)\n","stream":"stderr","time":"2021-01-05T12:51:34.24662573Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.\u003c\u003ec__DisplayClass13_0.\u003cUseStartup\u003eb__2(IApplicationBuilder app)\n","stream":"stderr","time":"2021-01-05T12:51:34.246633517Z"}
{"log":"   at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.\u003c\u003ec__DisplayClass0_0.\u003cConfigure\u003eg__MiddlewareFilterBuilder|0(IApplicationBuilder builder)\n","stream":"stderr","time":"2021-01-05T12:51:34.246640762Z"}
{"log":"   at Microsoft.AspNetCore.HostFilteringStartupFilter.\u003c\u003ec__DisplayClass0_0.\u003cConfigure\u003eb__0(IApplicationBuilder app)\n","stream":"stderr","time":"2021-01-05T12:51:34.246652006Z"}
{"log":"   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)\n","stream":"stderr","time":"2021-01-05T12:51:34.246658787Z"}
{"log":"   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)\n","stream":"stderr","time":"2021-01-05T12:51:34.246664799Z"}
{"log":"   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)\n","stream":"stderr","time":"2021-01-05T12:51:34.246699291Z"}
{"log":"   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)\n","stream":"stderr","time":"2021-01-05T12:51:34.246708412Z"}
{"log":"   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)\n","stream":"stderr","time":"2021-01-05T12:51:34.246714918Z"}
{"log":"   at OpenAlprWebhookProcessor.Program.Main(String[] args) in /src/OpenAlprWebhookProcessor/Program.cs:line 20\n","stream":"stderr","time":"2021-01-05T12:51:34.246721109Z"}
 

mlapaglia

Getting comfortable
Joined
Apr 6, 2016
Messages
849
Reaction score
506
ok, i'm going to move the configuration and db to a new folder, so we will only need to map that one directory instead of every file individually

docker run -d \
--name=openalprwebhookprocessor \
--net=bridge \
-v /app/config/:/app/config/ \
-p 3859:80 \
mlapaglia/openalprwebhookprocessor
 

biggen

Known around here
Joined
May 6, 2018
Messages
2,563
Reaction score
2,837
So it now creates the .db file in the appropriate directory, but I can't get the web page to load at ipaddress:5000. I just get a connection refused. I turned stopped my other service that was running at port 5000 for testing yours.

Bash:
#!/bin/bash

docker run -d \
--name=openalprwebhookprocessor \
--net=bridge \
-v /home/joe/webhook_alpr/app/config/:/app/config \
-p 3859:80 \
mlapaglia/openalprwebhookprocessor
JSON:
{
  "AllowedHosts": "*",
  "Cameras": {
    "Cameras": [
      {
        "Manufacturer": "Dahua",
        "OpenAlprCameraId": 123456789,
        "Password": "password",
        "UpdateOverlayTextUrl": "http://10.200.200.14/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=",
        "Username": "admin"
      }
    ]
  },
  "ConnectionStrings": {
    "ProcessorContext": "Data Source=config/processor.db"
  },
  "WebRequestLoggingEnabled": false
}
JSON:
{"log":"[14:16:05 WRN] 'AddEntityFramework*' was called on the service provider, but 'UseInternalServiceProvider' wasn't called in the DbContext options configuration. Remove the 'AddEntityFramework*' call as in most cases it's not needed and might cause conflicts with other products and services registered in the same service provider.\n","stream":"stdout","time":"2021-01-05T14:16:05.099247322Z"}
{"log":"[14:16:05 INF] Entity Framework Core 3.1.10 initialized 'ProcessorContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None\n","stream":"stdout","time":"2021-01-05T14:16:05.714673408Z"}
{"log":"[14:16:05 INF] Executed DbCommand (25ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n","stream":"stdout","time":"2021-01-05T14:16:05.918464887Z"}
{"log":"PRAGMA journal_mode = 'wal';\n","stream":"stdout","time":"2021-01-05T14:16:05.918544448Z"}
{"log":"[14:16:06 INF] Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n","stream":"stdout","time":"2021-01-05T14:16:06.097564684Z"}
{"log":"CREATE TABLE \"__EFMigrationsHistory\" (\n","stream":"stdout","time":"2021-01-05T14:16:06.09759607Z"}
{"log":"    \"MigrationId\" TEXT NOT NULL CONSTRAINT \"PK___EFMigrationsHistory\" PRIMARY KEY,\n","stream":"stdout","time":"2021-01-05T14:16:06.09760497Z"}
{"log":"    \"ProductVersion\" TEXT NOT NULL\n","stream":"stdout","time":"2021-01-05T14:16:06.097612504Z"}
{"log":");\n","stream":"stdout","time":"2021-01-05T14:16:06.097619143Z"}
{"log":"[14:16:06 INF] Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n","stream":"stdout","time":"2021-01-05T14:16:06.106067353Z"}
{"log":"SELECT COUNT(*) FROM \"sqlite_master\" WHERE \"name\" = '__EFMigrationsHistory' AND \"type\" = 'table';\n","stream":"stdout","time":"2021-01-05T14:16:06.106098635Z"}
{"log":"[14:16:06 INF] Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n","stream":"stdout","time":"2021-01-05T14:16:06.110761875Z"}
{"log":"SELECT \"MigrationId\", \"ProductVersion\"\n","stream":"stdout","time":"2021-01-05T14:16:06.110791343Z"}
{"log":"FROM \"__EFMigrationsHistory\"\n","stream":"stdout","time":"2021-01-05T14:16:06.110800678Z"}
{"log":"ORDER BY \"MigrationId\";\n","stream":"stdout","time":"2021-01-05T14:16:06.110807712Z"}
{"log":"[14:16:06 INF] Applying migration '20210104162820_initial'.\n","stream":"stdout","time":"2021-01-05T14:16:06.134069015Z"}
{"log":"[14:16:06 INF] Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n","stream":"stdout","time":"2021-01-05T14:16:06.170152486Z"}
{"log":"CREATE TABLE \"PlateGroups\" (\n","stream":"stdout","time":"2021-01-05T14:16:06.170182296Z"}
{"log":"    \"Id\" TEXT NOT NULL CONSTRAINT \"PK_PlateGroups\" PRIMARY KEY,\n","stream":"stdout","time":"2021-01-05T14:16:06.170192247Z"}
{"log":"    \"OpenAlprCameraId\" INTEGER NOT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170199399Z"}
{"log":"    \"OpenAlprProcessingTimeMs\" REAL NOT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170205463Z"}
{"log":"    \"IsAlert\" INTEGER NOT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170212115Z"}
{"log":"    \"AlertDescription\" TEXT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170218349Z"}
{"log":"    \"ReceivedOn\" TEXT NOT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170224481Z"}
{"log":"    \"PlateNumber\" TEXT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170230529Z"}
{"log":"    \"PlateJpeg\" TEXT NULL,\n","stream":"stdout","time":"2021-01-05T14:16:06.170236158Z"}
{"log":"    \"PlateConfidence\" REAL NOT NULL\n","stream":"stdout","time":"2021-01-05T14:16:06.170242276Z"}
{"log":");\n","stream":"stdout","time":"2021-01-05T14:16:06.170248771Z"}
{"log":"[14:16:06 INF] Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n","stream":"stdout","time":"2021-01-05T14:16:06.170455063Z"}
{"log":"INSERT INTO \"__EFMigrationsHistory\" (\"MigrationId\", \"ProductVersion\")\n","stream":"stdout","time":"2021-01-05T14:16:06.170472882Z"}
{"log":"VALUES ('20210104162820_initial', '3.1.10');\n","stream":"stdout","time":"2021-01-05T14:16:06.170480453Z"}
{"log":"[14:16:06 INF] Now listening on: http://[::]:80\n","stream":"stdout","time":"2021-01-05T14:16:06.321652579Z"}
{"log":"[14:16:06 INF] Application started. Press Ctrl+C to shut down.\n","stream":"stdout","time":"2021-01-05T14:16:06.322029646Z"}
{"log":"[14:16:06 INF] Hosting environment: Production\n","stream":"stdout","time":"2021-01-05T14:16:06.322134683Z"}
{"log":"[14:16:06 INF] Content root path: /app\n","stream":"stdout","time":"2021-01-05T14:16:06.322245201Z"}
 

biggen

Known around here
Joined
May 6, 2018
Messages
2,563
Reaction score
2,837
Its amazing how far you have come with this service. From printing overlays to inputting everything into a DB. Well done!
 

tech101

Known around here
Joined
Mar 30, 2015
Messages
1,474
Reaction score
2,130
Location
SF BayArea, USA
Thank you mlapaglia for creating this and improving/adding features so much for this in a very short time :)
 
Top