Release 1.3.0

This commit is contained in:
2021-08-26 12:33:15 +02:00
commit 9bb72f0207
1148 changed files with 92133 additions and 0 deletions

71
dev/.gitignore vendored Normal file
View File

@@ -0,0 +1,71 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.envrc
# next.js build output
.next
# Python stuff
__pycache__/
*.pyc
# homehub
.venv/
build/
frontend/

BIN
dev/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

21
dev/babel.config.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = {
'presets': [
[
'@babel/preset-env', {
'targets': {
'chrome': 81,
'edge': 18,
'firefox': 75,
'ie': 11,
'opera': 68,
'safari': 13
},
'modules': 'commonjs'
}
],
'@babel/preset-react'
],
'plugins': [
'@babel/plugin-proposal-class-properties'
]
};

13
dev/docker-compose.yml Normal file
View File

@@ -0,0 +1,13 @@
version: '3'
services:
homehub:
image: docker-hosted.nexus.bthlabs.pl/homehub:1.0.0
volumes:
- "homehub_var:/homehub_var"
- ".:/homehub_workspace"
ports:
- "3010:3010"
volumes:
homehub_var:

View File

@@ -0,0 +1,5 @@
#!/bin/sh
set -e
apk add build-base python3-dev autoconf

3
dev/gunicorn.conf.py Normal file
View File

@@ -0,0 +1,3 @@
bind = "0.0.0.0:3010"
worker_class = "aiohttp.GunicornWebWorker"
workers = 1

2
dev/homehub.py Normal file
View File

@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from homehub_backend.app import app

5
dev/index.js Normal file
View File

@@ -0,0 +1,5 @@
import * as HomeHubApp from '@bthlabs/homehub-app';
import SETTINGS from './settings';
HomeHubApp.App(SETTINGS);

40
dev/package.json Normal file
View File

@@ -0,0 +1,40 @@
{
"name": "dev",
"version": "1.0.0",
"description": "The BTHLabs HomeHub Workspace",
"main": "src/index.js",
"author": "BTHLabs <contact@bthlabs.pl> (https://bthlabs.pl/)",
"license": "SEE LICENSE IN LICENSE",
"scripts": {
"build": "NODE_ENV=production npx webpack-cli",
"dev": "npx webpack-cli",
"start": "WDS=true npx webpack-dev-server"
},
"dependencies": {
"@bthlabs/homehub-app": "1.3.0",
"@bthlabs/homehub-components": "1.3.0",
"@bthlabs/homehub-core": "1.3.0",
"@bthlabs/homehub-icons": "1.3.0",
"@bthlabs/homehub-iformicarium": "1.3.0",
"@bthlabs/homehub-tradfri": "1.3.0",
"@babel/core": "7.7.2",
"@babel/plugin-proposal-class-properties": "7.8.3",
"@babel/preset-env": "7.7.1",
"@babel/preset-react": "7.7.0",
"babel-loader": "8.0.6",
"css-loader": "3.5.3",
"clean-webpack-plugin": "3.0.0",
"copy-webpack-plugin": "6.0.3",
"html-webpack-plugin": "4.2.1",
"prop-types": "15.7.2",
"react": "16.11.0",
"react-bootstrap": "1.0.1",
"react-dom": "16.11.0",
"style-loader": "1.2.1",
"webpack": "4.41.2",
"webpack-cli": "3.3.11"
},
"devDependencies": {
"webpack-dev-server": "3.10.3"
}
}

2
dev/requirements-dev.txt Normal file
View File

@@ -0,0 +1,2 @@
-r requirements.txt
aiohttp-devtools==0.13.1

3
dev/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
homehub_backend==1.3.0
homehub_iformicarium==1.3.0
homehub_tradfri==1.3.0

37
dev/settings.js Normal file
View File

