Compare commits

...

3 Commits

Author SHA1 Message Date
Cédric Verstraeten
bbbed49887 Add capabilities + fix typo 2023-04-07 08:41:47 +02:00
Cedric Verstraeten
87f681cfe1 fix show language selector 2023-03-23 18:08:20 +01:00
Cedric Verstraeten
f935360fda add delay when failed uploading, send to different mqtt topic when no hub + fixes responsiveness 2023-03-23 16:19:01 +01:00
10 changed files with 59 additions and 32 deletions

View File

@@ -97,11 +97,16 @@ This repository contains everything you'll need to know about our core product,
- Simplified and modern user interface.
- Multi architecture (ARMv7, ARMv8, amd64, etc).
- Multi camera support: IP Cameras (H264), USB cameras and Raspberry Pi Cameras [through a RTSP proxy](https://github.com/kerberos-io/camera-to-rtsp).
- Single camera per instance (e.g. oneå container per camera).
- Ability to specifiy conditions: motion region, time table, continuous recording, etc.
- Single camera per instance (e.g. one container per camera).
- Primary and secondary stream setup (record full-res, stream low-res).
- Low resolution streaming through MQTT and full resolution streaming through WebRTC.
- Ability to specifiy conditions: offline mode, motion region, time table, continuous recording, etc.
- Post- and pre-recording on motion detection.
- Ability to create fragmented recordings, and streaming though HLS fMP4.
- [Deploy where you want](#how-to-run-and-deploy-a-kerberos-agent) with the tools you use: `docker`, `docker compose`, `ansible`, `terraform`, `kubernetes`, etc.
- Cloud storage (Kerberos Hub, Kerberos Vault). WIP: Minio, Storj, etc.
- Cloud storage (Kerberos Hub, Kerberos Vault). WIP: Minio, Storj, Dropbox, Google Drive etc.
- WIP: Integrations (Webhooks, MQTT, Script, etc).
- REST API access and documentation through Swagger (trigger recording, update configuration, etc).
- MIT License
## How to run and deploy a Kerberos Agent

View File

@@ -54,6 +54,9 @@ func HandleUpload(configuration *models.Configuration, communication *models.Com
log.Log.Debug("HandleUpload: stopping as Offline is enabled.")
} else {
// Half a second delay between two uploads
delay := 500 * time.Millisecond
loop:
for {
// This will check if we need to stop the thread,
@@ -69,6 +72,7 @@ func HandleUpload(configuration *models.Configuration, communication *models.Com
log.Log.Error("HandleUpload: " + err.Error())
} else {
for _, f := range ff {
// This will check if we need to stop the thread,
// because of a reconfiguration.
select {
@@ -89,6 +93,7 @@ func HandleUpload(configuration *models.Configuration, communication *models.Com
// Check if the file is uploaded, if so, remove it.
if uploaded {
delay = 500 * time.Millisecond // reset
err := os.Remove(watchDirectory + fileName)
if err != nil {
log.Log.Error("HandleUpload: " + err.Error())
@@ -107,8 +112,12 @@ func HandleUpload(configuration *models.Configuration, communication *models.Com
if err != nil {
log.Log.Error("HandleUpload: " + err.Error())
}
} else {
delay = 5 * time.Second // slow down
log.Log.Error("HandleUpload: " + err.Error())
}
time.Sleep(delay)
}
}
}

View File

@@ -164,8 +164,12 @@ func ProcessMotion(motionCursor *pubsub.QueueCursor, configuration *models.Confi
// If offline mode is disabled, send a message to the hub
if config.Offline == "false" {
if mqttClient != nil && key != "" {
mqttClient.Publish("kerberos/"+key+"/device/"+config.Key+"/motion", 2, false, "motion")
if mqttClient != nil {
if key != "" {
mqttClient.Publish("kerberos/"+key+"/device/"+config.Key+"/motion", 2, false, "motion")
} else {
mqttClient.Publish("kerberos/device/"+config.Key+"/motion", 2, false, "motion")
}
}
}

View File

@@ -4,7 +4,7 @@
"private": false,
"dependencies": {
"@giantmachines/redux-websocket": "^1.5.1",
"@kerberos-io/ui": "^1.71.0",
"@kerberos-io/ui": "^1.72.0",
"@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.11.3",
"@testing-library/jest-dom": "^5.16.5",

View File

@@ -1,5 +1,20 @@
@import "./app.variables";
.grid-container {
row-gap: size(2);
}
.main {
padding-top: size(7);
@media (min-width: 800px) {
padding-top: 0;
}
}
.MuiPopover-root {
z-index: 99999999 !important;
}
.offline-mode, .cloud-not-installed {
background: var(--upper-gradient);

View File

@@ -46,11 +46,3 @@ export function doCheckIfInstalled(onSuccess, onError) {
}
});
}
/* export function doAuth(onSuccess, onError) {
}
export function doRefreshToken(onSuccess, onError) {
} */

View File

@@ -220,14 +220,21 @@ class Dashboard extends React.Component {
id="cells1"
bodycells={[
<>
<div className="time">
<div
className="time"
onClick={() =>
this.openModal(
`${config.URL}/file/${event.key}`
)
}
>
<Ellipse status="success" />{' '}
<p data-tip="10m and 5s ago">{event.time}</p>
</div>
</>,
<>
<p
className="pointer"
className="pointer event-description"
onClick={() =>
this.openModal(
`${config.URL}/file/${event.key}`

View File

@@ -1,3 +1,5 @@
@import "../../app.variables";
#dashboard {
hr {
@@ -15,6 +17,13 @@
video {
width: 100%;
}
p.event-description {
display: none;
@media (min-width: 800px) {
display: block;
}
}
a {
display: flex;

View File

@@ -3,11 +3,8 @@ import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import {
Breadcrumb,
VideoContainer,
VideoCard,
ControlBar,
Button,
Input,
Modal,
ModalHeader,
ModalBody,
@@ -105,17 +102,7 @@ class Media extends React.Component {
</Link>
</Breadcrumb>
<ControlBar>
<Input
iconleft="search"
onChange={() => {}}
placeholder={t('recordings.search_media')}
layout="controlbar"
type="text"
/>
</ControlBar>
<VideoContainer cols={4} isVideoWall={false}>
<div className="stats grid-container --four-columns">
{events.map((event) => (
<div
key={event.key}
@@ -135,7 +122,7 @@ class Media extends React.Component {
/>
</div>
))}
</VideoContainer>
</div>
{open && (
<Modal>
<ModalHeader

View File

@@ -12,7 +12,6 @@
}
}
.table-container table {
border-spacing: 0 12px;
width: 100%;