├── env.d.ts
├── .vscode
└── extensions.json
├── dist
├── favicon.ico
├── assets
│ ├── xknx_logo_inverted-1da82253.png
│ └── index-04e56ed8.css
└── index.html
├── public
├── favicon.ico
└── index.html
├── src
├── assets
│ ├── xknx_logo_inverted.png
│ ├── main.css
│ └── base.css
├── main.ts
├── views
│ ├── HomeView.vue
│ └── AboutView.vue
├── router
│ └── index.ts
├── App.vue
└── components
│ └── ConfigurationImporter.vue
├── .prettierrc.json
├── tsconfig.vitest.json
├── tsconfig.node.json
├── tsconfig.json
├── tsconfig.app.json
├── .eslintrc.cjs
├── index.html
├── .gitignore
├── vite.config.ts
├── vitest.config.ts
├── package.json
└── README.md
/env.d.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
3 | }
4 |
--------------------------------------------------------------------------------
/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensVanhooydonck/xknx-configuration-importer/HEAD/dist/favicon.ico
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensVanhooydonck/xknx-configuration-importer/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/xknx_logo_inverted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensVanhooydonck/xknx-configuration-importer/HEAD/src/assets/xknx_logo_inverted.png
--------------------------------------------------------------------------------
/dist/assets/xknx_logo_inverted-1da82253.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JensVanhooydonck/xknx-configuration-importer/HEAD/dist/assets/xknx_logo_inverted-1da82253.png
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/prettierrc",
3 | "semi": false,
4 | "tabWidth": 2,
5 | "singleQuote": true,
6 | "printWidth": 100,
7 | "trailingComma": "none"
8 | }
--------------------------------------------------------------------------------
/tsconfig.vitest.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.app.json",
3 | "exclude": [],
4 | "compilerOptions": {
5 | "composite": true,
6 | "lib": [],
7 | "types": ["node", "jsdom"]
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@vue/tsconfig/tsconfig.node.json",
3 | "include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
4 | "compilerOptions": {
5 | "composite": true,
6 | "experimentalDecorators": true,
7 | "types": ["node"]
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { createPinia } from 'pinia'
3 |
4 | import App from './App.vue'
5 | import router from './router'
6 |
7 | import './assets/main.css'
8 |
9 | const app = createApp(App)
10 |
11 | app.use(createPinia())
12 | app.use(router)
13 |
14 | app.mount('#app')
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "compilerOptions": {
4 | "experimentalDecorators": true
5 | },
6 | "references": [
7 | {
8 | "path": "./tsconfig.node.json"
9 | },
10 | {
11 | "path": "./tsconfig.app.json"
12 | },
13 | {
14 | "path": "./tsconfig.vitest.json"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@vue/tsconfig/tsconfig.web.json",
3 | "include": ["../env.d.ts", "src/**/*", "src/**/*.vue"],
4 | "exclude": ["src/**/__tests__/*"],
5 | "compilerOptions": {
6 | "composite": true,
7 | "experimentalDecorators": true,
8 | "baseUrl": ".",
9 | "paths": {
10 | "@/*": ["./src/*"]
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | require('@rushstack/eslint-patch/modern-module-resolution')
3 |
4 | module.exports = {
5 | root: true,
6 | 'extends': [
7 | 'plugin:vue/vue3-essential',
8 | 'eslint:recommended',
9 | '@vue/eslint-config-typescript',
10 | '@vue/eslint-config-prettier/skip-formatting'
11 | ],
12 | parserOptions: {
13 | ecmaVersion: 'latest'
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | xknx configuration importer
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/views/HomeView.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-ssr
14 | coverage
15 | *.local
16 |
17 | /cypress/videos/
18 | /cypress/screenshots/
19 |
20 | # Editor directories and files
21 | .vscode/*
22 | !.vscode/extensions.json
23 | .idea
24 | *.suo
25 | *.ntvs*
26 | *.njsproj
27 | *.sln
28 | *.sw?
29 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url'
2 |
3 | import { defineConfig } from 'vite'
4 | import vue from '@vitejs/plugin-vue'
5 | import vueJsx from '@vitejs/plugin-vue-jsx'
6 |
7 | // https://vitejs.dev/config/
8 | export default defineConfig({
9 | plugins: [vue(), vueJsx()],
10 | base: '/xknx-configuration-importer/',
11 | resolve: {
12 | alias: {
13 | '@': fileURLToPath(new URL('./src', import.meta.url))
14 | }
15 | }
16 | })
17 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath } from 'node:url'
2 | import { mergeConfig } from 'vite'
3 | import { configDefaults, defineConfig } from 'vitest/config'
4 | import viteConfig from './vite.config'
5 |
6 | export default mergeConfig(
7 | viteConfig,
8 | defineConfig({
9 | test: {
10 | environment: 'jsdom',
11 | exclude: [...configDefaults.exclude, 'e2e/*'],
12 | root: fileURLToPath(new URL('./', import.meta.url))
13 | }
14 | })
15 | )
16 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from 'vue-router'
2 | import HomeView from '../views/HomeView.vue'
3 | import AboutView from '../views/AboutView.vue'
4 |
5 | const router = createRouter({
6 | history: createWebHistory('/xknx-configuration-importer/'),
7 | routes: [
8 | {
9 | path: '/',
10 | name: 'home',
11 | component: HomeView
12 | },
13 | {
14 | path: '/about',
15 | name: 'about',
16 | component: AboutView
17 | }
18 | ]
19 | })
20 |
21 | export default router
22 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | xknx configuration importer
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/views/AboutView.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | This project is created to convert a knxproj file created by ETS5 or ETS6 to a xKNX-yaml file. This uses the so called Functions in ETS to automaticly convert a group of groupaddresses to the correct group in xKNX.
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/assets/main.css:
--------------------------------------------------------------------------------
1 | @import './base.css';
2 |
3 | #app {
4 | max-width: 1280px;
5 | margin: 0 auto;
6 | padding: 2rem;
7 |
8 | font-weight: normal;
9 | }
10 |
11 | a {
12 | text-decoration: none;
13 | color: rgb(209, 111, 0);
14 | transition: 0.4s;
15 | }
16 |
17 | @media (hover: hover) {
18 | a:hover {
19 | background-color: hsla(34, 100%, 37%, 0.2);
20 | }
21 | }
22 |
23 | @media (min-width: 1024px) {
24 | body {
25 | display: flex;
26 | place-items: center;
27 | }
28 |
29 | #app {
30 | display: grid;
31 | grid-template-columns: 1fr 1fr;
32 | padding: 0 2rem;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | xknx-configuration-importer
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xknx-configuration-importer",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "run-p type-check build-only",
8 | "preview": "vite preview",
9 | "test:unit": "vitest",
10 | "build-only": "vite build",
11 | "type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
12 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
13 | "format": "prettier --write src/"
14 | },
15 | "dependencies": {
16 | "fast-xml-parser": "^4.1.3",
17 | "js-yaml": "^4.1.0",
18 | "jszip": "^3.10.1",
19 | "pinia": "^2.0.32",
20 | "sass": "^1.61.0",
21 | "vue": "^3.2.47",
22 | "vue-facing-decorator": "^2.1.19",
23 | "vue-router": "^4.1.6"
24 | },
25 | "devDependencies": {
26 | "@rushstack/eslint-patch": "^1.2.0",
27 | "@types/js-yaml": "^4.0.5",
28 | "@types/jsdom": "^21.1.0",
29 | "@types/node": "^18.14.2",
30 | "@vitejs/plugin-vue": "^4.0.0",
31 | "@vitejs/plugin-vue-jsx": "^3.0.0",
32 | "@vue/eslint-config-prettier": "^7.1.0",
33 | "@vue/eslint-config-typescript": "^11.0.2",
34 | "@vue/test-utils": "^2.3.0",
35 | "@vue/tsconfig": "^0.1.3",
36 | "eslint": "^8.34.0",
37 | "eslint-plugin-vue": "^9.9.0",
38 | "jsdom": "^21.1.0",
39 | "npm-run-all": "^4.1.5",
40 | "prettier": "^2.8.4",
41 | "typescript": "~4.8.4",
42 | "vite": "^4.1.4",
43 | "vitest": "^0.29.1",
44 | "vue-tsc": "^1.2.0"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
16 |
17 |
18 |
19 |
20 |
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xknx-configuration-importer
2 |
3 | This project is created to convert a knxproj file created by ETS5 or ETS6 to a xKNX-yaml file. This uses the so called `Functions` in ETS to automaticly convert a group of groupaddresses to the correct group in xKNX.
4 |
5 | ## Recommended IDE Setup
6 |
7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
8 |
9 | ## Type Support for `.vue` Imports in TS
10 |
11 | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
12 |
13 | If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
14 |
15 | 1. Disable the built-in TypeScript Extension
16 | 1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
17 | 2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
18 | 2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
19 |
20 | ## Customize configuration
21 |
22 | See [Vite Configuration Reference](https://vitejs.dev/config/).
23 |
24 | ## Project Setup
25 |
26 | ```sh
27 | npm install
28 | ```
29 |
30 | ### Compile and Hot-Reload for Development
31 |
32 | ```sh
33 | npm run dev
34 | ```
35 |
36 | ### Type-Check, Compile and Minify for Production
37 |
38 | ```sh
39 | npm run build
40 | ```
41 |
42 | ### Run Unit Tests with [Vitest](https://vitest.dev/)
43 |
44 | ```sh
45 | npm run test:unit
46 | ```
47 |
48 | ### Lint with [ESLint](https://eslint.org/)
49 |
50 | ```sh
51 | npm run lint
52 | ```
53 |
--------------------------------------------------------------------------------
/src/assets/base.css:
--------------------------------------------------------------------------------
1 | /* color palette from */
2 | :root {
3 | --vt-c-white: #ffffff;
4 | --vt-c-white-soft: #f8f8f8;
5 | --vt-c-white-mute: #f2f2f2;
6 |
7 | --vt-c-black: #181818;
8 | --vt-c-black-soft: #222222;
9 | --vt-c-black-mute: #282828;
10 |
11 | --vt-c-indigo: #2c3e50;
12 |
13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
17 |
18 | --vt-c-text-light-1: var(--vt-c-indigo);
19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
20 | --vt-c-text-dark-1: var(--vt-c-white);
21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
22 | }
23 |
24 | /* semantic color variables for this project */
25 | :root {
26 | --color-background: var(--vt-c-white);
27 | --color-background-soft: var(--vt-c-white-soft);
28 | --color-background-mute: var(--vt-c-white-mute);
29 |
30 | --color-border: var(--vt-c-divider-light-2);
31 | --color-border-hover: var(--vt-c-divider-light-1);
32 |
33 | --color-heading: var(--vt-c-text-light-1);
34 | --color-text: var(--vt-c-text-light-1);
35 |
36 | --section-gap: 160px;
37 | }
38 |
39 | @media (prefers-color-scheme: dark) {
40 | :root {
41 | --color-background: var(--vt-c-black);
42 | --color-background-soft: var(--vt-c-black-soft);
43 | --color-background-mute: var(--vt-c-black-mute);
44 |
45 | --color-border: var(--vt-c-divider-dark-2);
46 | --color-border-hover: var(--vt-c-divider-dark-1);
47 |
48 | --color-heading: var(--vt-c-text-dark-1);
49 | --color-text: var(--vt-c-text-dark-2);
50 | }
51 | }
52 |
53 | *,
54 | *::before,
55 | *::after {
56 | box-sizing: border-box;
57 | margin: 0;
58 | position: relative;
59 | font-weight: normal;
60 | }
61 |
62 | body {
63 | min-height: 100vh;
64 | color: var(--color-text);
65 | background: var(--color-background);
66 | transition: color 0.5s, background-color 0.5s;
67 | line-height: 1.6;
68 | font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
69 | Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
70 | font-size: 15px;
71 | text-rendering: optimizeLegibility;
72 | -webkit-font-smoothing: antialiased;
73 | -moz-osx-font-smoothing: grayscale;
74 | }
75 |
--------------------------------------------------------------------------------
/dist/assets/index-04e56ed8.css:
--------------------------------------------------------------------------------
1 | header[data-v-8cf9f3d9]{line-height:1.5;max-height:100vh}.logo[data-v-8cf9f3d9]{display:block;margin:0 auto 2rem}nav[data-v-8cf9f3d9]{width:100%;font-size:12px;text-align:center;margin-top:2rem}nav a.router-link-exact-active[data-v-8cf9f3d9]{color:var(--color-text)}nav a.router-link-exact-active[data-v-8cf9f3d9]:hover{background-color:transparent}nav a[data-v-8cf9f3d9]{display:inline-block;padding:0 1rem;border-left:1px solid var(--color-border)}nav a[data-v-8cf9f3d9]:first-of-type{border:0}@media (min-width: 1024px){header[data-v-8cf9f3d9]{display:flex;place-items:center;padding-right:calc(var(--section-gap) / 2)}.logo[data-v-8cf9f3d9]{margin:0 2rem 0 0}header .wrapper[data-v-8cf9f3d9]{display:flex;place-items:flex-start;flex-wrap:wrap}nav[data-v-8cf9f3d9]{text-align:left;margin-left:-1rem;font-size:1rem;padding:1rem 0;margin-top:1rem}}main[data-v-31b2d0d7]{padding:25px}.container[data-v-31b2d0d7]{display:flex;flex-direction:column;align-items:center}.container .info[data-v-31b2d0d7]{padding:10px}.container .info span[data-v-31b2d0d7]{color:orange;font-style:italic}.container .process[data-v-31b2d0d7],.container .buttons[data-v-31b2d0d7]{padding:10px}.container .process button[data-v-31b2d0d7],.container .process input[data-v-31b2d0d7],.container .buttons button[data-v-31b2d0d7],.container .buttons input[data-v-31b2d0d7]{border:1px solid transparent;padding:5px 10px;color:#d16f00;background:unset;transition:.4s;cursor:pointer}.container .process button[data-v-31b2d0d7]:hover,.container .process input[data-v-31b2d0d7]:hover,.container .buttons button[data-v-31b2d0d7]:hover,.container .buttons input[data-v-31b2d0d7]:hover{border:1px solid orange;color:#fff;background-color:#d16f0080;transition:.4s}.container .buttons[data-v-31b2d0d7]{width:100%;display:flex;flex-direction:row;justify-content:space-around}main[data-v-98c0d28b]{padding:25px}span[data-v-98c0d28b]{color:orange;font-style:italic}:root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}@media (prefers-color-scheme: dark){:root{--color-background: var(--vt-c-black);--color-background-soft: var(--vt-c-black-soft);--color-background-mute: var(--vt-c-black-mute);--color-border: var(--vt-c-divider-dark-2);--color-border-hover: var(--vt-c-divider-dark-1);--color-heading: var(--vt-c-text-dark-1);--color-text: var(--vt-c-text-dark-2)}}*,*:before,*:after{box-sizing:border-box;margin:0;position:relative;font-weight:400}body{min-height:100vh;color:var(--color-text);background:var(--color-background);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app{max-width:1280px;margin:0 auto;padding:2rem;font-weight:400}a{text-decoration:none;color:#d16f00;transition:.4s}@media (hover: hover){a:hover{background-color:#bd6b0033}}@media (min-width: 1024px){body{display:flex;place-items:center}#app{display:grid;grid-template-columns:1fr 1fr;padding:0 2rem}}
2 |
--------------------------------------------------------------------------------
/src/components/ConfigurationImporter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Select a ETS5 or ETS6 .knxproj file which uses Functions to convert it to a xKNX-yaml file.
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
339 |
340 |
341 |
--------------------------------------------------------------------------------