@@ -0,0 +1,37 @@
import * as HOMEHUB_SETTINGS from '@bthlabs/homehub-app/lib/settings';
import {
SERVICES as IFORMICARIUM_SERVICES,
WIDGETS as IFORMICARIUM_WIDGETS
} from '@bthlabs/homehub-iformicarium';
import {
SERVICES as TRADFRI_SERVICES,
WIDGETS as TRADFRI_WIDGETS
} from '@bthlabs/homehub-tradfri';
import {FakeAPIService, FakeAPIWidget} from 'vendor/fake_api_service';
import {VendorTestService, VendorTestWidget} from 'vendor/vendor_test';
var APP_SETTINGS = {
...HOMEHUB_SETTINGS,
WEBSOCKET: {
...HOMEHUB_SETTINGS.WEBSOCKET,
url: 'ws://homehub.work/backend/websocket'
},
SERVICES: {
...HOMEHUB_SETTINGS.SERVICES,
...IFORMICARIUM_SERVICES,
...TRADFRI_SERVICES,
[VendorTestService.kind]: VendorTestService,
[FakeAPIService.kind]: FakeAPIService
},
WIDGETS: {
...HOMEHUB_SETTINGS.WIDGETS,
...IFORMICARIUM_WIDGETS,
...TRADFRI_WIDGETS,
[VendorTestService.widget]: VendorTestWidget,
[FakeAPIService.widget]: FakeAPIWidget
},
OFFLINE_MODE: false
};
export default APP_SETTINGS;

15
dev/settings.py Normal file
View File

@@ -0,0 +1,15 @@
from homehub_backend.settings import *
from homehub_iformicarium.services import iFormicariumService
from homehub_tradfri.services import TradfriService
from vendor.fake_api_service import FakeAPIService
from vendor.vendor_test import VendorTestService
DEBUG = True
WEATHER_SERVICE_API_KEY = 'f394f91b23746fb42e5ff643f2c5a96f'
SERVICES['VendorTestService'] = VendorTestService
SERVICES[TradfriService.KIND] = TradfriService
SERVICES[iFormicariumService.KIND] = iFormicariumService
SERVICES[FakeAPIService.KIND] = FakeAPIService

5
dev/start.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
export PYTHONPATH="`realpath .`"
exec adev runserver --host=10.100.100.101 --port=3010 --aux-port=3011 homehub.py

51
dev/state.json Normal file
View File

@@ -0,0 +1,51 @@
{
"frontend": {
"dashboards": [
{
"id": "62477a3a-707d-42d8-805e-427a26946750",
"name": "Default",
"services": [
{
"kind": "kServiceTime",
"instance": "e1f72865-69fd-4faf-9c05-684c786b9f1a",
"characteristics": {
"locale": "",
"timeFormat": "",
"dateFormat": "DATE_HUGE",
"appearance": {
"color": "#008A00"
}
},
"layout": {
"x": 0,
"y": 0,
"w": 6,
"h": 3
}
},
{
"kind": "kServiceUptime",
"instance": "e26eabbc-440b-4784-a775-8ef5605ccb4b",
"characteristics": {
"appearance": {
"color": "#6D8764"
}
},
"layout": {
"x": 6,
"y": 0,
"w": 6,
"h": 3
}
}
]
},
{
"id": "88a726fe-ff95-4977-bb84-7a731f7fdc33",
"name": "Test",
"services": []
}
]
},
"backend": {}
}

25
dev/templates/index.html Normal file
View File

@@ -0,0 +1,25 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<title>BTHLabs HomeHub</title>
<link href="<%= publicPath %>homehub-<%= build %>.css" rel="stylesheet">
<link href="<%= publicPath %>homehub-components-<%= build %>.css" rel="stylesheet">
<link href="<%= publicPath %>icon.png" rel="apple-touch-icon">
<link href="<%= publicPath %>icon.png" rel="shortcut icon">
</head>
<body>
<div id="root"></div>
<script type="text/javascript">
window.HOMEHUB_CONFIG = {
version: '<%= version %>',
build: '<%= build %>'
};
</script>
</body>
</html>

0
dev/vendor/__init__.py vendored Normal file
View File

116
dev/vendor/fake_api_service.js vendored Normal file
View File

