├── frontend ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── js │ │ │ └── script.js │ │ ├── images │ │ │ ├── logo.png │ │ │ ├── default-rpi.png │ │ │ ├── dropflower.png │ │ │ └── spinnerbggood.png │ │ └── css │ │ │ └── style.css │ ├── app │ │ ├── app.component.css │ │ ├── login │ │ │ ├── login.component.css │ │ │ ├── login.component.spec.ts │ │ │ ├── login-form │ │ │ │ └── login-form.component.css │ │ │ ├── login.routing.ts │ │ │ ├── login.component.ts │ │ │ └── login.module.ts │ │ ├── settings │ │ │ ├── settings.component.css │ │ │ ├── settings-rpi │ │ │ │ ├── rpi-add │ │ │ │ │ ├── rpi-add.component.css │ │ │ │ │ ├── rpi-add.component.html │ │ │ │ │ ├── rpi-add.component.ts │ │ │ │ │ └── rpi-add.component.spec.ts │ │ │ │ ├── settings-rpi.component.css │ │ │ │ ├── rpi-list │ │ │ │ │ ├── rpi-list.component.css │ │ │ │ │ ├── rpi-list.component.html │ │ │ │ │ ├── rpi-list.component.ts │ │ │ │ │ └── rpi-list.component.spec.ts │ │ │ │ ├── rpi-upload-image │ │ │ │ │ ├── rpi-upload-image.component.css │ │ │ │ │ ├── rpi-upload-image.component.html │ │ │ │ │ └── rpi-upload-image.component.spec.ts │ │ │ │ ├── rpicomponent-add │ │ │ │ │ ├── rpicomponent-add.component.css │ │ │ │ │ ├── rpicomponent-add.component.html │ │ │ │ │ ├── rpicomponent-add.component.ts │ │ │ │ │ └── rpicomponent-add.component.spec.ts │ │ │ │ ├── rpicomponent-form │ │ │ │ │ ├── rpicomponent-form.component.css │ │ │ │ │ ├── rpicomponent-form.component.html │ │ │ │ │ ├── rpicomponent-form.component.ts │ │ │ │ │ └── rpicomponent-form.component.spec.ts │ │ │ │ ├── rpicomponent-table │ │ │ │ │ ├── rpicomponent-filter │ │ │ │ │ │ ├── rpicomponent-filter.component.css │ │ │ │ │ │ ├── rpicomponent-filter.pipe.spec.ts │ │ │ │ │ │ └── filter-by.enum.ts │ │ │ │ │ ├── rpicomponent-table.component.css │ │ │ │ │ └── rpicomponent-table.component.spec.ts │ │ │ │ ├── rpi-form │ │ │ │ │ ├── rpi-form.component.css │ │ │ │ │ └── rpi-form.component.spec.ts │ │ │ │ ├── settings-rpi.component.html │ │ │ │ ├── rpi │ │ │ │ │ ├── rpi.component.css │ │ │ │ │ └── rpi.component.spec.ts │ │ │ │ ├── rpi-details │ │ │ │ │ ├── rpi-details.component.css │ │ │ │ │ └── rpi-details.component.spec.ts │ │ │ │ ├── settings-rpicomponent.service.spec.ts │ │ │ │ ├── rpi-pinout │ │ │ │ │ └── rpi-pinout.component.spec.ts │ │ │ │ └── settings-rpi.component.spec.ts │ │ │ ├── settings-user │ │ │ │ ├── settings-user.component.css │ │ │ │ ├── settings-user.component.html │ │ │ │ └── settings-user.component.ts │ │ │ ├── settings-schedule │ │ │ │ ├── settings-schedule.component.css │ │ │ │ ├── relay-schedule-form │ │ │ │ │ ├── relay-schedule-form.component.css │ │ │ │ │ └── relay-schedule-form.component.spec.ts │ │ │ │ └── relay-schedule-list │ │ │ │ │ └── relay-schedule-list.component.css │ │ │ ├── settings-rpicomponent │ │ │ │ ├── settings-rpicomponent.component.css │ │ │ │ ├── rpicomponent-add │ │ │ │ │ ├── rpicomponent-add.component.css │ │ │ │ │ ├── rpicomponent-add.component.html │ │ │ │ │ └── rpicomponent-add.component.spec.ts │ │ │ │ ├── rpicomponent-edit │ │ │ │ │ ├── rpicomponent-edit.component.css │ │ │ │ │ ├── rpicomponent-edit.component.html │ │ │ │ │ └── rpicomponent-edit.component.spec.ts │ │ │ │ ├── rpicomponent-form │ │ │ │ │ ├── rpicomponent-form.component.css │ │ │ │ │ └── rpicomponent-form.component.spec.ts │ │ │ │ ├── rpicomponent-table │ │ │ │ │ ├── rpicomponent-table.component.css │ │ │ │ │ ├── rpicomponent-list │ │ │ │ │ │ └── rpicomponent-list.component.css │ │ │ │ │ ├── rpicomponent-filter │ │ │ │ │ │ ├── rpicomponent-filter.component.css │ │ │ │ │ │ └── filter-by.enum.ts │ │ │ │ │ └── rpicomponent-table.component.spec.ts │ │ │ │ ├── settings-rpicomponent.service.spec.ts │ │ │ │ ├── settings-rpicomponent.component.html │ │ │ │ └── rpi-pinout │ │ │ │ │ └── rpi-pinout.component.spec.ts │ │ │ ├── settings.component.ts │ │ │ └── settings-navigation │ │ │ │ ├── settings-navigation.component.ts │ │ │ │ └── settings-navigation.component.css │ │ ├── navigation │ │ │ ├── navigation.component.css │ │ │ ├── navigation.component.spec.ts │ │ │ ├── notification-list │ │ │ │ ├── notification-list.component.css │ │ │ │ ├── notification-infinite-scroll.directive.ts │ │ │ │ ├── notification-infinite-scroll.directive.spec.ts │ │ │ │ ├── notification-list.component.ts │ │ │ │ ├── notification-list.component.html │ │ │ │ └── notification-list.component.spec.ts │ │ │ ├── notification │ │ │ │ ├── notification.component.css │ │ │ │ └── notification.component.spec.ts │ │ │ └── notification-dropdown │ │ │ │ └── notification-dropdown.component.css │ │ ├── dashboard-components │ │ │ ├── panel │ │ │ │ ├── panel.component.css │ │ │ │ ├── panel.component.html │ │ │ │ ├── panel.component.spec.ts │ │ │ │ └── fixed-side-panel │ │ │ │ │ └── fixed-side-panel.component.spec.ts │ │ │ ├── row │ │ │ │ ├── row.component.css │ │ │ │ ├── row.component.html │ │ │ │ └── row.component.spec.ts │ │ │ ├── column │ │ │ │ ├── column.component.css │ │ │ │ ├── column.component.html │ │ │ │ └── column.component.spec.ts │ │ │ └── widgets │ │ │ │ ├── graph │ │ │ │ ├── graph │ │ │ │ │ ├── graph.component.css │ │ │ │ │ ├── graph.component.html │ │ │ │ │ ├── graph-presets.ts │ │ │ │ │ ├── graph.component.ts │ │ │ │ │ └── graph.component.spec.ts │ │ │ │ └── graph-table │ │ │ │ │ ├── graph-table-options │ │ │ │ │ └── graph-table-options.component.css │ │ │ │ │ ├── graph-table.component.css │ │ │ │ │ ├── graph-table-data │ │ │ │ │ ├── graph-table-data.component.css │ │ │ │ │ └── graph-table-data.component.spec.ts │ │ │ │ │ └── graph-table.component.spec.ts │ │ │ │ ├── table │ │ │ │ ├── table │ │ │ │ │ ├── table.component.css │ │ │ │ │ ├── table.component.ts │ │ │ │ │ ├── table.component.spec.ts │ │ │ │ │ └── table.component.html │ │ │ │ └── pageable-table │ │ │ │ │ ├── pageable-table.component.css │ │ │ │ │ ├── pageable-table.component.ts │ │ │ │ │ └── pageable-table.component.spec.ts │ │ │ │ ├── control │ │ │ │ ├── relays │ │ │ │ │ ├── relays.component.css │ │ │ │ │ ├── relay.model.ts │ │ │ │ │ └── relays.component.html │ │ │ │ └── simple-relay │ │ │ │ │ ├── simple-relay.component.css │ │ │ │ │ └── simple-relay.component.spec.ts │ │ │ │ └── sensor │ │ │ │ ├── readings-list │ │ │ │ ├── readings-list.component.css │ │ │ │ └── readings-list.component.spec.ts │ │ │ │ └── simple-reading │ │ │ │ └── simple-reading.component.spec.ts │ │ ├── shared │ │ │ ├── component │ │ │ │ ├── alert │ │ │ │ │ ├── alert.component.css │ │ │ │ │ ├── alert.component.html │ │ │ │ │ └── alert.component.ts │ │ │ │ ├── modal-confirm │ │ │ │ │ ├── modal-confirm.component.css │ │ │ │ │ ├── modal-confirm.model.ts │ │ │ │ │ ├── modal-confirm.component.spec.ts │ │ │ │ │ └── modal-confirm.component.ts │ │ │ │ ├── page-loader │ │ │ │ │ ├── page-loader.component.html │ │ │ │ │ ├── spinnerbggood.png │ │ │ │ │ ├── page-loading.ts │ │ │ │ │ ├── page-loader.component.ts │ │ │ │ │ └── page-loader.component.spec.ts │ │ │ │ ├── unauthorized │ │ │ │ │ ├── unauthorized.component.css │ │ │ │ │ ├── unauthorized.component.ts │ │ │ │ │ └── unauthorized.component.html │ │ │ │ ├── panel-list-group │ │ │ │ │ ├── panel-list-group.component.css │ │ │ │ │ ├── panel-list-group.component.html │ │ │ │ │ └── panel-list-group.component.ts │ │ │ │ ├── simple-loader │ │ │ │ │ ├── simple-loader.component.html │ │ │ │ │ ├── simple-loader.component.ts │ │ │ │ │ ├── simple-loader.component.css │ │ │ │ │ └── simple-loader.component.spec.ts │ │ │ │ └── file-uploader │ │ │ │ │ ├── file-uploader.component.css │ │ │ │ │ └── file-uploader.component.spec.ts │ │ │ ├── model │ │ │ │ ├── paging │ │ │ │ │ ├── sort-direction.enum.ts │ │ │ │ │ ├── sort.model.ts │ │ │ │ │ └── page.model.ts │ │ │ │ ├── user │ │ │ │ │ ├── authority.enum.ts │ │ │ │ │ └── user.model.ts │ │ │ │ ├── rpipin │ │ │ │ │ ├── rpi-pin-direction.enum.ts │ │ │ │ │ └── rpi-pin.model.ts │ │ │ │ ├── rpi │ │ │ │ │ ├── rpi-type.enum.ts │ │ │ │ │ ├── system-state.enum.ts │ │ │ │ │ └── rpi.model.ts │ │ │ │ ├── dashboard │ │ │ │ │ ├── configuration │ │ │ │ │ │ ├── widget │ │ │ │ │ │ │ ├── graph │ │ │ │ │ │ │ │ ├── graph-widget-type.enum.ts │ │ │ │ │ │ │ │ ├── graph-table │ │ │ │ │ │ │ │ │ ├── orientation-type.enum.ts │ │ │ │ │ │ │ │ │ └── data-source │ │ │ │ │ │ │ │ │ │ ├── metric-data-type.enum.ts │ │ │ │ │ │ │ │ │ │ ├── metric-calculation.enum.ts │ │ │ │ │ │ │ │ │ │ ├── metric-time-span.enum.ts │ │ │ │ │ │ │ │ │ │ └── data-source.configuration.ts │ │ │ │ │ │ │ │ └── graph │ │ │ │ │ │ │ │ │ ├── graph-type.enum.ts │ │ │ │ │ │ │ │ │ └── graph.configuration.ts │ │ │ │ │ │ │ ├── table │ │ │ │ │ │ │ │ ├── table-widget-type.enum.ts │ │ │ │ │ │ │ │ └── table │ │ │ │ │ │ │ │ │ └── table.configuration.ts │ │ │ │ │ │ │ ├── widget.configuration.ts │ │ │ │ │ │ │ ├── control │ │ │ │ │ │ │ │ ├── control-widget-type.enum.ts │ │ │ │ │ │ │ │ ├── control-widget.configuration.ts │ │ │ │ │ │ │ │ ├── simple-relay │ │ │ │ │ │ │ │ │ ├── simple-relay-color.enum.ts │ │ │ │ │ │ │ │ │ └── simple-relay.configuration.ts │ │ │ │ │ │ │ │ ├── relay-list │ │ │ │ │ │ │ │ │ └── relay-list.configuration.ts │ │ │ │ │ │ │ │ └── control-widget.model.ts │ │ │ │ │ │ │ ├── sensor │ │ │ │ │ │ │ │ ├── sensor-widget-type.enum.ts │ │ │ │ │ │ │ │ ├── sensor-widget.configuration.ts │ │ │ │ │ │ │ │ ├── simple-reading │ │ │ │ │ │ │ │ │ ├── simple-reading-color.enum.ts │ │ │ │ │ │ │ │ │ └── simple-reading.configuration.ts │ │ │ │ │ │ │ │ ├── readings-list │ │ │ │ │ │ │ │ │ └── readings-list.configuration.ts │ │ │ │ │ │ │ │ └── sensor-widget.model.ts │ │ │ │ │ │ │ ├── widget-type.enum.ts │ │ │ │ │ │ │ └── widget.model.ts │ │ │ │ │ │ ├── panel │ │ │ │ │ │ │ ├── panel-location.enum.ts │ │ │ │ │ │ │ ├── panel-type.enum.ts │ │ │ │ │ │ │ ├── panel.model.ts │ │ │ │ │ │ │ └── panel.configuration.ts │ │ │ │ │ │ ├── shared │ │ │ │ │ │ │ └── sensor-reading-type.enum.ts │ │ │ │ │ │ ├── layout │ │ │ │ │ │ │ └── layout.model.ts │ │ │ │ │ │ ├── row │ │ │ │ │ │ │ ├── row.configuration.ts │ │ │ │ │ │ │ └── row.model.ts │ │ │ │ │ │ └── column │ │ │ │ │ │ │ ├── column.model.ts │ │ │ │ │ │ │ ├── column.configuration.ts │ │ │ │ │ │ │ ├── desktop-width.enum.ts │ │ │ │ │ │ │ ├── phone-width.enum.ts │ │ │ │ │ │ │ └── tablet-width.enum.ts │ │ │ │ │ ├── component-item │ │ │ │ │ │ ├── component-item.model.ts │ │ │ │ │ │ ├── control-component-item │ │ │ │ │ │ │ ├── control-component-item.enum.ts │ │ │ │ │ │ │ └── control-component-item.model.ts │ │ │ │ │ │ ├── graph-component-item │ │ │ │ │ │ │ ├── graph-component-item.enum.ts │ │ │ │ │ │ │ └── graph-component-item.model.ts │ │ │ │ │ │ ├── sensor-component-item │ │ │ │ │ │ │ ├── sensor-component-item.enum.ts │ │ │ │ │ │ │ └── sensor-component-item.model.ts │ │ │ │ │ │ ├── table-component-item │ │ │ │ │ │ │ ├── table-component-item.enum.ts │ │ │ │ │ │ │ └── table-component-item.model.ts │ │ │ │ │ │ └── component-item-type.enum.ts │ │ │ │ │ └── dashboard.model.ts │ │ │ │ ├── notification │ │ │ │ │ ├── notification-view.enum.ts │ │ │ │ │ └── notification.model.ts │ │ │ │ ├── rpicomponent │ │ │ │ │ ├── rpicomponent.preferences.ts │ │ │ │ │ ├── relay │ │ │ │ │ │ ├── relay-state.enum.ts │ │ │ │ │ │ ├── relay.preferences.ts │ │ │ │ │ │ ├── relaydto.model.ts │ │ │ │ │ │ └── relay.model.ts │ │ │ │ │ ├── rpicomponent-type.enum.ts │ │ │ │ │ ├── relay-schedule-job.model.ts │ │ │ │ │ ├── rpicomponent.model.ts │ │ │ │ │ ├── rpicomponent-sensor.preferences.ts │ │ │ │ │ ├── humidity-sensor │ │ │ │ │ │ ├── humidity-sensor.preferences.ts │ │ │ │ │ │ └── humidity-sensor.model.ts │ │ │ │ │ ├── moisture-sensor │ │ │ │ │ │ ├── moisture-sensor.preferences.ts │ │ │ │ │ │ └── moisture-sensor.model.ts │ │ │ │ │ ├── proximity-sensor │ │ │ │ │ │ ├── proximity-sensor.preferences.ts │ │ │ │ │ │ └── proximity-sensor.model.ts │ │ │ │ │ └── temperature-sensor │ │ │ │ │ │ ├── temperature-sensor.preferences.ts │ │ │ │ │ │ └── temperature-sensor.model.ts │ │ │ │ ├── schedule │ │ │ │ │ ├── frequency-metric.enum.ts │ │ │ │ │ ├── abstract-schedule-job.model.ts │ │ │ │ │ ├── fixed-time-schedule-job.model.ts │ │ │ │ │ └── interval-schedule-job.model.ts │ │ │ │ ├── humidity-data │ │ │ │ │ └── humidity-data.model.ts │ │ │ │ └── temperature-data │ │ │ │ │ └── temperature-data.model.ts │ │ │ ├── pipe │ │ │ │ ├── key-extract │ │ │ │ │ ├── key-extract.pipe.spec.ts │ │ │ │ │ └── key-extract.pipe.ts │ │ │ │ ├── key-to-title │ │ │ │ │ └── key-to-title.pipe.spec.ts │ │ │ │ └── celsius-to-fahrenheit │ │ │ │ │ ├── celsius-to-fahrenheit.pipe.spec.ts │ │ │ │ │ └── celsius-to-fahrenheit.pipe.ts │ │ │ └── directive │ │ │ │ └── scrollable │ │ │ │ └── scrollable.directive.spec.ts │ │ ├── dashboard-builder │ │ │ ├── components │ │ │ │ └── panel │ │ │ │ │ ├── panel.component.css │ │ │ │ │ └── panel.component.spec.ts │ │ │ ├── service │ │ │ │ ├── dashboard-builder.service.ts │ │ │ │ └── dashboard-builder.service.spec.ts │ │ │ ├── dashboard-builder-toolbar │ │ │ │ └── dashboard-builder-toolbar.component.css │ │ │ ├── dashboard-builder.routing.ts │ │ │ ├── directive │ │ │ │ └── panel-menu.directive.spec.ts │ │ │ ├── dashboard-builder.component.css │ │ │ └── dashboard-builder.component.spec.ts │ │ ├── app.component.html │ │ ├── core │ │ │ ├── component │ │ │ │ └── toaster │ │ │ │ │ ├── toast-message.model.ts │ │ │ │ │ ├── toast-type.enum.ts │ │ │ │ │ ├── toaster.component.html │ │ │ │ │ ├── toaster-location.enum.ts │ │ │ │ │ ├── toaster.service.spec.ts │ │ │ │ │ ├── toast-message │ │ │ │ │ ├── toast-message.component.css │ │ │ │ │ ├── toast-message.component.spec.ts │ │ │ │ │ ├── toast-message.component.ts │ │ │ │ │ └── toast-message.component.html │ │ │ │ │ └── toaster.component.spec.ts │ │ │ ├── service │ │ │ │ ├── base-api-url.default.ts │ │ │ │ ├── request-options.default.ts │ │ │ │ ├── crudoperations.interface.ts │ │ │ │ ├── rpi │ │ │ │ │ ├── rpi.service.spec.ts │ │ │ │ │ └── rpi.service.ts │ │ │ │ ├── sse │ │ │ │ │ └── sse.service.spec.ts │ │ │ │ ├── relay │ │ │ │ │ ├── relay.service.spec.ts │ │ │ │ │ └── relay-schedule.service.spec.ts │ │ │ │ ├── rpipin │ │ │ │ │ ├── rpi-pin.service.spec.ts │ │ │ │ │ └── rpi-pin.service.ts │ │ │ │ ├── dashboard │ │ │ │ │ ├── dashboard.service.spec.ts │ │ │ │ │ └── dashboard.service.ts │ │ │ │ ├── humidity-data │ │ │ │ │ └── humidity-data.service.spec.ts │ │ │ │ ├── notification │ │ │ │ │ └── notification.service.spec.ts │ │ │ │ ├── rpicomponent │ │ │ │ │ └── rpicomponent.service.spec.ts │ │ │ │ ├── humidity-sensor │ │ │ │ │ ├── humidity-sensor.service.spec.ts │ │ │ │ │ └── humidity-sensor.service.ts │ │ │ │ ├── moisture-sensor │ │ │ │ │ ├── moisture-sensor.service.spec.ts │ │ │ │ │ └── moisture-sensor.service.ts │ │ │ │ ├── proximity-sensor │ │ │ │ │ ├── proximity-sensor.service.spec.ts │ │ │ │ │ └── proximity-sensor.service.ts │ │ │ │ ├── temperature-data │ │ │ │ │ └── temperature-data.service.spec.ts │ │ │ │ ├── temperature-sensor │ │ │ │ │ ├── temperature-sensor.service.spec.ts │ │ │ │ │ └── temperature-sensor.service.ts │ │ │ │ └── temperature-humidity-sensor │ │ │ │ │ ├── temperature-humidity-sensor.service.spec.ts │ │ │ │ │ └── temperature-humidity-sensor.service.ts │ │ │ ├── resolve │ │ │ │ ├── find-all.resolve.ts │ │ │ │ ├── relay-find-all.resolve.ts │ │ │ │ ├── relay-find-one.resolve.ts │ │ │ │ ├── find-one.resolve.ts │ │ │ │ ├── humidity-sensor-find-all.resolve.ts │ │ │ │ ├── humidity-sensor-find-one.resolve.ts │ │ │ │ ├── moisture-sensor-find-all.resolve.ts │ │ │ │ ├── moisture-sensor-find-one.resolve.ts │ │ │ │ ├── proximity-sensor-find-all.resolve.ts │ │ │ │ ├── proximity-sensor-find-one.resolve.ts │ │ │ │ ├── temperature-sensor-find-all.resolve.ts │ │ │ │ └── temperature-sensor-find-one.resolve.ts │ │ │ └── core.module.ts │ │ ├── dashboard │ │ │ ├── dashboard.component.css │ │ │ ├── dashboard.routing.ts │ │ │ └── dashboard.module.ts │ │ ├── app.component.ts │ │ ├── authentication │ │ │ ├── authentication.service.spec.ts │ │ │ └── guard │ │ │ │ └── authentication.guard.ts │ │ └── app.module.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── favicon-old.ico │ ├── main.ts │ └── tsconfig.json ├── e2e │ ├── app.po.ts │ ├── app.e2e-spec.ts │ └── tsconfig.json ├── .editorconfig └── .gitignore ├── backend ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── gro │ │ │ │ ├── model │ │ │ │ ├── rpi │ │ │ │ │ └── RPiType.java │ │ │ │ ├── rpipin │ │ │ │ │ └── RPiPinDirection.java │ │ │ │ ├── rpicomponent │ │ │ │ │ ├── preferences │ │ │ │ │ │ ├── TemperatureUnit.java │ │ │ │ │ │ ├── HumiditySensorPreferences.java │ │ │ │ │ │ ├── MoistureSensorPreferences.java │ │ │ │ │ │ ├── RelayPreferences.java │ │ │ │ │ │ ├── ProximitySensorPreferences.java │ │ │ │ │ │ ├── TemperatureSensorPreferences.java │ │ │ │ │ │ └── TemperatureHumiditySensorPreferences.java │ │ │ │ │ ├── exception │ │ │ │ │ │ ├── InvalidRelayStateException.java │ │ │ │ │ │ ├── InvalidRPiComponentTypeException.java │ │ │ │ │ │ ├── EntityNotFoundException.java │ │ │ │ │ │ ├── RPiPinNotFoundException.java │ │ │ │ │ │ └── RPiComponentNotFoundException.java │ │ │ │ │ ├── data │ │ │ │ │ │ ├── RelayState.java │ │ │ │ │ │ ├── HumidityDTO.java │ │ │ │ │ │ └── ProximityDTO.java │ │ │ │ │ └── AbstractRPiComponentPreferences.java │ │ │ │ ├── NotFoundException.java │ │ │ │ ├── notification │ │ │ │ │ └── NotificationNotFoundException.java │ │ │ │ └── relay │ │ │ │ │ └── RelayScheduleJob.java │ │ │ │ ├── security │ │ │ │ ├── model │ │ │ │ │ └── AuthorityName.java │ │ │ │ ├── repository │ │ │ │ │ └── UserRepository.java │ │ │ │ └── service │ │ │ │ │ └── JwtAuthenticationResponse.java │ │ │ │ ├── scheduling │ │ │ │ ├── model │ │ │ │ │ ├── FrequencyMetric.java │ │ │ │ │ ├── FixedTimeJob.java │ │ │ │ │ ├── IntervalJob.java │ │ │ │ │ └── FixedTimeScheduleJob.java │ │ │ │ ├── service │ │ │ │ │ └── SchedulerService.java │ │ │ │ ├── ScheduleJobFactory.java │ │ │ │ ├── factory │ │ │ │ │ ├── ScheduleJobFactory.java │ │ │ │ │ ├── IntervalScheduleJobFactoryImpl.java │ │ │ │ │ └── FixedTimeScheduleJobFactoryImpl.java │ │ │ │ └── adapter │ │ │ │ │ ├── JobExecutionAdapter.java │ │ │ │ │ └── ScheduleJobExecutionAdapter.java │ │ │ │ ├── messaging │ │ │ │ ├── service │ │ │ │ │ └── TextMessageService.java │ │ │ │ └── gateway │ │ │ │ │ └── MqttOutboundGateway.java │ │ │ │ ├── web │ │ │ │ ├── service │ │ │ │ │ ├── ObjectSseEmitterService.java │ │ │ │ │ ├── storage │ │ │ │ │ │ ├── StorageService.java │ │ │ │ │ │ ├── StorageException.java │ │ │ │ │ │ └── StorageFileNotFoundException.java │ │ │ │ │ ├── HumidityDataService.java │ │ │ │ │ ├── TemperatureDataService.java │ │ │ │ │ └── SseEmitterService.java │ │ │ │ └── controller │ │ │ │ │ ├── MoistureSensorController.java │ │ │ │ │ ├── HumiditySensorController.java │ │ │ │ │ ├── ProximitySensorController.java │ │ │ │ │ └── TemperatureSensorController.java │ │ │ │ ├── repository │ │ │ │ ├── data │ │ │ │ │ └── ProximityDataRepository.java │ │ │ │ ├── rpi │ │ │ │ │ └── RPiRepository.java │ │ │ │ ├── rpicomponent │ │ │ │ │ ├── RPiComponentRepository.java │ │ │ │ │ ├── RPiPinRepository.java │ │ │ │ │ ├── RelayRepository.java │ │ │ │ │ ├── HumiditySensorRepository.java │ │ │ │ │ ├── MoistureSensorRepository.java │ │ │ │ │ ├── ProximitySensorRepository.java │ │ │ │ │ └── TemperatureSensorRepository.java │ │ │ │ ├── ReadOnlyRepository.java │ │ │ │ ├── schedule │ │ │ │ │ ├── ScheduleRepository.java │ │ │ │ │ ├── IntervalScheduleRepository.java │ │ │ │ │ ├── FixedTimeScheduleRepository.java │ │ │ │ │ └── RelayScheduleJobRepository.java │ │ │ │ ├── BaseRepository.java │ │ │ │ ├── NotificationRepository.java │ │ │ │ └── RestrictedWriteRepository.java │ │ │ │ ├── DemoApplication.java │ │ │ │ └── resources │ │ │ │ └── ObjectMapperFactory.java │ │ └── resources │ │ │ ├── quartz.properties │ │ │ └── ehcache.xml │ └── test │ │ └── java │ │ └── com │ │ └── gro │ │ └── DemoApplicationTests.java └── .gitignore └── .gitattributes /frontend/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/js/script.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/login/login.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/navigation.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/login/login-form/login-form.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/navigation.component.spec.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/panel/panel.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/row/row.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/alert/alert.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/column/column.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-add/rpi-add.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/settings-rpi.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-user/settings-user.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/components/panel/panel.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-list/rpi-list.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph/graph.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/table/table.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-schedule/settings-schedule.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/modal-confirm/modal-confirm.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/control/relays/relays.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/settings-rpicomponent.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-upload-image/rpi-upload-image.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-add/rpicomponent-add.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-form/rpicomponent-form.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/pageable-table/pageable-table.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-add/rpicomponent-add.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-edit/rpicomponent-edit.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-form/rpicomponent-form.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-schedule/relay-schedule-form/relay-schedule-form.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-schedule/relay-schedule-list/relay-schedule-list.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/paging/sort-direction.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SortDirection { 2 | ASC, 3 | DESC 4 | } -------------------------------------------------------------------------------- /frontend/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/favicon.ico -------------------------------------------------------------------------------- /frontend/src/app/shared/model/user/authority.enum.ts: -------------------------------------------------------------------------------- 1 | export enum Authority { 2 | ROLE_USER, 3 | ROLE_ADMIN 4 | } -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpipin/rpi-pin-direction.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RPiPinDirection { 2 | INPUT, OUTPUT 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/favicon-old.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/favicon-old.ico -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpi/rpi-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RpiType { 2 | RPI_3_MODEL_B = "RPI_3_MODEL_B" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph-widget-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum GraphWidgetType { 2 | } 3 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/table/table-widget-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum TableWidgetType { 2 | } 3 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-list/notification-list.component.css: -------------------------------------------------------------------------------- 1 | #notifications-list { 2 | max-height: 500px; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-add/rpicomponent-add.component.html: -------------------------------------------------------------------------------- 1 |

2 | rpicomponent-add works! 3 |

4 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-form/rpicomponent-form.component.html: -------------------------------------------------------------------------------- 1 |

2 | rpicomponent-form works! 3 |

4 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-table/rpicomponent-table.component.css: -------------------------------------------------------------------------------- 1 | hr { 2 | margin-top: 8px; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpi/system-state.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SystemState { 2 | UP = "Up", 3 | DOWN = "Down" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/assets/images/logo.png -------------------------------------------------------------------------------- /backend/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/backend/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpi/RPiType.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpi; 2 | 3 | public enum RPiType { 4 | RPI_3_MODEL_B 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Linguist 2 | frontend/node_modules/ linguist-vendored 3 | backend/target/ linguist-vendored 4 | backend/mvnw linguist-vendored 5 | -------------------------------------------------------------------------------- /frontend/src/assets/images/default-rpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/assets/images/default-rpi.png -------------------------------------------------------------------------------- /frontend/src/assets/images/dropflower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/assets/images/dropflower.png -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/component-item.model.ts: -------------------------------------------------------------------------------- 1 | export class ComponentItem { 2 | 3 | constructor() {} 4 | 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/assets/images/spinnerbggood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/assets/images/spinnerbggood.png -------------------------------------------------------------------------------- /frontend/src/app/shared/component/page-loader/page-loader.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /backend/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip 2 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/widget.configuration.ts: -------------------------------------------------------------------------------- 1 | export abstract class WidgetConfiguration { 2 | constructor() {} 3 | } 4 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpipin/RPiPinDirection.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpipin; 2 | 3 | public enum RPiPinDirection { 4 | INPUT, OUTPUT 5 | } 6 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/security/model/AuthorityName.java: -------------------------------------------------------------------------------- 1 | package com.gro.security.model; 2 | 3 | public enum AuthorityName { 4 | ROLE_USER, ROLE_ADMIN 5 | } -------------------------------------------------------------------------------- /frontend/src/app/shared/model/notification/notification-view.enum.ts: -------------------------------------------------------------------------------- 1 | export enum NotificationView { 2 | READ = "read", 3 | UNREAD = "unread" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-table/rpicomponent-filter/rpicomponent-filter.component.css: -------------------------------------------------------------------------------- 1 | .panel-nav { 2 | /*padding: 8px !important;*/ 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-table/rpicomponent-list/rpicomponent-list.component.css: -------------------------------------------------------------------------------- 1 | .label-direction { 2 | margin-right: 4px; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-table/rpicomponent-filter/rpicomponent-filter.component.css: -------------------------------------------------------------------------------- 1 | .panel-nav { 2 | /*padding: 8px !important;*/ 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/rpicomponent.preferences.ts: -------------------------------------------------------------------------------- 1 | export abstract class RPiComponentPreferences { 2 | 3 | constructor(public id: number) {} 4 | 5 | } 6 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/model/FrequencyMetric.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.model; 2 | 3 | public enum FrequencyMetric { 4 | SECONDS, MINUTES, HOURS 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/alert/alert.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{message}} 3 |
-------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/relay/relay-state.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RelayState { 2 | ON = "ON", 3 | OFF = "OFF", 4 | DISABLED = "DISABLED" 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/page-loader/spinnerbggood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmw5598/gro-light-automation/HEAD/frontend/src/app/shared/component/page-loader/spinnerbggood.png -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/control/relays/relay.model.ts: -------------------------------------------------------------------------------- 1 | export interface Relay { 2 | id: number; 3 | pinNum: number; 4 | alias: string; 5 | enabled: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/control-component-item/control-component-item.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ControlComponentItem { 2 | RELAY_TOGGLES = "Relay Toggles" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/schedule/frequency-metric.enum.ts: -------------------------------------------------------------------------------- 1 | export enum FrequencyMetric { 2 | SECONDS = "SECONDS", 3 | MINUTES = "MINUTES", 4 | HOURS = "HOURS" 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/panel/panel-location.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PanelLocation { 2 | LEFT = "Left", 3 | RIGHT = "Right", 4 | CENTER = "Center" 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-table/rpicomponent-table.component.css: -------------------------------------------------------------------------------- 1 | hr { 2 | margin-top: 8px; 3 | } 4 | 5 | .alert-component-custom { 6 | margin-bottom: 0px !important; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph-table/orientation-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum OrientationType { 2 | STACKED = "Stacked", 3 | INLINE = "Inline" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/control/control-widget-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ControlWidgetType { 2 | RELAY_LIST = "Relay List", 3 | SIMPLE_RELAY = "Simple" 4 | } 5 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/TemperatureUnit.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | public enum TemperatureUnit { 4 | CELSIUS, 5 | FAHRENHEIT 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/sensor/sensor-widget-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SensorWidgetType { 2 | READINGS_LIST = "Readings List", 3 | SIMPLE_SENSOR = "Simple Sensor" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/service/dashboard-builder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class DashboardBuilderService { 5 | 6 | constructor() { } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/graph-component-item/graph-component-item.enum.ts: -------------------------------------------------------------------------------- 1 | export enum GraphComponentItem { 2 | SIMPLE_GRAPH = "Simple Graph", 3 | GRAPH_TABLE = "Graph Table" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph-table/data-source/metric-data-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum MetricDataType { 2 | TEMPERATURE = "temperature", 3 | HUMIDITY = "humidity" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/widget-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum WidgetType { 2 | GRAPH = "Graph", 3 | TABLE = "Table", 4 | SENSOR = "Sensor", 5 | CONTROL = "Control" 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/unauthorized/unauthorized.component.css: -------------------------------------------------------------------------------- 1 | .unauthorized { 2 | margin-top: 60px !important; 3 | } 4 | 5 | .unauthorized .fa { 6 | margin-right: 10px !important; 7 | margin-left: 10px !important; 8 | } -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/sensor-component-item/sensor-component-item.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SensorComponentItem { 2 | SIMPLE_READING = "Simple Sensor", 3 | READING_LIST = "Reading List" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/table-component-item/table-component-item.enum.ts: -------------------------------------------------------------------------------- 1 | export enum TableComponentItem { 2 | SIMPLE_TABLE = "Simple Table", 3 | PAGEABLE_TABLE = "Pageable Table" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/component-item-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ComponentItemType { 2 | GRAPH = "Graph", 3 | TABLE = "Table", 4 | SENSOR = "Sensor", 5 | CONTROL = "Control" 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph-table/data-source/metric-calculation.enum.ts: -------------------------------------------------------------------------------- 1 | export enum MetricCalculation { 2 | AVERAGE = "average", 3 | HIGH = "high", 4 | LOW = "low" 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-form/rpi-form.component.css: -------------------------------------------------------------------------------- 1 | fieldset.form-section { 2 | margin-bottom: 16px; 3 | } 4 | 5 | fieldset.form-section > legend { 6 | font-size: 16px; 7 | 8 | padding-bottom: 4px; 9 | } 10 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/messaging/service/TextMessageService.java: -------------------------------------------------------------------------------- 1 | package com.gro.messaging.service; 2 | 3 | public interface TextMessageService { 4 | 5 | void sendSms(String message); 6 | void sendMms(String message); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/table/table/table.configuration.ts: -------------------------------------------------------------------------------- 1 | export class TableConfiguration { 2 | 3 | public visible: boolean; 4 | 5 | constructor() { 6 | this.visible = true; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/sensor/sensor-widget.configuration.ts: -------------------------------------------------------------------------------- 1 | import { SensorWidgetType } from './sensor-widget-type.enum'; 2 | 3 | export abstract class SensorWidgetConfiguration { 4 | 5 | constructor() {} 6 | 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/panel/panel-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PanelType { 2 | CENTER = "Center", 3 | FIXED_SIDE_LEFT = "Fixed Side Left", 4 | FIXED_SIDE_RIGHT = "Fixed Side Right", 5 | FULL = "Full" 6 | } 7 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/service/SchedulerService.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.service; 2 | 3 | public interface SchedulerService { 4 | public void addJob(I i); 5 | public void removeJob(I i); 6 | public void updateJob(I i); 7 | } 8 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/ObjectSseEmitterService.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class ObjectSseEmitterService extends AbstractSseEmitterService { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toast-message.model.ts: -------------------------------------------------------------------------------- 1 | import { ToastType } from './toast-type.enum'; 2 | 3 | export class ToastMessage { 4 | 5 | constructor( 6 | public type: ToastType, 7 | public message: string 8 | ) {} 9 | 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toast-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ToastType { 2 | DEFAULT = "alert-default", 3 | SUCCESS = "alert-success", 4 | INFO = "alert-info", 5 | WARNING = "alert-warning", 6 | DANGER = "alert-danger" 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/base-api-url.default.ts: -------------------------------------------------------------------------------- 1 | export const BASE_IMAGE_URL: string = 'http://localhost:8080/images/'; 2 | export const BASE_API_URL: string = 'http://localhost:8080/api/'; 3 | export const BASE_AUTH_URL: string = 'http://localhost:8080/auth/'; 4 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/shared/sensor-reading-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SensorReadingType { 2 | TEMPERATURE = "Temperature", 3 | HUMIDITY = "Humidity", 4 | PROXIMITY = "Proximity", 5 | MOISTURE = "Moisture" 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph-table/data-source/metric-time-span.enum.ts: -------------------------------------------------------------------------------- 1 | export enum MetricTimeSpan { 2 | HOURLY = "hourly", 3 | DAILY = "daily", 4 | WEEKLY = "weekly", 5 | MONTHLY = "monthly" 6 | } 7 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/storage/StorageService.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service.storage; 2 | 3 | import org.springframework.web.multipart.MultipartFile; 4 | 5 | public interface StorageService { 6 | void init(); 7 | void store(MultipartFile file); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toaster.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/layout/layout.model.ts: -------------------------------------------------------------------------------- 1 | import { Panel } from '@app/shared/model/dashboard/configuration/panel/panel.model'; 2 | 3 | export class Layout { 4 | 5 | constructor( 6 | public panels: Array 7 | ) {} 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class FrontendPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/login/login.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { LoginComponent } from '@app/login/login.component'; 4 | 5 | export const LOGIN_ROUTING: Routes = [ 6 | { 7 | path: '', 8 | component: LoginComponent 9 | } 10 | ]; 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/HumidityDataService.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.gro.model.rpicomponent.data.HumidityDTO; 6 | 7 | @Service 8 | public class HumidityDataService { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/panel-list-group/panel-list-group.component.css: -------------------------------------------------------------------------------- 1 | ul.panel-body-list { 2 | list-style: none; 3 | background: #546575; 4 | margin: 0; 5 | padding: 4px 0px; 6 | } 7 | 8 | ul.panel-body-list > li.panel-body-list-item { 9 | padding: 4px 16px; 10 | } -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph/graph-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum GraphType { 2 | LINE = "line", 3 | BAR = "bar", 4 | PIE = "pie", 5 | RADAR = "radar", 6 | DOUGHNUT = "doughnut", 7 | POLAR_AREA = "polarArea" 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/widget.model.ts: -------------------------------------------------------------------------------- 1 | import { WidgetConfiguration } from './widget.configuration'; 2 | import { WidgetType } from './widget-type.enum'; 3 | 4 | export abstract class Widget { 5 | 6 | constructor(widgetType: WidgetType) {} 7 | 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/dashboard-builder-toolbar/dashboard-builder-toolbar.component.css: -------------------------------------------------------------------------------- 1 | .dropshadow { 2 | -webkit-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 3 | -moz-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 4 | box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification/notification.component.css: -------------------------------------------------------------------------------- 1 | blockquote.notification-details { 2 | font-size: 14px; 3 | font-style: italic; 4 | margin: 8px; 5 | padding: 8px; 6 | } 7 | 8 | h6.notification-date-time { 9 | font-size: 11px; 10 | font-style: italic; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/dashboard.model.ts: -------------------------------------------------------------------------------- 1 | import { Layout } from '@app/shared/model/dashboard/configuration/layout/layout.model'; 2 | 3 | export class Dashboard { 4 | 5 | constructor( 6 | public name: string, 7 | public layout: Layout 8 | ) {} 9 | 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/relay/relay.preferences.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentPreferences } from '../rpicomponent.preferences'; 2 | 3 | export class RelayPreferences extends RPiComponentPreferences { 4 | 5 | constructor(id: number) { 6 | super(id); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/pipe/key-extract/key-extract.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { KeyExtractPipe } from './key-extract.pipe'; 2 | 3 | describe('KeyExtractPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new KeyExtractPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/graph-component-item/graph-component-item.model.ts: -------------------------------------------------------------------------------- 1 | import { ComponentItem } from '../component-item.model'; 2 | 3 | export class GraphComponentItem extends ComponentItem { 4 | 5 | constructor() { 6 | super(); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/sensor-component-item/sensor-component-item.model.ts: -------------------------------------------------------------------------------- 1 | import { ComponentItem } from '../component-item.model'; 2 | 3 | export class SensorComponentItem extends ComponentItem { 4 | 5 | constructor() { 6 | super(); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/table-component-item/table-component-item.model.ts: -------------------------------------------------------------------------------- 1 | import { ComponentItem } from '../component-item.model'; 2 | 3 | export class TableComponentItem extends ComponentItem { 4 | 5 | constructor() { 6 | super(); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/pipe/key-to-title/key-to-title.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { KeyToTitlePipe } from './key-to-title.pipe'; 2 | 3 | describe('KeyToTitlePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new KeyToTitlePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-upload-image/rpi-upload-image.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 7 |
8 |
9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/component-item/control-component-item/control-component-item.model.ts: -------------------------------------------------------------------------------- 1 | import { ComponentItem } from '../component-item.model'; 2 | 3 | export class ControlComponentItem extends ComponentItem { 4 | 5 | constructor() { 6 | super(); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/row/row.configuration.ts: -------------------------------------------------------------------------------- 1 | import { Column } from '../column/column.model'; 2 | 3 | export class RowConfiguration { 4 | 5 | columns: Array; 6 | 7 | constructor() { 8 | this.columns = new Array(); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toaster-location.enum.ts: -------------------------------------------------------------------------------- 1 | export enum ToasterLocation { 2 | TOP_LEFT = "toaster-location-top-left", 3 | TOP_RIGHT = "toaster-location-top-right", 4 | BOTTOM_LEFT = "toaster-location-bottom-left", 5 | BOTTOM_RIGHT = "toaster-location-bottom-right" 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-list/notification-infinite-scroll.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[appNotificationInfiniteScroll]' 5 | }) 6 | export class NotificationInfiniteScrollDirective { 7 | 8 | constructor() { } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/ScheduleJobFactory.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling; 2 | 3 | import org.quartz.JobDetail; 4 | import org.quartz.Trigger; 5 | 6 | public interface ScheduleJobFactory { 7 | public JobDetail getJobDetail(T t); 8 | public Trigger getTrigger(JobDetail jobDetail, T t); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/row/row.model.ts: -------------------------------------------------------------------------------- 1 | import { RowConfiguration } from './row.configuration'; 2 | 3 | export class Row { 4 | 5 | configuration: RowConfiguration; 6 | 7 | constructor(configuration: RowConfiguration) { 8 | this.configuration = configuration; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/humidity-data/humidity-data.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent/rpicomponent.model'; 2 | 3 | export class HumidityData { 4 | 5 | constructor( 6 | public timestamp: Date, 7 | public component: RPiComponent, 8 | public humidity: number 9 | ) {} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/relay/relaydto.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent.model'; 2 | import { RelayState } from './relay-state.enum'; 3 | 4 | export class RelayDTO { 5 | constructor ( 6 | public component: RPiComponent, 7 | public state: RelayState 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-list/rpi-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/exception/InvalidRelayStateException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.exception; 2 | 3 | public class InvalidRelayStateException extends RuntimeException { 4 | 5 | public InvalidRelayStateException(String message) { 6 | super(message); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/temperature-data/temperature-data.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent/rpicomponent.model'; 2 | 3 | export class TemperatureData { 4 | 5 | constructor( 6 | public timestamp: Date, 7 | public component: RPiComponent, 8 | public temperature: number 9 | ) {} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model; 2 | 3 | public class NotFoundException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = -4590791532876434L; 6 | 7 | public NotFoundException(String message) { 8 | super(message); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/directive/scrollable/scrollable.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { ScrollableDirective } from './scrollable.directive'; 2 | 3 | describe('ScrollableDirective', () => { 4 | it('should create an instance', () => { 5 | //const directive = new ScrollableDirective(); 6 | //expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/schedule/abstract-schedule-job.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '@app/shared/model/rpicomponent/rpicomponent.model'; 2 | 3 | export abstract class AbstractScheduleJob { 4 | constructor( 5 | public id: number, 6 | public component: RPiComponent, 7 | public enable: boolean 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/column/column.model.ts: -------------------------------------------------------------------------------- 1 | import { ColumnConfiguration } from './column.configuration'; 2 | export class Column { 3 | 4 | configuration: ColumnConfiguration; 5 | 6 | 7 | constructor(configuration: ColumnConfiguration) { 8 | this.configuration = configuration; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/panel/panel.model.ts: -------------------------------------------------------------------------------- 1 | import { PanelType } from './panel-type.enum'; 2 | import { PanelConfiguration } from './panel.configuration'; 3 | 4 | export class Panel { 5 | 6 | constructor( 7 | public type: PanelType, 8 | public configuration: PanelConfiguration 9 | ) {} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/pipe/celsius-to-fahrenheit/celsius-to-fahrenheit.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { CelsiusToFahrenheitPipe } from './celsius-to-fahrenheit.pipe'; 2 | 3 | describe('CelsiusToFahrenheitPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new CelsiusToFahrenheitPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/exception/InvalidRPiComponentTypeException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.exception; 2 | 3 | public class InvalidRPiComponentTypeException extends RuntimeException { 4 | 5 | public InvalidRPiComponentTypeException(String message) { 6 | super(message); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/factory/ScheduleJobFactory.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.factory; 2 | 3 | import org.quartz.JobDetail; 4 | import org.quartz.Trigger; 5 | 6 | public interface ScheduleJobFactory { 7 | public JobDetail getJobDetail(T t, D d); 8 | public Trigger getTrigger(JobDetail jobDetail, T t); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/pipe/key-extract/key-extract.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'keyExtract' 5 | }) 6 | export class KeyExtractPipe implements PipeTransform { 7 | 8 | transform(object: Object, args?: string[]): string[] { 9 | return Object.keys(object); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/data/ProximityDataRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.data; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.gro.model.rpicomponent.data.ProximityData; 6 | 7 | public interface ProximityDataRepository extends JpaRepository { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/TemperatureDataService.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.gro.model.rpicomponent.data.TemperatureDTO; 6 | 7 | @Service 8 | public class TemperatureDataService { 9 | 10 | //add more service methods here 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/dashboard-builder.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { DashboardBuilderComponent } from '@app/dashboard-builder/dashboard-builder.component'; 3 | 4 | export const DASHBOARD_BUILDER_ROUTES: Routes = [ 5 | { 6 | path: '', 7 | component: DashboardBuilderComponent, 8 | } 9 | ]; 10 | -------------------------------------------------------------------------------- /frontend/src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { LoginFormComponent } from './login-form/login-form.component'; 3 | 4 | @Component({ 5 | selector: 'gro-login', 6 | templateUrl: './login.component.html', 7 | styleUrls: ['./login.component.css'] 8 | }) 9 | export class LoginComponent { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/rpicomponent-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RPiComponentType { 2 | ALL = "ALL", 3 | TEMPERATURE = "TEMPERATURE", 4 | TEMPERATURE_HUMIDITY = "TEMPERATURE_HUMIDITY", 5 | HUMIDITY = "HUMIDITY", 6 | MOISTURE = "MOISTURE", 7 | PROXIMITY = "PROXIMITY", 8 | RELAY = "RELAY" 9 | } 10 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/HumiditySensorPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | import javax.persistence.Entity; 4 | 5 | import com.gro.model.rpicomponent.AbstractSensorPreferences; 6 | 7 | @Entity 8 | public class HumiditySensorPreferences extends AbstractSensorPreferences { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/MoistureSensorPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | import javax.persistence.Entity; 4 | 5 | import com.gro.model.rpicomponent.AbstractSensorPreferences; 6 | 7 | @Entity 8 | public class MoistureSensorPreferences extends AbstractSensorPreferences { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/RelayPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | import javax.persistence.Entity; 4 | 5 | import com.gro.model.rpicomponent.AbstractRPiComponentPreferences; 6 | 7 | @Entity 8 | public class RelayPreferences extends AbstractRPiComponentPreferences { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-table/rpicomponent-filter/rpicomponent-filter.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentFilterPipe } from './rpicomponent-filter.pipe'; 2 | 3 | describe('RPiComponentFilterPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new RPiComponentFilterPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/ProximitySensorPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | import javax.persistence.Entity; 4 | 5 | import com.gro.model.rpicomponent.AbstractSensorPreferences; 6 | 7 | @Entity 8 | public class ProximitySensorPreferences extends AbstractSensorPreferences { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpi/RPiRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpi; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpi.RPi; 6 | import com.gro.repository.RestrictedWriteRepository; 7 | 8 | @Repository 9 | public interface RPiRepository extends RestrictedWriteRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/RPiComponentRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import com.gro.model.rpicomponent.AbstractRPiComponent; 4 | import com.gro.repository.RestrictedWriteRepository; 5 | 6 | public interface RPiComponentRepository extends RestrictedWriteRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/SseEmitterService.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service; 2 | 3 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 4 | 5 | public interface SseEmitterService { 6 | public void addEmitter(SseEmitter emitter); 7 | public void removeEmitter(SseEmitter emitter); 8 | public void emit(T t); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/control/control-widget.configuration.ts: -------------------------------------------------------------------------------- 1 | import { ControlWidgetType } from './control-widget-type.enum'; 2 | import { WidgetConfiguration } from '@app/shared/model/dashboard/configuration/widget/widget.configuration'; 3 | 4 | export abstract class ControlWidgetConfiguration { 5 | 6 | constructor() {} 7 | 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/settings-rpi.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
7 |
8 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/pipe/celsius-to-fahrenheit/celsius-to-fahrenheit.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'celsiusToFahrenheit' 5 | }) 6 | export class CelsiusToFahrenheitPipe implements PipeTransform { 7 | 8 | transform(value: number): any { 9 | return (value * 1.8 + 32).toFixed(1); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/adapter/JobExecutionAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.adapter; 2 | 3 | import org.quartz.Job; 4 | import org.quartz.JobExecutionContext; 5 | import org.quartz.JobExecutionException; 6 | 7 | public interface JobExecutionAdapter extends Job{ 8 | void execute(JobExecutionContext context) throws JobExecutionException; 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard/dashboard.component.css: -------------------------------------------------------------------------------- 1 | #dashboard-builder-button { 2 | position: absolute; 3 | bottom: 16px; 4 | left: 16px; 5 | z-index: 10000; 6 | } 7 | 8 | .dropshadow { 9 | -webkit-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 10 | -moz-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 11 | box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-table/rpicomponent-filter/filter-by.enum.ts: -------------------------------------------------------------------------------- 1 | export enum FilterBy { 2 | ALL = "all", 3 | HUMIDITY = "humidity", 4 | MOISTURE = "moisture", 5 | PROXIMITY = "proximity", 6 | RELAY = "relay", 7 | TEMPERATURE = "temperature", 8 | TEMPERATURE_HUMIDITY = "temperature_humidity" 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/page-loader/page-loading.ts: -------------------------------------------------------------------------------- 1 | export class PageLoading { 2 | 3 | protected isLoading: boolean; 4 | 5 | constructor(isLoading:boolean) { 6 | this.isLoading = isLoading; 7 | } 8 | 9 | protected standby() { 10 | this.isLoading = true; 11 | } 12 | 13 | protected ready() { 14 | this.isLoading = false; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/find-all.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Resolve } from '@angular/router'; 2 | import { CrudService } from '@app/core/service/crud.service'; 3 | 4 | export abstract class FindAllResolve implements Resolve> { 5 | 6 | constructor(protected service: CrudService) {} 7 | 8 | resolve() { 9 | return this.service.findAll(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/request-options.default.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, Headers } from '@angular/http'; 2 | 3 | const createDefaultHeaders = function() { 4 | return new RequestOptions({ 5 | headers : new Headers({ 'Authorization': '' + localStorage.getItem('token') }) 6 | }); 7 | }; 8 | 9 | export const REQUEST_OPTIONS_DEFAULT: Function = createDefaultHeaders; 10 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph/graph.component.html: -------------------------------------------------------------------------------- 1 |
2 | 9 | 10 |
11 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/user/user.model.ts: -------------------------------------------------------------------------------- 1 | import { Authority } from './authority.enum'; 2 | 3 | export class User { 4 | 5 | constructor( 6 | public username: string, 7 | public firstname: string, 8 | public lastname: string, 9 | public email: string, 10 | public authorities: Array, 11 | public enabled: boolean 12 | ) {} 13 | 14 | } 15 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/factory/IntervalScheduleJobFactoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.factory; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.gro.scheduling.model.IntervalScheduleJob; 6 | 7 | @Component 8 | public class IntervalScheduleJobFactoryImpl extends IntervalScheduleJobFactory { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/storage/StorageException.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service.storage; 2 | 3 | public class StorageException extends RuntimeException { 4 | 5 | public StorageException(String message) { 6 | super(message); 7 | } 8 | 9 | public StorageException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | } -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/directive/panel-menu.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { PanelMenuDirective } from './panel-menu.directive'; 2 | 3 | describe('PanelMenuDirective', () => { 4 | it('should create an instance', () => { 5 | //const directive = new PanelMenuDirective(private element: ElementRef, private renderer : Renderer); 6 | //expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/row/row.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 | There are currenlty no columns in this row. 7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-table/rpicomponent-filter/filter-by.enum.ts: -------------------------------------------------------------------------------- 1 | export enum FilterBy { 2 | ALL = "all", 3 | HUMIDITY = "humidity", 4 | MOISTURE = "moisture", 5 | PROXIMITY = "proximity", 6 | RELAY = "relay", 7 | TEMPERATURE = "temperature", 8 | TEMPERATURE_HUMIDITY = "temperature_humidity" 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpi/rpi.model.ts: -------------------------------------------------------------------------------- 1 | export class RPi { 2 | //TODO: add list of pins and list of components 3 | constructor( 4 | public id: number, 5 | public description: string, 6 | public ip: string, 7 | public port: number, 8 | public mqttUsername: string, 9 | public mqttPassword: string, 10 | public imageUrl: string 11 | ) {} 12 | 13 | } 14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/RPiPinRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpipin.RPiPin; 6 | import com.gro.repository.ReadOnlyRepository; 7 | 8 | @Repository 9 | public interface RPiPinRepository extends ReadOnlyRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/factory/FixedTimeScheduleJobFactoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.factory; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.gro.scheduling.model.FixedTimeScheduleJob; 6 | 7 | @Component 8 | public class FixedTimeScheduleJobFactoryImpl extends FixedTimeScheduleJobFactory { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /backend/src/main/resources/quartz.properties: -------------------------------------------------------------------------------- 1 | # thread-pool 2 | org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool 3 | org.quartz.threadPool.threadCount=2 4 | org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true 5 | 6 | # job-store 7 | org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore 8 | 9 | # others 10 | org.quartz.jobStore.misfireThreshold = 60000 -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/dashboard-builder.component.css: -------------------------------------------------------------------------------- 1 | .dashboard-blank { 2 | position: absolute; 3 | left: 0; 4 | right: 0; 5 | top: 0; 6 | bottom: 0; 7 | margin: auto; 8 | z-index: -1; 9 | } 10 | 11 | #alert-blank-dashboard { 12 | position: absolute !important; 13 | top: 0; 14 | left: 0; 15 | right: 0; 16 | bottom: 0; 17 | margin: auto auto; 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-add/rpi-add.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Add new node 6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | 4 | @Component({ 5 | selector: 'gro-settings', 6 | templateUrl: './settings.component.html', 7 | styleUrls: ['./settings.component.css'] 8 | }) 9 | export class SettingsComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { environment } from './environments/environment'; 4 | import { AppModule } from './app/app.module'; 5 | 6 | if (environment.production) { 7 | enableProdMode(); 8 | } 9 | 10 | platformBrowserDynamic().bootstrapModule(AppModule); 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/messaging/gateway/MqttOutboundGateway.java: -------------------------------------------------------------------------------- 1 | package com.gro.messaging.gateway; 2 | 3 | import org.springframework.integration.annotation.MessagingGateway; 4 | import org.springframework.messaging.Message; 5 | 6 | @MessagingGateway(defaultRequestChannel="mqttOutboundChannel") 7 | public interface MqttOutboundGateway { 8 | void send(Message message); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { FrontendPage } from './app.po'; 2 | 3 | describe('frontend App', function() { 4 | let page: FrontendPage; 5 | 6 | beforeEach(() => { 7 | page = new FrontendPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/notification/notification.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '@app/shared/model/rpicomponent/rpicomponent.model'; 2 | 3 | export class Notification { 4 | 5 | constructor( 6 | public id: number, 7 | public timestamp: Date, 8 | public message: string, 9 | public component: RPiComponent, 10 | public isRead: boolean 11 | ) {} 12 | 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/paging/sort.model.ts: -------------------------------------------------------------------------------- 1 | import { SortDirection } from './sort-direction.enum'; 2 | 3 | export class Sort { 4 | 5 | constructor ( 6 | public direction: SortDirection, 7 | public property: string, 8 | public ignoreCase: boolean, 9 | public nullHandling: string, 10 | public descending: boolean, 11 | public ascending: boolean 12 | ) {} 13 | 14 | } -------------------------------------------------------------------------------- /frontend/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { ToasterLocation } from '@app/core/component/toaster/toaster-location.enum'; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.css'] 9 | }) 10 | export class AppComponent { 11 | private toasterLocation = ToasterLocation; 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/column/column.component.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 5 |
6 | 7 | There are currently now widgets or rows in this column 8 |
9 |
10 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-add/rpi-add.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-rpi-add', 5 | templateUrl: './rpi-add.component.html', 6 | styleUrls: ['./rpi-add.component.css'] 7 | }) 8 | export class RPiAddComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi/rpi.component.css: -------------------------------------------------------------------------------- 1 | legend { 2 | margin-top: 0px; 3 | margin-bottom: 8px; 4 | } 5 | 6 | .rpi-details-list-group { 7 | margin-bottom: 8px; 8 | margin-top: 8px; 9 | } 10 | 11 | .rpi-details-list-group > li { 12 | padding: 8px; 13 | font-size: 13px; 14 | margin-bottom: 2px; 15 | } 16 | 17 | .default-rpi { 18 | opacity: 0.2 !important; 19 | } 20 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/security/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.security.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import com.gro.security.model.User; 5 | 6 | /** 7 | * Created by stephan on 20.03.16. 8 | */ 9 | public interface UserRepository extends JpaRepository { 10 | User findByUsername(String username); 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/RelayRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpicomponent.component.Relay; 6 | import com.gro.repository.RestrictedWriteRepository; 7 | 8 | @Repository 9 | public interface RelayRepository extends RestrictedWriteRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/relay-find-all.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindAllResolve } from './find-all.resolve'; 3 | import { RelayService } from '../service/relay/relay.service'; 4 | 5 | @Injectable() 6 | export class RelayFindAllResolve extends FindAllResolve { 7 | 8 | constructor(protected service: RelayService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/relay-find-one.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindOneResolve } from './find-one.resolve'; 3 | import { RelayService } from '../service/relay/relay.service'; 4 | 5 | @Injectable() 6 | export class RelayFindOneResolve extends FindOneResolve { 7 | 8 | constructor(protected service: RelayService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/crudoperations.interface.ts: -------------------------------------------------------------------------------- 1 | import { Response } from '@angular/http'; 2 | import { Observable } from 'rxjs/Rx'; 3 | import 'rxjs/add/operator/map'; 4 | 5 | export interface CrudOperations { 6 | save(t: T): Observable; 7 | update(id: ID, t: T): Observable; 8 | findOne(id: ID): Observable; 9 | findAll(): Observable; 10 | delete(id: ID): Observable; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-list/notification-infinite-scroll.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { NotificationInfiniteScrollDirective } from './notification-infinite-scroll.directive'; 2 | 3 | describe('NotificationInfiniteScrollDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new NotificationInfiniteScrollDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/page-loader/page-loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-page-loader', 5 | templateUrl: './page-loader.component.html', 6 | styleUrls: ['./page-loader.component.css'] 7 | }) 8 | export class PageLoaderComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph/graph.configuration.ts: -------------------------------------------------------------------------------- 1 | import { GraphType } from './graph-type.enum'; 2 | export class GraphConfiguration { 3 | 4 | public type: GraphType; 5 | public data: number[]; 6 | public labels: string[]; 7 | public visible: boolean; 8 | 9 | constructor() { 10 | this.type = GraphType.LINE; 11 | this.visible = true; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/unauthorized/unauthorized.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-unauthorized', 5 | templateUrl: './unauthorized.component.html', 6 | styleUrls: ['./unauthorized.component.css'] 7 | }) 8 | export class UnauthorizedComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/panel/panel.configuration.ts: -------------------------------------------------------------------------------- 1 | import { PanelLocation } from './panel-location.enum'; 2 | import { Row } from '../row/row.model'; 3 | 4 | export class PanelConfiguration { 5 | 6 | rows: Array; 7 | 8 | constructor( 9 | public location: PanelLocation, 10 | public classes: Array 11 | ) { 12 | this.rows = new Array(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/relay-schedule-job.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from './rpicomponent.model'; 2 | import { RelayState } from './relay/relay-state.enum'; 3 | 4 | export class RelayScheduleJob { 5 | constructor( 6 | public id: number, 7 | public component: RPiComponent, 8 | public state: RelayState, 9 | public enabled: boolean, 10 | public time: number 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpipin/rpi-pin.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiPinDirection } from './rpi-pin-direction.enum'; 2 | import { RPiComponent } from '../rpicomponent/rpicomponent.model'; 3 | 4 | export class RPiPin { 5 | constructor( 6 | public id: number, 7 | public physicalPin: number, 8 | public usable: boolean, 9 | public direction: RPiPinDirection, 10 | public component?: RPiComponent 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/service/storage/StorageFileNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.service.storage; 2 | 3 | public class StorageFileNotFoundException extends StorageException { 4 | 5 | public StorageFileNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public StorageFileNotFoundException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | } -------------------------------------------------------------------------------- /frontend/src/app/shared/component/alert/alert.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit,Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-alert', 5 | templateUrl: './alert.component.html', 6 | styleUrls: ['./alert.component.css'] 7 | }) 8 | export class AlertComponent implements OnInit { 9 | 10 | @Input() 11 | message: string; 12 | 13 | constructor() { } 14 | 15 | ngOnInit() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/panel-list-group/panel-list-group.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{heading}} 4 |
5 |
    6 |
  • 8 | {{item.label}} 9 | {{item.value}} 10 |
  • 11 |
12 |
-------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/notification/NotificationNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.notification; 2 | 3 | import com.gro.model.NotFoundException; 4 | 5 | public class NotificationNotFoundException extends NotFoundException { 6 | 7 | private static final long serialVersionUID = -8762503873478598927L; 8 | 9 | public NotificationNotFoundException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /backend/src/test/java/com/gro/DemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.gro; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /frontend/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "outDir": "../dist/out-tsc-e2e", 10 | "sourceMap": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "../node_modules/@types" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/rpicomponent.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentType } from './rpicomponent-type.enum'; 2 | import { RPiPin } from '../rpipin/rpi-pin.model'; 3 | 4 | export abstract class RPiComponent { 5 | 6 | public current: number = 0; 7 | 8 | constructor ( 9 | public id: number, 10 | public alias: string, 11 | public pins: Array, 12 | public type: RPiComponentType 13 | ) { } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/HumiditySensorRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpicomponent.component.HumiditySensor; 6 | import com.gro.repository.RestrictedWriteRepository; 7 | 8 | @Repository 9 | public interface HumiditySensorRepository extends RestrictedWriteRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/MoistureSensorRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpicomponent.component.MoistureSensor; 6 | import com.gro.repository.RestrictedWriteRepository; 7 | 8 | @Repository 9 | public interface MoistureSensorRepository extends RestrictedWriteRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/column/column.configuration.ts: -------------------------------------------------------------------------------- 1 | import { Row } from '../row/row.model'; 2 | import { Widget } from '../widget/widget.model'; 3 | 4 | export class ColumnConfiguration { 5 | 6 | rows: Array; 7 | widgets: Array; 8 | 9 | constructor( 10 | public classes: Array 11 | ) { 12 | this.rows = new Array(); 13 | this.widgets = Array(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/exception/EntityNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.exception; 2 | 3 | import com.gro.model.NotFoundException; 4 | 5 | public class EntityNotFoundException extends NotFoundException { 6 | 7 | private static final long serialVersionUID = 6104607355884857925L; 8 | 9 | public EntityNotFoundException(String message) { 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/ProximitySensorRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpicomponent.component.ProximitySensor; 6 | import com.gro.repository.RestrictedWriteRepository; 7 | 8 | @Repository 9 | public interface ProximitySensorRepository extends RestrictedWriteRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/find-one.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Resolve, ActivatedRouteSnapshot, Route } from '@angular/router'; 2 | import { CrudService } from '@app/core/service/crud.service'; 3 | 4 | export abstract class FindOneResolve implements Resolve { 5 | 6 | constructor(protected service: CrudService) {} 7 | 8 | resolve(route: ActivatedRouteSnapshot) { 9 | return this.service.findOne(route.params['id']); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-dropdown/notification-dropdown.component.css: -------------------------------------------------------------------------------- 1 | .dropshadow { 2 | -webkit-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 3 | -moz-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 4 | box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 5 | } 6 | .dropdown-notifications { 7 | width: 350px; 8 | } 9 | 10 | hr { 11 | margin-top: 8px; 12 | } 13 | 14 | .notifications-button-container { 15 | margin-top: 8px; 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-add/rpicomponent-add.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-rpicomponent-add', 5 | templateUrl: './rpicomponent-add.component.html', 6 | styleUrls: ['./rpicomponent-add.component.css'] 7 | }) 8 | export class RPiComponentAddComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/exception/RPiPinNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.exception; 2 | 3 | import com.gro.model.NotFoundException; 4 | 5 | public class RPiPinNotFoundException extends NotFoundException{ 6 | 7 | private static final long serialVersionUID = -2544295686792571862L; 8 | 9 | public RPiPinNotFoundException(String message) { 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/rpi/rpi.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { RPiService } from './rpi.service'; 4 | 5 | describe('RpiService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [RPiService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([RPiService], (service: RPiService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/sse/sse.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { SseService } from './sse.service'; 4 | 5 | describe('SseService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [SseService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([SseService], (service: SseService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-form/rpicomponent-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-rpicomponent-form', 5 | templateUrl: './rpicomponent-form.component.html', 6 | styleUrls: ['./rpicomponent-form.component.css'] 7 | }) 8 | export class RPiComponentFormComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-user/settings-user.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 |

Settings : User

8 |
9 |
10 |

This is the user settings page.

11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/rpicomponent/TemperatureSensorRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.rpicomponent; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.gro.model.rpicomponent.component.TemperatureSensor; 6 | import com.gro.repository.RestrictedWriteRepository; 7 | 8 | @Repository 9 | public interface TemperatureSensorRepository extends RestrictedWriteRepository { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/paging/page.model.ts: -------------------------------------------------------------------------------- 1 | import { Sort } from './sort.model'; 2 | 3 | export class Page { 4 | 5 | constructor( 6 | public content: Array, 7 | public first: boolean, 8 | public last: boolean, 9 | public number: number, 10 | public numberOfElements: number, 11 | public size: number, 12 | public sort: Sort, 13 | public totalPages: number, 14 | public totalElements: number 15 | ) {} 16 | 17 | } 18 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/exception/RPiComponentNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.exception; 2 | 3 | import com.gro.model.NotFoundException; 4 | 5 | public class RPiComponentNotFoundException extends NotFoundException { 6 | 7 | private static final long serialVersionUID = 5009555411974113907L; 8 | 9 | public RPiComponentNotFoundException(String message) { 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/ReadOnlyRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | import org.springframework.data.repository.NoRepositoryBean; 7 | 8 | @NoRepositoryBean 9 | public interface ReadOnlyRepository extends BaseRepository { 10 | T findOne(ID id); 11 | boolean exists(ID id); 12 | List findAll(); 13 | long count(); 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/control/simple-relay/simple-relay-color.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SimpleRelayColor { 2 | GRAY_LIGHT = "relay-alert-gray-light", 3 | GRAY = "relay-alert-gray", 4 | GRAY_DARK = "relay-alert-gray-dark", 5 | GRAY_DARKER = "relay-alert-gray-darker", 6 | GREEN = "alert-success", 7 | BLUE = "alert-info", 8 | ORANGE = "alert-warning", 9 | RED = "alert-danger" 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/relay/relay.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { RelayService } from './relay.service'; 4 | 5 | describe('RelayService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [RelayService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([RelayService], (service: RelayService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/sensor/simple-reading/simple-reading-color.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SimpleReadingColor { 2 | GRAY_LIGHT = "sensor-alert-gray-light", 3 | GRAY = "sensor-alert-gray", 4 | GRAY_DARK = "sensor-alert-gray-dark", 5 | GRAY_DARKER = "sensor-alert-gray-darker", 6 | GREEN = "alert-success", 7 | BLUE = "alert-info", 8 | ORANGE = "alert-warning", 9 | RED = "alert-danger" 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/rpipin/rpi-pin.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { RPiPinService } from './rpi-pin.service'; 4 | 5 | describe('RPiPinService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [RPiPinService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([RPiPinService], (service: RPiPinService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/simple-loader/simple-loader.component.html: -------------------------------------------------------------------------------- 1 |
9 |
10 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/rpicomponent-sensor.preferences.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentPreferences } from './rpicomponent.preferences'; 2 | 3 | export abstract class RPiComponentSensorPreferences extends RPiComponentPreferences { 4 | 5 | constructor( 6 | public id: number, 7 | public minValue: number, 8 | public maxValue: number, 9 | public notificationEnabled: boolean, 10 | public notified: boolean, 11 | ) { 12 | super(id); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/schedule/ScheduleRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.schedule; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import com.gro.scheduling.model.AbstractScheduleJob; 9 | 10 | @Repository 11 | public interface ScheduleRepository extends CrudRepository { 12 | List findAll(); 13 | } 14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/adapter/ScheduleJobExecutionAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.adapter; 2 | 3 | import org.quartz.JobExecutionContext; 4 | import org.quartz.JobExecutionException; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class ScheduleJobExecutionAdapter implements JobExecutionAdapter { 9 | 10 | public void execute(JobExecutionContext context) throws JobExecutionException { 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toaster.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ToasterService } from './toaster.service'; 4 | 5 | describe('ToasterService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ToasterService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([ToasterService], (service: ToasterService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/humidity-sensor-find-all.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindAllResolve } from '@app/core/resolve/find-all.resolve'; 3 | import { HumiditySensorService } from '@app/core/service/humidity-sensor/humidity-sensor.service'; 4 | 5 | @Injectable() 6 | export class HumiditySensorFindAllResolve extends FindAllResolve { 7 | 8 | constructor(protected service: HumiditySensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/humidity-sensor-find-one.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindOneResolve } from '@app/core/resolve/find-one.resolve'; 3 | import { HumiditySensorService } from '@app/core/service/humidity-sensor/humidity-sensor.service'; 4 | 5 | @Injectable() 6 | export class HumiditySensorFindOneResolve extends FindOneResolve { 7 | 8 | constructor(protected service: HumiditySensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/moisture-sensor-find-all.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindAllResolve } from '@app/core/resolve/find-all.resolve'; 3 | import { MoistureSensorService } from '@app/core/service/moisture-sensor/moisture-sensor.service'; 4 | 5 | @Injectable() 6 | export class MoistureSensorFindAllResolve extends FindAllResolve { 7 | 8 | constructor(protected service: MoistureSensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/moisture-sensor-find-one.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindOneResolve } from '@app/core/resolve/find-one.resolve'; 3 | import { MoistureSensorService } from '@app/core/service/moisture-sensor/moisture-sensor.service'; 4 | 5 | @Injectable() 6 | export class MoistureSensorFindOneResolve extends FindOneResolve { 7 | 8 | constructor(protected service: MoistureSensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.gro; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.integration.annotation.IntegrationComponentScan; 6 | 7 | @SpringBootApplication 8 | @IntegrationComponentScan 9 | public class DemoApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(DemoApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/proximity-sensor-find-all.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindAllResolve } from '@app/core/resolve/find-all.resolve'; 3 | import { ProximitySensorService } from '@app/core/service/proximity-sensor/proximity-sensor.service'; 4 | 5 | @Injectable() 6 | export class ProximitySensorFindAllResolve extends FindAllResolve { 7 | 8 | constructor(protected service: ProximitySensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/proximity-sensor-find-one.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindOneResolve } from '@app/core/resolve/find-one.resolve'; 3 | import { ProximitySensorService } from '@app/core/service/proximity-sensor/proximity-sensor.service'; 4 | 5 | @Injectable() 6 | export class ProximitySensorFindOneResolve extends FindOneResolve { 7 | 8 | constructor(protected service: ProximitySensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/control/relay-list/relay-list.configuration.ts: -------------------------------------------------------------------------------- 1 | import { ControlWidgetConfiguration } from '@app/shared/model/dashboard/configuration/widget/control/control-widget.configuration'; 2 | import { ControlWidgetType } from '@app/shared/model/dashboard/configuration/widget/control/control-widget-type.enum'; 3 | 4 | export class RelayListConfiguration extends ControlWidgetConfiguration { 5 | 6 | constructor() { 7 | super(); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/sensor/readings-list/readings-list.configuration.ts: -------------------------------------------------------------------------------- 1 | import { SensorWidgetConfiguration } from '@app/shared/model/dashboard/configuration/widget/sensor/sensor-widget.configuration'; 2 | import { SensorWidgetType } from '@app/shared/model/dashboard/configuration/widget/sensor/sensor-widget-type.enum'; 3 | 4 | export class ReadingsListConfiguration extends SensorWidgetConfiguration { 5 | 6 | constructor() { 7 | super(); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/schedule/IntervalScheduleRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.schedule; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import com.gro.scheduling.model.IntervalScheduleJob; 9 | 10 | @Repository 11 | public interface IntervalScheduleRepository extends CrudRepository { 12 | List findAll(); 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/dashboard/dashboard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { DashboardService } from './dashboard.service'; 4 | 5 | describe('DashboardService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [DashboardService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([DashboardService], (service: DashboardService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-details/rpi-details.component.css: -------------------------------------------------------------------------------- 1 | .rpi-details-list-group { 2 | margin-bottom: 8px; 3 | margin-top: 8px; 4 | } 5 | 6 | .rpi-details-list-group > li { 7 | padding: 8px; 8 | font-size: 13px; 9 | margin-bottom: 2px; 10 | } 11 | 12 | .default-rpi { 13 | opacity: 0.2 !important; 14 | } 15 | 16 | .image-upload-btn { 17 | position: absolute; 18 | top: 0; 19 | right: 0; 20 | margin-right: 24px; 21 | margin-top: 8px; 22 | border-radius: 4px; 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/schedule/fixed-time-schedule-job.model.ts: -------------------------------------------------------------------------------- 1 | import { AbstractScheduleJob } from './abstract-schedule-job.model'; 2 | import { RPiComponent } from '@app/shared/model/rpicomponent/rpicomponent.model'; 3 | 4 | export class FixedTimeScheduleJob extends AbstractScheduleJob { 5 | constructor( 6 | public id: number, 7 | public component: RPiComponent, 8 | public enable: boolean, 9 | public time: Date, 10 | ) { 11 | super(id, component, enable); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/schedule/FixedTimeScheduleRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.schedule; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import com.gro.scheduling.model.FixedTimeScheduleJob; 9 | 10 | @Repository 11 | public interface FixedTimeScheduleRepository extends CrudRepository { 12 | List findAll(); 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/temperature-sensor-find-all.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindAllResolve } from '@app/core/resolve/find-all.resolve'; 3 | import { TemperatureSensorService } from '@app/core/service/temperature-sensor/temperature-sensor.service'; 4 | 5 | @Injectable() 6 | export class TemperatureSensorFindAllResolve extends FindAllResolve { 7 | 8 | constructor(protected service: TemperatureSensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/core/resolve/temperature-sensor-find-one.resolve.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { FindOneResolve } from '@app/core/resolve/find-one.resolve'; 3 | import { TemperatureSensorService } from '@app/core/service/temperature-sensor/temperature-sensor.service'; 4 | 5 | @Injectable() 6 | export class TemperatureSensorFindOneResolve extends FindOneResolve { 7 | 8 | constructor(protected service: TemperatureSensorService) { 9 | super(service); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/column/desktop-width.enum.ts: -------------------------------------------------------------------------------- 1 | export enum DesktopWidth { 2 | COLUMN_1 = "col-lg-1", 3 | COLUMN_2 = "col-lg-2", 4 | COLUMN_3 = "col-lg-3", 5 | COLUMN_4 = "col-lg-4", 6 | COLUMN_5 = "col-lg-5", 7 | COLUMN_6 = "col-lg-6", 8 | COLUMN_7 = "col-lg-7", 9 | COLUMN_8 = "col-lg-8", 10 | COLUMN_9 = "col-lg-9", 11 | COLUMN_10 = "col-lg-10", 12 | COLUMN_11 = "col-lg-11", 13 | COLUMN_12 = "col-lg-12", 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/column/phone-width.enum.ts: -------------------------------------------------------------------------------- 1 | export enum PhoneWidth { 2 | COLUMN_1 = "col-sm-1", 3 | COLUMN_2 = "col-sm-2", 4 | COLUMN_3 = "col-sm-3", 5 | COLUMN_4 = "col-sm-4", 6 | COLUMN_5 = "col-sm-5", 7 | COLUMN_6 = "col-sm-6", 8 | COLUMN_7 = "col-sm-7", 9 | COLUMN_8 = "col-sm-8", 10 | COLUMN_9 = "col-sm-9", 11 | COLUMN_10 = "col-sm-10", 12 | COLUMN_11 = "col-sm-11", 13 | COLUMN_12 = "col-sm-12", 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/column/tablet-width.enum.ts: -------------------------------------------------------------------------------- 1 | export enum TabletWidth { 2 | COLUMN_1 = "col-md-1", 3 | COLUMN_2 = "col-md-2", 4 | COLUMN_3 = "col-md-3", 5 | COLUMN_4 = "col-md-4", 6 | COLUMN_5 = "col-md-5", 7 | COLUMN_6 = "col-md-6", 8 | COLUMN_7 = "col-md-7", 9 | COLUMN_8 = "col-md-8", 10 | COLUMN_9 = "col-md-9", 11 | COLUMN_10 = "col-md-10", 12 | COLUMN_11 = "col-md-11", 13 | COLUMN_12 = "col-md-12", 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/humidity-data/humidity-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { HumidityDataService } from './humidity-data.service'; 4 | 5 | describe('HumidityDataService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [HumidityDataService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([HumidityDataService], (service: HumidityDataService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/notification/notification.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { NotificationService } from './notification.service'; 4 | 5 | describe('NotificationService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [NotificationService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([NotificationService], (service: NotificationService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/relay/relay-schedule.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { RelayScheduleService } from './relay-schedule.service'; 4 | 5 | describe('RelayScheduleService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [RelayScheduleService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([RelayScheduleService], (service: RelayScheduleService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/rpicomponent/rpicomponent.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { RPiComponentService } from './rpicomponent.service'; 4 | 5 | describe('RPiComponentService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [RPiComponentService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([RPiComponentService], (service: RPiComponentService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-edit/rpicomponent-edit.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Edit component 6 |
7 |
8 | 10 | 11 |
12 |
13 |
-------------------------------------------------------------------------------- /frontend/src/app/dashboard/dashboard.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { DashboardComponent } from '@app/dashboard/dashboard.component'; 4 | import { DashboardBuilderComponent } from '@app/dashboard-builder/dashboard-builder.component'; 5 | 6 | export const DASHBOARD_ROUTES: Routes = [ 7 | { 8 | path: '', 9 | component: DashboardComponent 10 | }, 11 | { 12 | path: 'builder', 13 | loadChildren: '@app/dashboard-builder/dashboard-builder.module#DashboardBuilderModule' 14 | } 15 | ]; 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-add/rpicomponent-add.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Create new component 6 |
7 |
8 | 10 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /frontend/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@app/*": ["app/*"] 6 | }, 7 | "declaration": false, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "lib": ["es6", "dom"], 11 | "mapRoot": "./", 12 | "module": "es6", 13 | "moduleResolution": "node", 14 | "outDir": "../dist/out-tsc", 15 | "sourceMap": true, 16 | "target": "es5", 17 | "typeRoots": [ 18 | "../node_modules/@types" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/humidity-sensor/humidity-sensor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { HumiditySensorService } from './humidity-sensor.service'; 4 | 5 | describe('HumiditySensorService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [HumiditySensorService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([HumiditySensorService], (service: HumiditySensorService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/moisture-sensor/moisture-sensor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { MoistureSensorService } from './moisture-sensor.service'; 4 | 5 | describe('MoistureSensorService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [MoistureSensorService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([MoistureSensorService], (service: MoistureSensorService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/proximity-sensor/proximity-sensor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ProximitySensorService } from './proximity-sensor.service'; 4 | 5 | describe('ProximitySensorService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ProximitySensorService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([ProximitySensorService], (service: ProximitySensorService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/temperature-data/temperature-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { TemperatureDataService } from './temperature-data.service'; 4 | 5 | describe('TemperatureDataService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [TemperatureDataService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([TemperatureDataService], (service: TemperatureDataService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/humidity-sensor/humidity-sensor.preferences.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentSensorPreferences } from '../rpicomponent-sensor.preferences'; 2 | 3 | export class HumiditySensorPreferences extends RPiComponentSensorPreferences { 4 | 5 | constructor( 6 | public id: number, 7 | public minValue: number, 8 | public maxValue: number, 9 | public notificationEnabled: boolean, 10 | public notified: boolean, 11 | ) { 12 | super(id, minValue, maxValue, notificationEnabled, notified); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/moisture-sensor/moisture-sensor.preferences.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentSensorPreferences } from '../rpicomponent-sensor.preferences'; 2 | 3 | export class MoistureSensorPreferences extends RPiComponentSensorPreferences { 4 | 5 | constructor( 6 | public id: number, 7 | public minValue: number, 8 | public maxValue: number, 9 | public notificationEnabled: boolean, 10 | public notified: boolean, 11 | ) { 12 | super(id, minValue, maxValue, notificationEnabled, notified); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/service/dashboard-builder.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { DashboardBuilderService } from './dashboard-builder.service'; 4 | 5 | describe('DashboardBuilderService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [DashboardBuilderService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([DashboardBuilderService], (service: DashboardBuilderService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/proximity-sensor/proximity-sensor.preferences.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentSensorPreferences } from '../rpicomponent-sensor.preferences'; 2 | 3 | export class ProximitySensorPreferences extends RPiComponentSensorPreferences { 4 | 5 | constructor( 6 | public id: number, 7 | public minValue: number, 8 | public maxValue: number, 9 | public notificationEnabled: boolean, 10 | public notified: boolean, 11 | ) { 12 | super(id, minValue, maxValue, notificationEnabled, notified); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/panel-list-group/panel-list-group.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-panel-list-group', 5 | templateUrl: './panel-list-group.component.html', 6 | styleUrls: ['./panel-list-group.component.css'] 7 | }) 8 | export class PanelListGroupComponent implements OnInit { 9 | 10 | @Input() 11 | data: Object[]; 12 | 13 | @Input() 14 | heading: string; 15 | 16 | constructor() { console.log(this.data); } 17 | 18 | ngOnInit() { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/temperature-sensor/temperature-sensor.preferences.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponentSensorPreferences } from '../rpicomponent-sensor.preferences'; 2 | 3 | export class TemperatureSensorPreferences extends RPiComponentSensorPreferences { 4 | 5 | constructor( 6 | public id: number, 7 | public minValue: number, 8 | public maxValue: number, 9 | public notificationEnabled: boolean, 10 | public notified: boolean, 11 | ) { 12 | super(id, minValue, maxValue, notificationEnabled, notified); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/temperature-sensor/temperature-sensor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { TemperatureSensorService } from './temperature-sensor.service'; 4 | 5 | describe('TemperatureSensorService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [TemperatureSensorService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([TemperatureSensorService], (service: TemperatureSensorService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/file-uploader/file-uploader.component.css: -------------------------------------------------------------------------------- 1 | .file-drop-zone { 2 | border: dotted 2px lightgray; 3 | } 4 | 5 | .well-dark { 6 | background: #4e5d6c; 7 | } 8 | 9 | .nv-file-over { 10 | border: dotted 2px #5cb85c; 11 | } /* Default class applied to drop zones on over */ 12 | 13 | input[type="file"] { 14 | display: none; 15 | } 16 | 17 | .text-italic { 18 | font-style: italic; 19 | font-size: 13px; 20 | } 21 | 22 | .label-queue-progress { 23 | font-weight: bold; 24 | font-size: 10px; 25 | text-transform: uppercase; 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/app/authentication/authentication.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { TestBed, async, inject } from '@angular/core/testing'; 4 | import { AuthenticationService } from './authentication.service'; 5 | 6 | describe('AuthenticationService', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | providers: [AuthenticationService] 10 | }); 11 | }); 12 | 13 | it('should ...', inject([AuthenticationService], (service: AuthenticationService) => { 14 | expect(service).toBeTruthy(); 15 | })); 16 | }); 17 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph-table/graph-table-options/graph-table-options.component.css: -------------------------------------------------------------------------------- 1 | .dropdown-legend { 2 | margin-bottom: 4px !important; 3 | margin-top: 4px !important; 4 | } 5 | 6 | .btn-checkbox { 7 | text-align: left; 8 | margin-bottom: 4px; 9 | } 10 | 11 | .btn-full { 12 | width: 100%; 13 | } 14 | 15 | .btn-checkbox:after { 16 | content: ""; 17 | display: block; 18 | clear: both; 19 | } 20 | 21 | .btn-checkbox > span { 22 | float: left; 23 | } 24 | 25 | .btn-checkbox > i { 26 | margin-top: 4px; 27 | float: right; 28 | } 29 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph-table/graph-table.component.css: -------------------------------------------------------------------------------- 1 | .dropdown-menu-panel { 2 | margin-left: 16px !important; 3 | margin-right: 16px !important; 4 | } 5 | 6 | .dropdown-menu-options { 7 | width: 246px; 8 | } 9 | 10 | .dropdown-menu-datasource { 11 | width: 300px; 12 | } 13 | 14 | .dropshadow { 15 | -webkit-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 16 | -moz-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 17 | box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46); 18 | } 19 | 20 | .hide { 21 | display: none !important; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/settings-rpicomponent.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { SettingsRPiComponentService } from './settings-rpicomponent.service'; 4 | 5 | describe('SettingsRPiComponentService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [SettingsRPiComponentService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([SettingsRPiComponentService], (service: SettingsRPiComponentService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/settings-rpicomponent.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { SettingsRPiComponentService } from './settings-rpicomponent.service'; 4 | 5 | describe('SettingsRPiComponentService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [SettingsRPiComponentService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([SettingsRPiComponentService], (service: SettingsRPiComponentService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/settings-rpicomponent.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 | 15 | 16 |
17 |
18 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-user/settings-user.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { PageLoading } from '@app/shared/component/page-loader/page-loading'; 4 | 5 | @Component({ 6 | selector: 'gro-settings-user', 7 | templateUrl: './settings-user.component.html', 8 | styleUrls: ['./settings-user.component.css'] 9 | }) 10 | export class SettingsUserComponent extends PageLoading implements OnInit { 11 | 12 | constructor() { 13 | super(true); 14 | } 15 | 16 | ngOnInit() { 17 | setTimeout(() => this.ready(), 1000); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/resources/ObjectMapperFactory.java: -------------------------------------------------------------------------------- 1 | package com.gro.resources; 2 | 3 | import org.springframework.integration.support.json.Jackson2JsonObjectMapper; 4 | 5 | import com.fasterxml.jackson.core.JsonParser; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | 8 | public class ObjectMapperFactory { 9 | 10 | public static Jackson2JsonObjectMapper getMapper() { 11 | ObjectMapper mapper = new ObjectMapper(); 12 | mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); 13 | return new Jackson2JsonObjectMapper(mapper); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/schedule/interval-schedule-job.model.ts: -------------------------------------------------------------------------------- 1 | import { AbstractScheduleJob } from './abstract-schedule-job.model'; 2 | import { FrequencyMetric } from './frequency-metric.enum'; 3 | import { RPiComponent } from '@app/shared/model/rpicomponent/rpicomponent.model'; 4 | 5 | export class IntervalScheduleJob extends AbstractScheduleJob { 6 | constructor( 7 | public id: number, 8 | public component: RPiComponent, 9 | public enable: boolean, 10 | public frequency: number, 11 | public metric: FrequencyMetric 12 | ) { 13 | super(id, component, enable); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/modal-confirm/modal-confirm.model.ts: -------------------------------------------------------------------------------- 1 | export class ModalConfirm { 2 | 3 | public message: string = 'Are you sure?'; 4 | public isShown: boolean = false; 5 | public title: string = 'Confirmation'; 6 | 7 | constructor( 8 | message?: string, 9 | isShown?: boolean, 10 | title?: string 11 | ) { 12 | this.message = message; 13 | this.isShown = isShown; 14 | this.title = title; 15 | } 16 | 17 | public toggle() { 18 | this.isShown = !this.isShown; 19 | } 20 | 21 | public setShown(isShown: boolean) { 22 | this.isShown = isShown; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/rpipin/rpi-pin.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | import { REQUEST_OPTIONS_DEFAULT } from '../request-options.default'; 4 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 5 | import { CrudService } from '../crud.service'; 6 | import { RPiPin } from '@app/shared/model/rpipin/rpi-pin.model'; 7 | 8 | @Injectable() 9 | export class RPiPinService extends CrudService { 10 | 11 | constructor(http: Http) { 12 | super(BASE_API_URL + 'rpipin', http, REQUEST_OPTIONS_DEFAULT); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/BaseRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | import org.springframework.data.repository.NoRepositoryBean; 7 | import org.springframework.data.repository.Repository; 8 | 9 | @NoRepositoryBean 10 | public interface BaseRepository extends Repository { 11 | S save(S entity); 12 | T findOne(ID id); 13 | boolean exists(ID id); 14 | List findAll(); 15 | long count(); 16 | void delete(ID id); 17 | void delete(Iterable entities); 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph/graph-presets.ts: -------------------------------------------------------------------------------- 1 | let graphPresets = { 2 | options : { 3 | scales : { 4 | yAxes: [] 5 | }, 6 | legend : { 7 | labels: { 8 | fontColor: '#ebebeb' 9 | } 10 | }, 11 | scaleShowVerticalLines: false, 12 | responsive: true 13 | }, 14 | 15 | legend: true, 16 | 17 | chartColors: [ 18 | { 19 | hoverBackgroundColor: '#31b0d5', 20 | backgroundColor: '#5bc0de' 21 | }, 22 | { 23 | hoverBackgroundColor: '#449d44', 24 | backgroundColor: '#5cb85c' 25 | } 26 | ] 27 | } 28 | export {graphPresets}; 29 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/temperature-humidity-sensor/temperature-humidity-sensor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { TemperatureHumiditySensorService } from './temperature-humidity-sensor.service'; 4 | 5 | describe('TemperatureHumiditySensorService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [TemperatureHumiditySensorService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([TemperatureHumiditySensorService], (service: TemperatureHumiditySensorService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/rpi/rpi.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { CrudService } from '@app/core/service/crud.service'; 5 | import { RPi } from '@app/shared/model/rpi/rpi.model'; 6 | 7 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 8 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 9 | 10 | @Injectable() 11 | export class RPiService extends CrudService { 12 | 13 | constructor(http: Http) { 14 | super(BASE_API_URL + "rpi", http, REQUEST_OPTIONS_DEFAULT); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/simple-loader/simple-loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-simple-loader', 5 | templateUrl: './simple-loader.component.html', 6 | styleUrls: ['./simple-loader.component.css'] 7 | }) 8 | export class SimpleLoaderComponent implements OnInit { 9 | 10 | @Input() 11 | isLoading: boolean = false; 12 | 13 | @Input() 14 | size: string = 'medium'; 15 | 16 | @Input() 17 | trackColor: string; 18 | 19 | @Input() 20 | spinnerColor: string; 21 | 22 | constructor() { } 23 | 24 | ngOnInit() { 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /backend/src/main/resources/ehcache.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /frontend/src/app/authentication/guard/authentication.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router, CanActivate } from '@angular/router'; 3 | import { AuthenticationService } from '@app/authentication/authentication.service'; 4 | 5 | @Injectable() 6 | export class AuthenticationGuard implements CanActivate { 7 | 8 | constructor( 9 | private auth: AuthenticationService, 10 | private router: Router 11 | ){} 12 | 13 | canActivate() { 14 | if(this.auth.isLoggedIn()) { 15 | return true; 16 | } else { 17 | this.router.navigate(['login']); 18 | return false; 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/model/FixedTimeJob.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.model; 2 | 3 | import org.quartz.Job; 4 | import org.quartz.JobExecutionContext; 5 | import org.quartz.JobExecutionException; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import com.gro.scheduling.adapter.ScheduleJobExecutionAdapter; 9 | 10 | public class FixedTimeJob implements Job { 11 | 12 | @Autowired 13 | private ScheduleJobExecutionAdapter adapter; 14 | 15 | @Override 16 | public void execute(JobExecutionContext context) throws JobExecutionException { 17 | adapter.execute(context); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/model/IntervalJob.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.model; 2 | 3 | import org.quartz.Job; 4 | import org.quartz.JobExecutionContext; 5 | import org.quartz.JobExecutionException; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import com.gro.scheduling.adapter.ScheduleJobExecutionAdapter; 9 | 10 | public class IntervalJob implements Job{ 11 | 12 | @Autowired 13 | private ScheduleJobExecutionAdapter adapter; 14 | 15 | @Override 16 | public void execute(JobExecutionContext context) throws JobExecutionException { 17 | adapter.execute(context); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/control/control-widget.model.ts: -------------------------------------------------------------------------------- 1 | import { ControlWidgetType } from './control-widget-type.enum'; 2 | import { ControlWidgetConfiguration } from './control-widget.configuration'; 3 | import { Widget } from '@app/shared/model/dashboard/configuration/widget/widget.model'; 4 | import { WidgetType } from '@app/shared/model/dashboard/configuration/widget/widget-type.enum'; 5 | 6 | export class ControlWidget extends Widget { 7 | 8 | constructor( 9 | public type: ControlWidgetType, 10 | public configuration: ControlWidgetConfiguration 11 | ) { 12 | super(WidgetType.CONTROL); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-list/notification-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | import { Notification } from '@app/shared/model/notification/notification.model'; 4 | 5 | @Component({ 6 | selector: 'gro-notification-list', 7 | templateUrl: './notification-list.component.html', 8 | styleUrls: ['./notification-list.component.css'] 9 | }) 10 | export class NotificationListComponent implements OnInit { 11 | 12 | @Input() 13 | notifications: Array; 14 | 15 | constructor() { 16 | this.notifications = new Array(); 17 | } 18 | 19 | ngOnInit() { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/temperature-humidity-sensor/temperature-humidity-sensor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { CrudService } from '@app/core/service/crud.service'; 5 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 6 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 7 | 8 | @Injectable() 9 | export class TemperatureHumiditySensorService extends CrudService { 10 | 11 | constructor(http: Http) { 12 | super(BASE_API_URL + "component/temperature-humidity", http, REQUEST_OPTIONS_DEFAULT) 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/login/login.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { LOGIN_ROUTING } from '@app/login/login.routing'; 5 | import { SharedModule } from '@app/shared/shared.module'; 6 | 7 | import { LoginComponent } from './login.component'; 8 | import { LoginFormComponent } from './login-form/login-form.component'; 9 | 10 | @NgModule({ 11 | imports: [ 12 | SharedModule, 13 | RouterModule.forChild(LOGIN_ROUTING) 14 | ], 15 | exports: [LoginComponent], 16 | declarations: [ 17 | LoginComponent, 18 | LoginFormComponent 19 | ] 20 | }) 21 | export class LoginModule {} 22 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/unauthorized/unauthorized.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 7 |

403 Unauthorized

8 |
9 |
10 |

You are not authorized to view this page. Please contact an administrator for details.

11 |
12 |
13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /frontend/src/assets/css/style.css: -------------------------------------------------------------------------------- 1 | .panel-default-light { 2 | background: #F3F3F3 !important; 3 | } 4 | .logo { 5 | padding: 30px !important; 6 | margin-bottom: 30px; 7 | background: #FEFEFE !important; 8 | } 9 | 10 | .btn-default-darker { 11 | background: #405563 !important; 12 | } 13 | 14 | .btn-default-darker>a { 15 | color: #FFF; 16 | } 17 | 18 | .btn-default-darker>a:hover { 19 | text-decoration: none; 20 | } 21 | 22 | .btn-default-darker:hover { 23 | background: #405060 !important; 24 | } 25 | 26 | .navbar-fixed-side .navbar-collapse { 27 | border-top: 0 !important; 28 | } 29 | 30 | 31 | 32 | 33 | .text-right { 34 | text-align: right; 35 | } 36 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | 10 | # IDEs and editors 11 | /.idea 12 | .project 13 | .classpath 14 | .c9/ 15 | *.launch 16 | .settings/ 17 | 18 | # IDE - VSCode 19 | .vscode/* 20 | !.vscode/settings.json 21 | !.vscode/tasks.json 22 | !.vscode/launch.json 23 | !.vscode/extensions.json 24 | 25 | # misc 26 | /.sass-cache 27 | /connect.lock 28 | /coverage/* 29 | /libpeerconnection.log 30 | npm-debug.log 31 | testem.log 32 | /typings 33 | 34 | # e2e 35 | /e2e/*.js 36 | /e2e/*.map 37 | 38 | #System Files 39 | .DS_Store 40 | Thumbs.db 41 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/data/RelayState.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.data; 2 | 3 | public enum RelayState { 4 | ON, 5 | OFF; 6 | 7 | public static RelayState from(String state) { 8 | RelayState result = null; 9 | 10 | switch(state.toLowerCase()) { 11 | case "on": 12 | result = RelayState.ON; 13 | break; 14 | case "off": 15 | result = RelayState.OFF; 16 | break; 17 | default: 18 | result = null; 19 | break; 20 | } 21 | 22 | return result; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-navigation/settings-navigation.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit,EventEmitter, Output, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'gro-settings-navigation', 5 | templateUrl: './settings-navigation.component.html', 6 | styleUrls: ['./settings-navigation.component.css'] 7 | }) 8 | export class SettingsNavigationComponent implements OnInit { 9 | 10 | @Output() 11 | onViewChange = new EventEmitter(); 12 | 13 | @Input() 14 | view: string; 15 | 16 | constructor() { } 17 | 18 | ngOnInit() { 19 | } 20 | 21 | changeView (view: string): void { 22 | this.onViewChange.emit(view); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/humidity-sensor/humidity-sensor.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent.model'; 2 | import { RPiComponentType } from '../rpicomponent-type.enum'; 3 | import { RPiPin } from '@app/shared/model/rpipin/rpi-pin.model'; 4 | import { HumiditySensorPreferences } from './humidity-sensor.preferences'; 5 | 6 | export class HumiditySensor extends RPiComponent { 7 | 8 | constructor ( 9 | public id: number, 10 | public alias: string, 11 | public pins: Array, 12 | public type: RPiComponentType, 13 | public preferences: HumiditySensorPreferences 14 | ) { 15 | super(id, alias, pins, type); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/moisture-sensor/moisture-sensor.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent.model'; 2 | import { RPiComponentType } from '../rpicomponent-type.enum'; 3 | import { RPiPin } from '@app/shared/model/rpipin/rpi-pin.model'; 4 | import { MoistureSensorPreferences } from './moisture-sensor.preferences'; 5 | 6 | export class MoistureSensor extends RPiComponent { 7 | 8 | constructor ( 9 | public id: number, 10 | public alias: string, 11 | public pins: Array, 12 | public type: RPiComponentType, 13 | public preferences: MoistureSensorPreferences 14 | ) { 15 | super(id, alias, pins, type); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/dashboard/dashboard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 5 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 6 | import { CrudService } from '@app/core/service/crud.service'; 7 | 8 | import { Dashboard } from '@app/shared/model/dashboard/dashboard.model'; 9 | 10 | @Injectable() 11 | export class DashboardService extends CrudService { 12 | 13 | constructor(http: Http ) { 14 | super(BASE_API_URL + 'component', http, REQUEST_OPTIONS_DEFAULT); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/proximity-sensor/proximity-sensor.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent.model'; 2 | import { RPiComponentType } from '../rpicomponent-type.enum'; 3 | import { RPiPin } from '@app/shared/model/rpipin/rpi-pin.model'; 4 | import { ProximitySensorPreferences } from './proximity-sensor.preferences'; 5 | 6 | export class ProximitySensor extends RPiComponent { 7 | 8 | constructor ( 9 | public id: number, 10 | public alias: string, 11 | public pins: Array, 12 | public type: RPiComponentType, 13 | public preferences: ProximitySensorPreferences 14 | ) { 15 | super(id, alias, pins, type); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/control/simple-relay/simple-relay.configuration.ts: -------------------------------------------------------------------------------- 1 | import { RelayDTO } from '@app/shared/model/rpicomponent/relay/relaydto.model'; 2 | import { SimpleRelayColor } from './simple-relay-color.enum'; 3 | import { ControlWidgetConfiguration } from '../control-widget.configuration'; 4 | import { ControlWidgetType } from '../control-widget-type.enum'; 5 | 6 | export class SimpleRelayConfiguration extends ControlWidgetConfiguration { 7 | 8 | relay: RelayDTO; 9 | color: SimpleRelayColor; 10 | 11 | constructor(relay: RelayDTO) { 12 | super(); 13 | this.relay = relay; 14 | this.color = SimpleRelayColor.GREEN; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-list/rpi-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 2 | 3 | import { RPi } from '@app/shared/model/rpi/rpi.model'; 4 | 5 | @Component({ 6 | selector: 'gro-rpi-list', 7 | templateUrl: './rpi-list.component.html', 8 | styleUrls: ['./rpi-list.component.css'] 9 | }) 10 | export class RPiListComponent implements OnInit { 11 | 12 | @Input() 13 | rpis: Array; 14 | 15 | @Output() 16 | onDelete: EventEmitter = new EventEmitter(); 17 | 18 | constructor() { } 19 | 20 | ngOnInit() { 21 | } 22 | 23 | delete(id: number) { 24 | this.onDelete.emit(id); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/temperature-sensor/temperature-sensor.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent.model'; 2 | import { RPiComponentType } from '../rpicomponent-type.enum'; 3 | import { RPiPin } from '@app/shared/model/rpipin/rpi-pin.model'; 4 | import { TemperatureSensorPreferences } from './temperature-sensor.preferences'; 5 | 6 | export class TemperatureSensor extends RPiComponent { 7 | 8 | constructor ( 9 | public id: number, 10 | public alias: string, 11 | public pins: Array, 12 | public type: RPiComponentType, 13 | public preferences: TemperatureSensorPreferences 14 | ) { 15 | super(id, alias, pins, type); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-navigation/settings-navigation.component.css: -------------------------------------------------------------------------------- 1 | .nav-section { 2 | margin-left: 0px; 3 | margin-bottom: 16px; 4 | } 5 | 6 | .nav-section > .nav-section-title { 7 | display: block; 8 | font-size: 12px; 9 | text-transform: uppercase; 10 | color: #ccc; 11 | font-weight: bold; 12 | } 13 | 14 | ul.panel-nav-list { 15 | list-style: none; 16 | margin: 4px 0px 0px 0px; 17 | padding: 0px; 18 | } 19 | 20 | ul.panel-nav-list > li.panel-nav-list-item > a { 21 | text-decoration: none; 22 | color: #fff; 23 | } 24 | 25 | ul.panel-nav-list > li.panel-nav-list-item { 26 | padding: 4px 8px !important; 27 | } 28 | 29 | li.list-item-active { 30 | background: #2b3e50; 31 | } 32 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/NotificationRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository; 2 | 3 | import org.springframework.data.domain.Page; 4 | import org.springframework.data.domain.Pageable; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | 9 | import com.gro.model.notification.Notification; 10 | 11 | public interface NotificationRepository extends BaseRepository { 12 | 13 | @Query("SELECT n FROM Notification n WHERE isRead = :read") 14 | public Page findAllByIsRead(@Param("read") Boolean read, Pageable pageable); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/schedule/RelayScheduleJobRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository.schedule; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.security.access.prepost.PreAuthorize; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import com.gro.model.relay.RelayScheduleJob; 10 | 11 | @Repository 12 | @PreAuthorize("hasRole('ADMIN')") 13 | public interface RelayScheduleJobRepository extends CrudRepository { 14 | List findAll(); 15 | List findByEnabled(Boolean enabled); 16 | List findAllByComponentId(Integer id); 17 | } 18 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/AbstractRPiComponentPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent; 2 | 3 | import javax.persistence.GeneratedValue; 4 | import javax.persistence.GenerationType; 5 | import javax.persistence.Id; 6 | import javax.persistence.MappedSuperclass; 7 | import javax.validation.constraints.NotNull; 8 | 9 | @MappedSuperclass 10 | public abstract class AbstractRPiComponentPreferences { 11 | 12 | @Id 13 | @GeneratedValue(strategy=GenerationType.IDENTITY) 14 | private Integer id; 15 | 16 | 17 | 18 | public Integer getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Integer id) { 23 | this.id = id; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/table/table.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 2 | import { KeyToTitlePipe } from '@app/shared/pipe/key-to-title/key-to-title.pipe'; 3 | import { KeyExtractPipe } from '@app/shared/pipe/key-extract/key-extract.pipe'; 4 | 5 | @Component({ 6 | selector: 'gro-table', 7 | templateUrl: './table.component.html', 8 | styleUrls: ['./table.component.css'] 9 | }) 10 | export class TableComponent implements OnInit { 11 | 12 | @Input() 13 | headings: string[]; 14 | 15 | @Input() 16 | data: Object[]; 17 | 18 | @Input() 19 | title: string; 20 | 21 | constructor() { 22 | 23 | } 24 | 25 | ngOnInit() { } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/relay/RelayScheduleJob.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.relay; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.EnumType; 5 | import javax.persistence.Enumerated; 6 | import javax.validation.constraints.NotNull; 7 | 8 | import com.gro.model.FixedTimeScheduleJob; 9 | 10 | @Entity 11 | public class RelayScheduleJob extends FixedTimeScheduleJob { 12 | 13 | @NotNull 14 | @Enumerated(EnumType.STRING) 15 | private RelayState state; 16 | 17 | public RelayScheduleJob() {} 18 | 19 | public RelayState getState() { 20 | return state; 21 | } 22 | 23 | public void setState(RelayState state) { 24 | this.state = state; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toast-message/toast-message.component.css: -------------------------------------------------------------------------------- 1 | .alert { 2 | margin-top: 4px; 3 | margin-bottom: 4px; 4 | padding: 12px; 5 | } 6 | .alert > span { 7 | font-size: 13px; 8 | padding: 0; 9 | margin: 0; 10 | } 11 | 12 | .alert > button { 13 | margin: 0; 14 | margin-top: 2px; 15 | padding: 0; 16 | font-size: 20px; 17 | } 18 | 19 | .alert-default { 20 | background: #4e5d6c; 21 | } 22 | 23 | .fa-icon-margin { 24 | margin-right: 6px !important; 25 | } 26 | 27 | .dropshadow { 28 | -webkit-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46) !important; 29 | -moz-box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46) !important; 30 | box-shadow: -5px 4px 12px 0px rgba(0,0,0,0.46) !important; 31 | } 32 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/humidity-sensor/humidity-sensor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { CrudService } from '@app/core/service/crud.service'; 5 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 6 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 7 | 8 | import { HumiditySensor } from '@app/shared/model/rpicomponent/humidity-sensor/humidity-sensor.model'; 9 | 10 | @Injectable() 11 | export class HumiditySensorService extends CrudService { 12 | 13 | constructor(http: Http) { 14 | super(BASE_API_URL + "component/humidity", http, REQUEST_OPTIONS_DEFAULT) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/moisture-sensor/moisture-sensor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { CrudService } from '@app/core/service/crud.service'; 5 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 6 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 7 | 8 | import { MoistureSensor } from '@app/shared/model/rpicomponent/moisture-sensor/moisture-sensor.model'; 9 | 10 | @Injectable() 11 | export class MoistureSensorService extends CrudService { 12 | 13 | constructor(http: Http) { 14 | super(BASE_API_URL + "component/moisture", http, REQUEST_OPTIONS_DEFAULT) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/sensor/simple-reading/simple-reading.configuration.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '@app/shared/model/rpicomponent/rpicomponent.model'; 2 | import { SensorReadingType } from '../../../shared/sensor-reading-type.enum'; 3 | import { SimpleReadingColor } from './simple-reading-color.enum'; 4 | 5 | export class SimpleReadingConfiguration { 6 | 7 | type: SensorReadingType; 8 | component: RPiComponent; 9 | size: string[]; 10 | color: SimpleReadingColor; 11 | 12 | constructor(component: RPiComponent) { 13 | this.type = SensorReadingType.TEMPERATURE; 14 | this.component = component; 15 | this.size = []; 16 | this.color = SimpleReadingColor.GREEN; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/panel/panel.component.html: -------------------------------------------------------------------------------- 1 | 2 |
4 | 21 |
22 | 23 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph-table/graph-table-data/graph-table-data.component.css: -------------------------------------------------------------------------------- 1 | .dropdown-legend { 2 | margin-bottom: 4px !important; 3 | margin-top: 4px !important; 4 | } 5 | 6 | .btn-checkbox, .btn-radio { 7 | text-align: left; 8 | margin-bottom: 4px; 9 | } 10 | 11 | .btn-full { 12 | width: 100%; 13 | } 14 | 15 | .btn-checkbox:after, .btn-radio:after { 16 | content: ""; 17 | display: block; 18 | clear: both; 19 | } 20 | 21 | .btn-checkbox > span, .btn-radio > span { 22 | float: left; 23 | } 24 | 25 | .btn-checkbox > i, .btn-radio > i { 26 | margin-top: 4px; 27 | } 28 | 29 | .btn-checkbox > i { 30 | float: right; 31 | } 32 | 33 | .btn-radio > i { 34 | width: 20px; 35 | float: left; 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/proximity-sensor/proximity-sensor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { CrudService } from '@app/core/service/crud.service'; 5 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 6 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 7 | 8 | import { ProximitySensor } from '@app/shared/model/rpicomponent/proximity-sensor/proximity-sensor.model'; 9 | 10 | @Injectable() 11 | export class ProximitySensorService extends CrudService { 12 | 13 | constructor(http: Http) { 14 | super(BASE_API_URL + "component/proximity", http, REQUEST_OPTIONS_DEFAULT) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph/graph.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { graphPresets } from './graph-presets'; 3 | 4 | @Component({ 5 | selector: 'gro-graph', 6 | templateUrl: './graph.component.html', 7 | styleUrls: ['./graph.component.css'] 8 | }) 9 | export class GraphComponent implements OnInit { 10 | 11 | @Input() 12 | data: any; 13 | 14 | @Input() 15 | labels: any; 16 | 17 | @Input() 18 | graphType: string = "line"; 19 | 20 | graphPresets: Object; 21 | 22 | constructor() { 23 | this.graphPresets = graphPresets; 24 | } 25 | 26 | ngOnInit() {} 27 | 28 | onChangeGraphType(type: string) { 29 | this.graphType = type; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/sensor/sensor-widget.model.ts: -------------------------------------------------------------------------------- 1 | import { Widget } from '@app/shared/model/dashboard/configuration/widget/widget.model'; 2 | import { WidgetType } from '@app/shared/model/dashboard/configuration/widget/widget-type.enum'; 3 | import { SensorWidgetType } from '@app/shared/model/dashboard/configuration/widget/sensor/sensor-widget-type.enum'; 4 | import { SensorWidgetConfiguration } from '@app/shared/model/dashboard/configuration/widget/sensor/sensor-widget.configuration'; 5 | 6 | export class SensorWidget extends Widget { 7 | 8 | constructor( 9 | public type: SensorWidgetType, 10 | public configuration: SensorWidgetConfiguration 11 | ) { 12 | super(WidgetType.SENSOR); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/app/core/service/temperature-sensor/temperature-sensor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | import { CrudService } from '@app/core/service/crud.service'; 5 | import { REQUEST_OPTIONS_DEFAULT } from '@app/core/service/request-options.default'; 6 | import { BASE_API_URL } from '@app/core/service/base-api-url.default'; 7 | 8 | import { TemperatureSensor } from '@app/shared/model/rpicomponent/temperature-sensor/temperature-sensor.model'; 9 | 10 | @Injectable() 11 | export class TemperatureSensorService extends CrudService { 12 | 13 | constructor(http: Http) { 14 | super(BASE_API_URL + "component/temperature", http, REQUEST_OPTIONS_DEFAULT) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/row/row.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RowComponent } from './row.component'; 4 | 5 | describe('RowComponent', () => { 6 | let component: RowComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RowComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RowComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi/rpi.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponent } from './rpi.component'; 4 | 5 | describe('RPiComponent', () => { 6 | let component: RPiComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/controller/MoistureSensorController.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import com.gro.model.rpicomponent.component.MoistureSensor; 8 | import com.gro.repository.rpicomponent.MoistureSensorRepository; 9 | 10 | @RestController 11 | @RequestMapping("/api/component/moisture") 12 | public class MoistureSensorController extends AbstractRestController { 13 | 14 | @Autowired 15 | public MoistureSensorController(MoistureSensorRepository repository) { 16 | super(repository); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/rpicomponent/relay/relay.model.ts: -------------------------------------------------------------------------------- 1 | import { RPiComponent } from '../rpicomponent.model'; 2 | import { RPiComponentType } from '../rpicomponent-type.enum'; 3 | import { RPiPin } from '@app/shared/model/rpipin/rpi-pin.model'; 4 | import { RelayPreferences } from './relay.preferences'; 5 | import { RelayState } from './relay-state.enum'; 6 | 7 | export class Relay extends RPiComponent { 8 | 9 | constructor( 10 | public id: number, 11 | public alias: string, 12 | public state: RelayState, 13 | public pins: Array, 14 | public type: RPiComponentType, 15 | public preferences: RelayPreferences 16 | ) { 17 | super(id, alias, pins, type); 18 | if(!state) 19 | this.state = RelayState.DISABLED 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/controller/HumiditySensorController.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import com.gro.model.rpicomponent.component.HumiditySensor; 8 | import com.gro.repository.rpicomponent.HumiditySensorRepository; 9 | 10 | @RestController 11 | @RequestMapping("/api/component/humidity") 12 | public class HumiditySensorController extends AbstractRestController { 13 | 14 | @Autowired 15 | public HumiditySensorController(HumiditySensorRepository repository) { 16 | super(repository); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/controller/ProximitySensorController.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import com.gro.model.rpicomponent.component.ProximitySensor; 8 | import com.gro.repository.rpicomponent.ProximitySensorRepository; 9 | 10 | @RestController 11 | @RequestMapping("/api/component/proximity") 12 | public class ProximitySensorController extends AbstractRestController { 13 | 14 | @Autowired 15 | public ProximitySensorController(ProximitySensorRepository repository) { 16 | super(repository); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/panel/panel.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PanelComponent } from './panel.component'; 4 | 5 | describe('PanelComponent', () => { 6 | let component: PanelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PanelComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PanelComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/components/panel/panel.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PanelComponent } from './panel.component'; 4 | 5 | describe('PanelComponent', () => { 6 | let component: PanelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PanelComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PanelComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/column/column.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ColumnComponent } from './column.component'; 4 | 5 | describe('ColumnComponent', () => { 6 | let component: ColumnComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ColumnComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ColumnComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toaster.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ToasterComponent } from './toaster.component'; 4 | 5 | describe('ToasterComponent', () => { 6 | let component: ToasterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ToasterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ToasterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/control/relays/relays.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Relays

4 |
    5 | 6 |
  • {{relay.component.alias}} {{relay.state}} 8 | 9 | 16 | 17 |
  • 18 | 19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph/graph.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { GraphComponent } from './graph.component'; 4 | 5 | describe('GraphComponent', () => { 6 | let component: GraphComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ GraphComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(GraphComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/table/table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TableComponent } from './table.component'; 4 | 5 | describe('TableComponent', () => { 6 | let component: TableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TableComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-add/rpi-add.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiAddComponent } from './rpi-add.component'; 4 | 5 | describe('RPiAddComponent', () => { 6 | let component: RPiAddComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiAddComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiAddComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/web/controller/TemperatureSensorController.java: -------------------------------------------------------------------------------- 1 | package com.gro.web.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import com.gro.model.rpicomponent.component.TemperatureSensor; 8 | import com.gro.repository.rpicomponent.TemperatureSensorRepository; 9 | 10 | @RestController 11 | @RequestMapping("/api/component/temperature") 12 | public class TemperatureSensorController extends AbstractRestController { 13 | 14 | @Autowired 15 | public TemperatureSensorController(TemperatureSensorRepository repository) { 16 | super(repository); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/shared/model/dashboard/configuration/widget/graph/graph-table/data-source/data-source.configuration.ts: -------------------------------------------------------------------------------- 1 | import { MetricCalculation } from './metric-calculation.enum'; 2 | import { MetricDataType } from './metric-data-type.enum'; 3 | import { MetricTimeSpan } from './metric-time-span.enum'; 4 | import { RPiComponent } from '@app/shared/model/rpicomponent/rpicomponent.model'; 5 | 6 | export class DataSourceConfiguration { 7 | 8 | public calculation: MetricCalculation; 9 | public dataType: MetricDataType; 10 | public timeSpan: MetricTimeSpan; 11 | public component: RPiComponent; 12 | 13 | constructor() { 14 | this.calculation = MetricCalculation.AVERAGE; 15 | this.dataType = MetricDataType.TEMPERATURE; 16 | this.timeSpan = MetricTimeSpan.HOURLY; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import { CoreModule } from '@app/core/core.module'; 5 | import { SharedModule } from '@app/shared/shared.module'; 6 | import { DashboardComponentsModule } from '@app/dashboard-components/dashboard-components.module'; 7 | 8 | import { DASHBOARD_ROUTES } from './dashboard.routing'; 9 | 10 | import { DashboardComponent } from './dashboard.component'; 11 | 12 | @NgModule({ 13 | imports: [ 14 | DashboardComponentsModule, 15 | SharedModule, 16 | RouterModule.forChild(DASHBOARD_ROUTES) 17 | ], 18 | exports: [ 19 | DashboardComponent 20 | ], 21 | declarations: [ 22 | DashboardComponent 23 | ] 24 | }) 25 | export class DashboardModule {} 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-form/rpi-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiFormComponent } from './rpi-form.component'; 4 | 5 | describe('RPiFormComponent', () => { 6 | let component: RPiFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiFormComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-list/rpi-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiListComponent } from './rpi-list.component'; 4 | 5 | describe('RPiListComponent', () => { 6 | let component: RPiListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/scheduling/model/FixedTimeScheduleJob.java: -------------------------------------------------------------------------------- 1 | package com.gro.scheduling.model; 2 | 3 | import java.util.Date; 4 | 5 | import javax.persistence.DiscriminatorValue; 6 | import javax.persistence.Entity; 7 | import javax.persistence.Temporal; 8 | import javax.persistence.TemporalType; 9 | import javax.validation.constraints.NotNull; 10 | 11 | @Entity 12 | @DiscriminatorValue("FIXED") 13 | public class FixedTimeScheduleJob extends AbstractScheduleJob { 14 | 15 | @NotNull 16 | @Temporal(TemporalType.TIMESTAMP) 17 | private Date time; 18 | 19 | public FixedTimeScheduleJob() {} 20 | 21 | public Date getTime() { 22 | return this.time; 23 | } 24 | 25 | public void setTime(Date time) { 26 | this.time = time; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/security/service/JwtAuthenticationResponse.java: -------------------------------------------------------------------------------- 1 | package com.gro.security.service; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.gro.security.JwtUser; 6 | 7 | /** 8 | * Created by stephan on 20.03.16. 9 | */ 10 | public class JwtAuthenticationResponse implements Serializable { 11 | 12 | private static final long serialVersionUID = 1250166508152483573L; 13 | 14 | private final String token; 15 | private final JwtUser user; 16 | 17 | public JwtAuthenticationResponse(String token, JwtUser user) { 18 | this.token = token; 19 | this.user = user; 20 | } 21 | 22 | public String getToken() { 23 | return this.token; 24 | } 25 | 26 | public JwtUser getUser() { 27 | return this.user; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/control/simple-relay/simple-relay.component.css: -------------------------------------------------------------------------------- 1 | .dropshadow { 2 | 3 | } 4 | 5 | .relay-alert::after { 6 | content: ""; 7 | display: block; 8 | clear: both; 9 | } 10 | 11 | .relay-alert > .relay-info > h4 { 12 | font-weight: 500; 13 | margin-bottom: 0; 14 | } 15 | 16 | .relay-toggle > span { 17 | margin-top:4px; 18 | padding: 8px; 19 | } 20 | .relay-toggle > span { 21 | 22 | } 23 | 24 | .relay-alert > .relay-info > p { 25 | font-style: italic; 26 | } 27 | 28 | .relay-alert-gray-light { 29 | background-color: #546575; 30 | } 31 | 32 | .relay-alert-gray { 33 | background-color: #4e5d6c; 34 | } 35 | 36 | .relay-alert-gray-dark { 37 | background-color: #3f4b58; 38 | } 39 | 40 | .relay-alert-gray-darker { 41 | background-color: #2b3e50; 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/sensor/readings-list/readings-list.component.css: -------------------------------------------------------------------------------- 1 | ul.panel-body-list { 2 | list-style: none; 3 | background: #546575; 4 | margin: 0; 5 | padding: 16px; 6 | } 7 | 8 | ul.panel-body-list > li.panel-body-list-title { 9 | 10 | } 11 | 12 | ul.panel-body-list > li.panel-body-list-title > span { 13 | background: #4e5d6c; 14 | display: block; 15 | text-align: right; 16 | padding: 8px 16px; 17 | } 18 | 19 | ul.panel-body-list > li.panel-body-list-title > span > i { 20 | width: 16px; 21 | } 22 | 23 | ul.panel-body-list > li.panel-body-list-title > ul { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | ul.panel-body-list > li.panel-body-list-title > ul > li { 29 | list-style: none; 30 | padding: 8px 8px; 31 | border-bottom: 1px solid #4e5d6c 32 | } 33 | -------------------------------------------------------------------------------- /frontend/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { HttpModule } from '@angular/http'; 4 | 5 | import { AppRoutingModule } from './app.routing'; 6 | import { AuthenticationModule } from './authentication/authentication.module'; 7 | import { CoreModule } from './core/core.module'; 8 | import { NavigationModule } from './navigation/navigation.module'; 9 | 10 | import { AppComponent } from './app.component'; 11 | 12 | 13 | @NgModule({ 14 | declarations: [ 15 | AppComponent 16 | ], 17 | imports: [ 18 | AppRoutingModule, 19 | AuthenticationModule, 20 | BrowserModule, 21 | CoreModule, 22 | HttpModule, 23 | NavigationModule, 24 | ], 25 | bootstrap: [AppComponent] 26 | }) 27 | export class AppModule { } 28 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-pinout/rpi-pinout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiPinoutComponent } from './rpi-pinout.component'; 4 | 5 | describe('RPiPinoutComponent', () => { 6 | let component: RPiPinoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiPinoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiPinoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/page-loader/page-loader.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageLoaderComponent } from './page-loader.component'; 4 | 5 | describe('PageLoaderComponent', () => { 6 | let component: PageLoaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PageLoaderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageLoaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/repository/RestrictedWriteRepository.java: -------------------------------------------------------------------------------- 1 | package com.gro.repository; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | import org.springframework.data.repository.NoRepositoryBean; 7 | import org.springframework.security.access.prepost.PreAuthorize; 8 | 9 | @NoRepositoryBean 10 | public interface RestrictedWriteRepository extends BaseRepository { 11 | 12 | T findOne(ID id); 13 | boolean exists(ID id); 14 | List findAll(); 15 | long count(); 16 | 17 | @PreAuthorize("hasRole('ADMIN')") 18 | void delete(ID id); 19 | 20 | @PreAuthorize("hasRole('ADMIN')") 21 | void delete(Iterable entities); 22 | 23 | @PreAuthorize("hasRole('ADMIN')") 24 | S save(S entity); 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-details/rpi-details.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiDetailsComponent } from './rpi-details.component'; 4 | 5 | describe('RPiDetailsComponent', () => { 6 | let component: RPiDetailsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiDetailsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiDetailsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/settings-rpi.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SettingsRPiComponent } from './settings-rpi.component'; 4 | 5 | describe('SettingsRpiComponent', () => { 6 | let component: SettingsRPiComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SettingsRPiComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SettingsRPiComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpi-pinout/rpi-pinout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiPinoutComponent } from './rpi-pinout.component'; 4 | 5 | describe('RPiPinoutComponent', () => { 6 | let component: RPiPinoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiPinoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiPinoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/pageable-table/pageable-table.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 2 | 3 | import { Page } from '@app/shared/model/paging/page.model'; 4 | 5 | @Component({ 6 | selector: 'gro-pageable-table', 7 | templateUrl: './pageable-table.component.html', 8 | styleUrls: ['./pageable-table.component.css'] 9 | }) 10 | export class PageableTableComponent implements OnInit { 11 | 12 | @Output() 13 | onPageChange = new EventEmitter(); 14 | 15 | @Input() 16 | page: Page; 17 | 18 | @Input() 19 | headings: string[]; 20 | 21 | @Input() 22 | title: string; 23 | 24 | constructor() { } 25 | 26 | ngOnInit() { 27 | } 28 | 29 | pageChange(page: number) { 30 | this.onPageChange.emit(page); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification/notification.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NotificationComponent } from './notification.component'; 4 | 5 | describe('NotificationComponent', () => { 6 | let component: NotificationComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NotificationComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NotificationComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/simple-loader/simple-loader.component.css: -------------------------------------------------------------------------------- 1 | .simple-loader { 2 | margin: auto; 3 | border-radius: 50%; 4 | border-style: solid; 5 | border-color: #FFF; /* Light grey 4e5d6c */ 6 | border-top-color: #2b3e50; /* dark gray */ 7 | animation: spin 1s linear infinite; 8 | } 9 | 10 | @keyframes spin { 11 | 0% { transform: rotate(0deg); } 12 | 100% { transform: rotate(360deg); } 13 | } 14 | 15 | .simple-loader-xs { 16 | border-width: 2px; 17 | width: 16px; 18 | height: 16px; 19 | } 20 | 21 | .simple-loader-sm { 22 | border-width: 4px; 23 | width: 32px; 24 | height: 32px; 25 | } 26 | 27 | .simple-loader-md { 28 | border-width: 8px; 29 | width: 64px; 30 | height: 64px; 31 | } 32 | 33 | .simple-loader-lg { 34 | border-width: 16px; 35 | width: 128px; 36 | height: 128px; 37 | } 38 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph-table/graph-table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { GraphTableComponent } from './graph-table.component'; 4 | 5 | describe('GraphTableComponent', () => { 6 | let component: GraphTableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ GraphTableComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(GraphTableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/file-uploader/file-uploader.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FileUploaderComponent } from './file-uploader.component'; 4 | 5 | describe('FileUploaderComponent', () => { 6 | let component: FileUploaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FileUploaderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FileUploaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/modal-confirm/modal-confirm.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModalConfirmComponent } from './modal-confirm.component'; 4 | 5 | describe('ModalConfirmComponent', () => { 6 | let component: ModalConfirmComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ModalConfirmComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ModalConfirmComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/simple-loader/simple-loader.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SimpleLoaderComponent } from './simple-loader.component'; 4 | 5 | describe('SimpleLoaderComponent', () => { 6 | let component: SimpleLoaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SimpleLoaderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SimpleLoaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toast-message/toast-message.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ToastMessageComponent } from './toast-message.component'; 4 | 5 | describe('ToastMessageComponent', () => { 6 | let component: ToastMessageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ToastMessageComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ToastMessageComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toast-message/toast-message.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | import { ToastMessage } from '../toast-message.model'; 4 | import { ToastType } from '../toast-type.enum'; 5 | 6 | @Component({ 7 | selector: 'gro-toast-message', 8 | templateUrl: './toast-message.component.html', 9 | styleUrls: ['./toast-message.component.css'] 10 | }) 11 | export class ToastMessageComponent implements OnInit { 12 | 13 | @Input() 14 | message: ToastMessage; 15 | dismissed: boolean = false; 16 | 17 | private toastType = ToastType; 18 | 19 | constructor() { 20 | this.message = new ToastMessage(ToastType.DANGER, "A blank toast message was created"); 21 | } 22 | 23 | ngOnInit() { 24 | } 25 | 26 | dismiss() { 27 | this.dismissed = true; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/table/table.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
{{ heading | keyToTitle:"camel" }}
{{ heading }}
{{ d.timestamp | date:'short' }}{{ d.component.alias }}{{ d.temperature }}{{ d.humidity }}
21 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-list/notification-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 8 | 9 |
10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | There are no notifications. 18 |
19 |
20 |
21 | 22 | 23 |
24 |
25 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/control/simple-relay/simple-relay.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SimpleRelayComponent } from './simple-relay.component'; 4 | 5 | describe('SimpleRelayComponent', () => { 6 | let component: SimpleRelayComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SimpleRelayComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SimpleRelayComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-builder/dashboard-builder.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DashboardBuilderComponent } from './dashboard-builder.component'; 4 | 5 | describe('DashboardBuilderComponent', () => { 6 | let component: DashboardBuilderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DashboardBuilderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DashboardBuilderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/sensor/readings-list/readings-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ReadingsListComponent } from './readings-list.component'; 4 | 5 | describe('ReadingsListComponent', () => { 6 | let component: ReadingsListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ReadingsListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ReadingsListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/table/pageable-table/pageable-table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageableTableComponent } from './pageable-table.component'; 4 | 5 | describe('PageableTableComponent', () => { 6 | let component: PageableTableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PageableTableComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageableTableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpi-upload-image/rpi-upload-image.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiUploadImageComponent } from './rpi-upload-image.component'; 4 | 5 | describe('RPiUploadImageComponent', () => { 6 | let component: RPiUploadImageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiUploadImageComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiUploadImageComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/TemperatureSensorPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.EnumType; 5 | import javax.persistence.Enumerated; 6 | import javax.validation.constraints.NotNull; 7 | 8 | import com.gro.model.rpicomponent.AbstractSensorPreferences; 9 | 10 | @Entity 11 | public class TemperatureSensorPreferences extends AbstractSensorPreferences { 12 | 13 | @Enumerated(EnumType.STRING) 14 | @NotNull 15 | private TemperatureUnit temperatureUnit = TemperatureUnit.CELSIUS; 16 | 17 | public TemperatureUnit getTemperatureUnit() { 18 | return temperatureUnit; 19 | } 20 | 21 | public void setTemperatureUnit(TemperatureUnit temperatureUnit) { 22 | this.temperatureUnit = temperatureUnit; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/app/core/component/toaster/toast-message/toast-message.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 7 | 9 | 11 | {{ message.message }} 12 | 13 | 14 | 15 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/panel/fixed-side-panel/fixed-side-panel.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FixedSidePanelComponent } from './fixed-side-panel.component'; 4 | 5 | describe('FixedSidePanelComponent', () => { 6 | let component: FixedSidePanelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FixedSidePanelComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FixedSidePanelComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/sensor/simple-reading/simple-reading.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SimpleReadingComponent } from './simple-reading.component'; 4 | 5 | describe('SimpleReadingComponent', () => { 6 | let component: SimpleReadingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SimpleReadingComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SimpleReadingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/navigation/notification-list/notification-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NotificationListComponent } from './notification-list.component'; 4 | 5 | describe('NotificationListComponent', () => { 6 | let component: NotificationListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NotificationListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NotificationListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-add/rpicomponent-add.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentAddComponent } from './rpicomponent-add.component'; 4 | 5 | describe('RPiComponentAddComponent', () => { 6 | let component: RPiComponentAddComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentAddComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentAddComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/shared/component/modal-confirm/modal-confirm.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; 2 | import { ModalConfirm } from './modal-confirm.model'; 3 | 4 | @Component({ 5 | selector: 'gro-modal-confirm', 6 | templateUrl: './modal-confirm.component.html', 7 | styleUrls: ['./modal-confirm.component.css'] 8 | }) 9 | export class ModalConfirmComponent implements OnInit { 10 | 11 | @Input() 12 | modalConfirm: ModalConfirm; 13 | 14 | @Output() 15 | onConfirm: EventEmitter = new EventEmitter(); 16 | 17 | constructor() { 18 | this.modalConfirm = new ModalConfirm("Are you sure?", false, "Confirmation"); 19 | } 20 | 21 | ngOnInit() { 22 | } 23 | 24 | confirm(confirm: boolean) { 25 | this.onConfirm.emit(confirm) 26 | this.modalConfirm.setShown(false); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-form/rpicomponent-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentFormComponent } from './rpicomponent-form.component'; 4 | 5 | describe('RPiComponentFormComponent', () => { 6 | let component: RPiComponentFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentFormComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-add/rpicomponent-add.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentAddComponent } from './rpicomponent-add.component'; 4 | 5 | describe('RPiComponentAddComponent', () => { 6 | let component: RPiComponentAddComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentAddComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentAddComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/data/HumidityDTO.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.data; 2 | 3 | import java.util.Date; 4 | 5 | import com.gro.model.rpicomponent.AbstractDataDTO; 6 | 7 | public class HumidityDTO extends AbstractDataDTO { 8 | 9 | private Double humidity; 10 | 11 | public HumidityDTO() {} 12 | 13 | public HumidityDTO(Date timestamp, Double humidity) { 14 | super(timestamp); 15 | this.humidity = humidity; 16 | } 17 | 18 | public HumidityDTO(Date timestamp, Double humidity, Integer componentId) { 19 | super(timestamp, componentId); 20 | this.humidity = humidity; 21 | } 22 | 23 | public Double getHumidity() { 24 | return humidity; 25 | } 26 | 27 | public void setHumidity(Double humidity) { 28 | this.humidity = humidity; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/preferences/TemperatureHumiditySensorPreferences.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.preferences; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.EnumType; 5 | import javax.persistence.Enumerated; 6 | import javax.validation.constraints.NotNull; 7 | 8 | import com.gro.model.rpicomponent.AbstractSensorPreferences; 9 | 10 | @Entity 11 | public class TemperatureHumiditySensorPreferences extends AbstractSensorPreferences { 12 | 13 | @Enumerated(EnumType.STRING) 14 | @NotNull 15 | private TemperatureUnit temperatureUnit = TemperatureUnit.CELSIUS; 16 | 17 | public TemperatureUnit getTemperatureUnit() { 18 | return temperatureUnit; 19 | } 20 | 21 | public void setTemperatureUnit(TemperatureUnit temperatureUnit) { 22 | this.temperatureUnit = temperatureUnit; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/app/core/core.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { CoreResolveModule } from './resolve/core-resolve.module'; 5 | import { CoreServiceModule } from './service/core-service.module'; 6 | 7 | import { ToasterComponent } from './component/toaster/toaster.component'; 8 | import { ToastMessageComponent } from './component/toaster/toast-message/toast-message.component'; 9 | 10 | import { ToasterService } from './component/toaster/toaster.service'; 11 | 12 | @NgModule({ 13 | imports: [ 14 | CommonModule 15 | ], 16 | exports: [ 17 | ToasterComponent, 18 | CoreServiceModule, 19 | CoreResolveModule 20 | ], 21 | declarations: [ 22 | ToasterComponent, 23 | ToastMessageComponent 24 | ], 25 | providers: [ 26 | ToasterService 27 | ] 28 | }) 29 | export class CoreModule { } 30 | -------------------------------------------------------------------------------- /frontend/src/app/dashboard-components/widgets/graph/graph-table/graph-table-data/graph-table-data.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { GraphTableDataComponent } from './graph-table-data.component'; 4 | 5 | describe('GraphTableDataComponent', () => { 6 | let component: GraphTableDataComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ GraphTableDataComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(GraphTableDataComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpi/rpicomponent-table/rpicomponent-table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentTableComponent } from './rpicomponent-table.component'; 4 | 5 | describe('RPiComponentsTableComponent', () => { 6 | let component: RPiComponentTableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentTableComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentTableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-edit/rpicomponent-edit.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentEditComponent } from './rpicomponent-edit.component'; 4 | 5 | describe('RPiComponentEditComponent', () => { 6 | let component: RPiComponentEditComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentEditComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentEditComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-form/rpicomponent-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentFormComponent } from './rpicomponent-form.component'; 4 | 5 | describe('RPiComponentFormComponent', () => { 6 | let component: RPiComponentFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentFormComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/gro/model/rpicomponent/data/ProximityDTO.java: -------------------------------------------------------------------------------- 1 | package com.gro.model.rpicomponent.data; 2 | 3 | import java.util.Date; 4 | 5 | import com.gro.model.rpicomponent.AbstractDataDTO; 6 | 7 | public class ProximityDTO extends AbstractDataDTO { 8 | 9 | private Double distance; 10 | 11 | public ProximityDTO() {} 12 | 13 | public ProximityDTO(Date timestamp, Double distance) { 14 | super(timestamp); 15 | this.distance = distance; 16 | } 17 | 18 | public ProximityDTO(Date timestamp, Double distance, Integer componentId) { 19 | super(timestamp, componentId); 20 | this.distance = distance; 21 | } 22 | 23 | public void setDistance(Double distance) { 24 | this.distance = distance; 25 | } 26 | 27 | public Double getDistance() { 28 | return this.distance; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-rpicomponent/rpicomponent-table/rpicomponent-table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RPiComponentTableComponent } from './rpicomponent-table.component'; 4 | 5 | describe('RPiComponentsTableComponent', () => { 6 | let component: RPiComponentTableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RPiComponentTableComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RPiComponentTableComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/src/app/settings/settings-schedule/relay-schedule-form/relay-schedule-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RelayScheduleFormComponent } from './relay-schedule-form.component'; 4 | 5 | describe('RelayScheduleFormComponent', () => { 6 | let component: RelayScheduleFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RelayScheduleFormComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RelayScheduleFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | --------------------------------------------------------------------------------