@@ -0,0 +1,116 @@
import {Widget} from '@bthlabs/homehub-components';
import {API, BaseService} from '@bthlabs/homehub-core';
import React from 'react';
export const FakeAPIWidgetSettingsView = (props) => {
const onSpamInputChange = React.useCallback(
(event) => {
props.setNextCharacteristics({
...props.nextCharacteristics,
spam: event.target.value
});
},
[props]
);
const onEggsInputChange = React.useCallback(
(event) => {
props.setNextCharacteristics({
...props.nextCharacteristics,
eggs: event.target.value
});
},
[props]
);
if (!props.nextCharacteristics) {
return null;
}
return (
<React.Fragment>
<p>
<label htmlFor="input-spam">Spam</label>
<input
type="text"
value={props.nextCharacteristics.spam}
onChange={onSpamInputChange}
/>
</p>
<p>
<label htmlFor="input-eggs">Eggs</label>
<input
type="text"
value={props.nextCharacteristics.eggs}
onChange={onEggsInputChange}
/>
</p>
</React.Fragment>
)
};
export const FakeAPIWidget = (props) => {
let appearance = {...props.appearance};
if (props.serviceState !== null) {
console.log('FakeAPIWidget()', props.serviceState.payload, props.serviceState.isLoading())
if (props.serviceState.isLoading()) {
appearance.color = 'blue';
} else if (props.serviceState.hasError()) {
appearance.color = 'purple';
} else if (props.serviceState.hasFatalError()) {
appearance.color = 'red';
} else if (props.serviceState.hasData()) {
appearance.color = 'green';
}
}
return (
<Widget {...props} appearance={appearance}>
<p>
<code>spam: &raquo;{props.service.characteristics['spam']}&laquo;</code>
<br/>
<code>eggs: &raquo;{props.service.characteristics['eggs']}&laquo;</code>
</p>
<p>
<code>serviceState: &raquo;{JSON.stringify(props.serviceState)}&laquo;</code>
</p>
</Widget>
);
};
FakeAPIWidget.defaultLayout = {
h: 6,
w: 4
};
FakeAPIWidget.layoutConstraints = {
minH: 6,
minW: 4
};
FakeAPIWidget.settingsView = FakeAPIWidgetSettingsView;
FakeAPIWidget.title = 'Fake API Service';
export class FakeAPIService extends BaseService {
static kind = 'FakeAPIService';
static widget = 'FakeAPIWidget';
static emptyCharacteristics () {
return {
'spam': '',
'eggs': ''
};
}
async start () {
const result = await API.Services.start(
FakeAPIService.kind, this.instance, this.characteristics
);
this.notify(result);
}
async stop () {
return API.Services.stop(FakeAPIService.kind, this.instance);
}
setCharacteristics (newCharacteristics) {
super.setCharacteristics(newCharacteristics);
this.restart()
}
}

33
dev/vendor/fake_api_service.py vendored Normal file
View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
import asyncio
import datetime
import logging
from homehub_backend.lib.services import BaseService, ServiceData
LOGGER = logging.getLogger('homehub.fake_api_service')
class FakeAPIService(BaseService):
KIND = 'FakeAPIService'
def __init__(self, *args, **kwargs):
super(FakeAPIService, self).__init__(*args, **kwargs)
self.started_at = None
async def current_data(self):
result = ServiceData()
if self.started_at:
result.data = {
'started_at': self.started_at.isoformat()
}
return result
async def start(self):
LOGGER.debug('FakeAPIService.start()')
await asyncio.sleep(5)
self.started_at = datetime.datetime.utcnow()
async def stop(self):
LOGGER.debug('FakeAPIService.stop()')

36
dev/vendor/vendor_test.js vendored Normal file
View File

@@ -0,0 +1,36 @@
import {Widget} from '@bthlabs/homehub-components';
import {API, BaseService} from '@bthlabs/homehub-core';
import React from 'react';
export const VendorTestWidget = (props) => {
return (
<Widget {...props}>
<p>Hello, <strong>VendorTestWidget!</strong></p>
</Widget>
);
};
VendorTestWidget.defaultLayout = {
h: 2,
w: 2
};
VendorTestWidget.layoutConstraints = {
minH: 2,
minW: 2
};
VendorTestWidget.title = 'Vendor Test';
export class VendorTestService extends BaseService {
static kind = 'VendorTestService';
static widget = 'VendorTestWidget';
async start () {
const result = await API.Services.start(
VendorTestService.kind, this.instance, this.characteristics
);
this.notify(result.data);
}
async stop () {
return API.Services.stop(VendorTestService.kind, this.instance);
}
}

16
dev/vendor/vendor_test.py vendored Normal file
View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
import logging
from homehub_backend.lib.services import BaseService
LOGGER = logging.getLogger('homehub.vendor_test')
class VendorTestService(BaseService):
KIND = 'VendorTestService'
async def start(self):
LOGGER.debug('VendorTestService.start()')
async def stop(self):
LOGGER.debug('VendorTestService.stop()')

173
dev/webpack.config.js Normal file
View File

@@ -0,0 +1,173 @@
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const packageJSON = require('./package.json');
const IS_PRODUCTION = (process.env['NODE_ENV'] === 'production');
const IS_WDS = (process.env['WDS'] === 'true');
const MODULES_FOLDER = (
(process.env['YARN_MODULES_FOLDER']) ? process.env['YARN_MODULES_FOLDER'] : 'node_modules'
);
const CONTEXT = path.resolve(__dirname);
const OUTPUT_DIR = path.resolve(CONTEXT, 'frontend');
const settingsContent = fs.readFileSync(path.resolve(CONTEXT, 'settings.js'));
const settingsHash = crypto.createHash('sha1');
settingsHash.update(settingsContent);
const BUILD = settingsHash.digest('hex');
const OUTPUT_FILENAME = `[name]-${BUILD}.js`;
const PUBLIC_PATH = (IS_WDS) ? '/' : '/frontend/';
const VENDOR_PATH = path.resolve('./vendor');
const HOMEHUB_CSS_PATTERN = (IS_PRODUCTION) ? 'homehub.css' : 'homehub.css*';
const HOMEHUB_COMPONENTS_CSS_PATTERN = (
(IS_PRODUCTION) ? 'homehub-components.css' : 'homehub-components.css*'
);
const copyTransformPath = (targetPath, absolutePath) => {
return path.basename(targetPath).replace('.css', `-${BUILD}.css`);
};
const copyTransform = (content, absolutePath) => {
if (IS_PRODUCTION) {
return content;
}
const filename = path.basename(absolutePath);
const cssFilename = path.basename(filename, '.map');
const stringContent = content.toString('utf-8').replace(
cssFilename, cssFilename.replace('.css', `-${BUILD}.css`)
);
return stringContent;
};
const config = {
mode: (IS_PRODUCTION) ? 'production' : 'development',
devtool: (IS_PRODUCTION) ? false : 'source-map',
context: CONTEXT,
entry: {
homehub: './index.js'
},
output: {
path: OUTPUT_DIR,
publicPath: PUBLIC_PATH,
filename: OUTPUT_FILENAME
},
module: {
rules: [
{
test: /\.js?$/,
include: VENDOR_PATH,
use: [
'babel-loader'
]
},
{
test: /\.css?$/,
use: [
'style-loader',
'css-loader'
]
}
]
},
resolve: {
modules: [MODULES_FOLDER],
alias: {
'@bthlabs/homehub-app': path.resolve(
MODULES_FOLDER, '@bthlabs/homehub-app'
),
'@bthlabs/homehub-components': path.resolve(
MODULES_FOLDER, '@bthlabs/homehub-components'
),
'@bthlabs/homehub-core': path.resolve(
MODULES_FOLDER, '@bthlabs/homehub-core'
),
'@bthlabs/homehub-icons': path.resolve(
MODULES_FOLDER, '@bthlabs/homehub-icons'
),
'prop-types': path.resolve(MODULES_FOLDER, 'prop-types'),
react: path.resolve(MODULES_FOLDER, 'react'),
'react-bootstrap': path.resolve(MODULES_FOLDER, 'react-bootstrap'),
'react-dom': path.resolve(MODULES_FOLDER, 'react-dom'),
'vendor': VENDOR_PATH
}
},
devServer: {
disableHostCheck: true,
host: '10.100.100.101',
port: 3012,
proxy: {
'/backend': 'http://10.100.100.101:3010'
}
},
plugins: [
new CleanWebpackPlugin(),
new webpack.DefinePlugin({
PRODUCTION: IS_PRODUCTION
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(CONTEXT, 'templates', 'index.html'),
templateParameters: {
build: BUILD,
version: packageJSON.version,
publicPath: PUBLIC_PATH
}
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(
MODULES_FOLDER, '@bthlabs', 'homehub-app', 'lib',
HOMEHUB_CSS_PATTERN
),
transformPath: copyTransformPath,
transform: copyTransform
}
]
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(
MODULES_FOLDER, '@bthlabs', 'homehub-components', 'lib',
HOMEHUB_COMPONENTS_CSS_PATTERN
),
transformPath: copyTransformPath,
transform: copyTransform
}
]
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'assets/icon.png'
}
]
})
]
};
if (IS_PRODUCTION) {
config.resolve.alias = {
...config.resolve.alias,
'prop-types': path.resolve(MODULES_FOLDER, 'prop-types/prop-types.min.js'),
'react': path.resolve(MODULES_FOLDER, 'react/umd/react.production.min.js'),
'react-dom': path.resolve(
MODULES_FOLDER, 'react-dom/umd/react-dom.production.min.js'
)
};
}
module.exports = config;

5919
dev/yarn.lock Normal file

File diff suppressed because it is too large Load Diff