Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f52931f
added missing @Column annotation, added custom Directus endpoint
thanaParis Mar 23, 2024
2529c0c
Merge branch 'feature/admin-api' into feature/evse-connection-status
thanaParis Mar 23, 2024
d05a6c1
adding total true count to show how many stations are connected at a …
thanaParis Mar 24, 2024
2e8fd42
Merge branch 'rc-1.1.0' into feature/evse-connection-status
thanaParis Mar 25, 2024
30d90e7
setting up new preseeded db for release
thanaParis Mar 25, 2024
b9f197d
Forcing addition of dist/index.js for directus extension so that it c…
thanaParis Mar 25, 2024
2ff16ae
directus extension completed, bundled, and added to root
thanaParis Mar 27, 2024
2d7c15d
adding config.js to directus to provide more complex values to enviro…
thanaParis Mar 29, 2024
05daa49
making tsconfig for directus extension match the rest of the repository.
thanaParis Apr 2, 2024
c1c2d5e
Merge branch 'rc-1.1.0' into feature/station-connection-status
thanaParis Apr 2, 2024
28c4d44
moving files in order to rename top level folder to 'DirectusExtensions'
thanaParis Apr 2, 2024
e340c80
Merge branch 'rc-1.1.0' into feature/station-connection-status
thanaParis Apr 4, 2024
6eae968
fixing directus extension bundle to be built inside dockerfile
thanaParis Apr 4, 2024
f271246
fixing issue with building directus bundle in dockerfile, added healt…
thanaParis Apr 5, 2024
265b229
Update DirectusExtensions/charging-stations-bundle/src/display-true-c…
thanaParis Apr 5, 2024
c9ae76f
merged paths
thanaParis Apr 5, 2024
1f4c7a7
Merge branch 'feature/station-connection-status' of https://github.co…
thanaParis Apr 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 01_Data/src/layers/sequelize/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class DefaultSequelizeInstance {
storage: config.data.sequelize.storage,
models: [AdditionalInfo, Authorization, Boot, ChargingStation, Component,
ComponentVariable, Evse, EventData, IdToken, IdTokenInfo, Location, MeterValue, MessageInfo,
SecurityEvent, Transaction, TransactionEvent, Tariff, VariableAttribute,
SecurityEvent, Subscription, Transaction, TransactionEvent, Tariff, VariableAttribute,
VariableCharacteristics, VariableMonitoring, VariableMonitoringStatus, VariableStatus, Variable],
logging: (sql: string, timing?: number) => {
// TODO: Look into fixing that
Expand Down
54 changes: 54 additions & 0 deletions DirectusExtensions/charging-stations-bundle/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "directus-extension-charging-stations-bundle",
"description": "Directus extension bundle for CitrineOS to support charging stations",
"icon": "extension",
"version": "1.0.0",
"keywords": [
"directus",
"directus-extension",
"directus-extension-bundle"
],
"type": "module",
"files": [
"dist"
],
"directus:extension": {
"type": "bundle",
"path": {
"app": "dist/app.js",
"api": "dist/api.js"
},
"entries": [
{
"type": "display",
"name": "Present or True Count",
"source": "src/display-true-count/index.ts"
},
{
"type": "endpoint",
"name": "Charging Stations endpoints",
"source": "src/endpoints-charging-stations/index.ts"
},
{
"type": "hook",
"name": "On Create Charging Station",
"source": "src/hook-on-create-charging-station/index.ts"
}
],
"host": "^10.10.0"
},
"scripts": {
"build": "npx directus-extension build",
"dev": "npx directus-extension build -w --no-minify",
"link": "npx directus-extension link",
"add": "npx directus-extension add"
},
"devDependencies": {
"@types/node": "^20.11.30",
"typescript": "^5.4.3"
},
"dependencies": {
"@directus/extensions-sdk": "^11.0.1",
"@directus/types": "^11.0.7"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<span>{{ calculatedValue }}{{ totalPrefix }}{{ total }}{{ suffix }}</span>
</template>

<script lang="ts">
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0
Comment thread
thanaParis marked this conversation as resolved.

import { defineComponent, ref } from 'vue';

export default defineComponent({
props: {
value: {
type: Array<object | string>,
default: null,
},
column: {
type: String,
default: null,
},
showTotal: {
type: Boolean,
default: false,
},
totalPrefix: {
type: String,
default: null,
},
suffix: {
type: String,
default: null,
},
},
setup(props) {
const calculatedValue = ref(0);
const total = props.showTotal ? props.value.length : null;

props.value.forEach(item => {
const columns = props.column.split('.');

columns.forEach(col => {
item = item[col];
});

if (item && item !== 'false') {
calculatedValue.value += 1;
}
});


return { calculatedValue, total };
},
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0

import { defineDisplay, useStores } from '@directus/extensions-sdk';
import DisplayComponent from './display.vue';
import { DeepPartial, Field, FieldMeta } from '@directus/types';

export default defineDisplay({
id: 'directus-display-true-count',
name: 'Count Present or True',
icon: '123',
description: 'Count present or true rows in a column',
component: DisplayComponent,
options: ({ editing, relations }) => {
const relatedCollection =
relations.o2m?.meta?.junction_field != null ? relations.m2o?.related_collection : relations.o2m?.collection;

const junction_table = relations.o2m?.meta?.junction_field != null ? relations.o2m?.collection : null;
const { useFieldsStore } = useStores();
const fieldsStore = useFieldsStore();

let fieldSelection: DeepPartial<FieldMeta>;
if (editing === '+') {
fieldSelection = {
interface: 'presentation-notice',
options: {
text: 'Please complete the field before attempting to configure the display.',
},
width: 'full',
};
} else {
const fields: Field[] = fieldsStore.getFieldsForCollection(relatedCollection);
const field_choices: object[] = [];

// console.log("fields", fields);

fields.forEach((field) => {
// console.log(field);
field_choices.push({
text: field.field,
value: junction_table ? `${relations.o2m?.meta?.junction_field}.${field.field}` : field.field,
});
});

fieldSelection = {
interface: 'select-dropdown',
options: {
choices: field_choices,
},
width: 'full',
};
}

return [
{
field: 'column',
name: 'Choose a column',
meta: fieldSelection,
},
{
field: 'showTotal',
type: 'boolean',
name: 'Show Total',
meta: {
interface: 'boolean',
options: {
label: 'Show Total',
},
width: 'half',
},
},
{
field: 'totalPrefix',
type: 'string',
name: 'Total Prefix',
meta: {
interface: 'input',
options: {
font: 'monospace',
},
width: 'half',
hidden: true,
conditions: [
{
name: 'showTotalTrue',
rule: {
"showTotal": {
"_eq": true
}
},
hidden: false
}
]
},
},
{
field: 'suffix',
type: 'string',
name: 'Suffix',
meta: {
interface: 'input',
options: {
font: 'monospace',
},
width: 'half',
},
},
];
},
types: ['alias', 'string', 'uuid', 'integer', 'bigInteger', 'json'],
localTypes: ['m2m', 'm2o', 'o2m', 'translations', 'm2a', 'file', 'files'],
fields: (options) => {
return [options.column];
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0

import { defineEndpoint } from '@directus/extensions-sdk';

export default defineEndpoint({
id: 'charging-stations',
handler: (router, { database }) => {
router.post('/update-station-status', async (req, res) => {
Comment thread
thanaParis marked this conversation as resolved.
try {
console.log("update-station-status request received: " + JSON.stringify(req.body));
const { stationId, event } = req.body;
let isOnline = false;

// Determine the status based on the event type
if (event === 'connected') {
isOnline = true;
} else if (event === 'closed') {
isOnline = false;
} else {
// If the event type is neither 'connected' nor 'closed', return an error
return res.status(400).json({ message: 'Invalid event type, expecting only "connected" or "closed"' });
}

// Update the `isOnline` field in the `ChargingStation` collection for the specified stationId
await database('ChargingStations')
.where({ id: stationId })
.update({ isOnline });

return res.status(200).json({ message: 'ChargingStation status updated successfully' });
} catch (error) {
console.error('Error updating ChargingStation status:', error);
return res.status(500).json({ message: 'Internal server error' });
}
});
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0

import { defineHook } from '@directus/extensions-sdk';

export default defineHook(({ action }, { env }) => {

action('ChargingStations.items.create', (input) => {
console.log("Subscribing " + input.key + " to connect and close events");

const stationId = input.key;
const subscriptionUrl = `${env.CITRINEOS_URL}${env.CITRINEOS_SUBSCRIPTION_API_PATH}`;
const updateStationStatusUrl = `${env.DIRECTUS_URL}${env.DIRECTUS_CHARGING_STATION_UPDATE_STATUS_PATH}`;
Comment thread
thanaParis marked this conversation as resolved.
const requestBody = {
stationId: stationId,
onConnect: true,
onClose: true,
url: updateStationStatusUrl
}

console.log("Subscribing to " + subscriptionUrl + " with request body " + JSON.stringify(requestBody));
fetch(subscriptionUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
}).then((response) => {
console.log('Response: ', response);
}).catch((error) => {
console.log('Error: ', error);
});
});
});
12 changes: 12 additions & 0 deletions DirectusExtensions/charging-stations-bundle/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.build.json",
"include": [
"src/**/*.ts",
"src/**/*.json"
],
"compilerOptions": {
"outDir": "./dist/",
"composite": true,
"rootDir": "./src"
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 16 additions & 0 deletions Server/directus-env-config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0

module.exports = function (env) {
const config = {
// API Paths
CITRINEOS_SUBSCRIPTION_API_PATH: '/data/ocpprouter/subscription',
DIRECTUS_CHARGING_STATION_UPDATE_STATUS_PATH: '/charging-stations/update-station-status',
// Environment-specific urls
CITRINEOS_URL: "http://citrine:8080",
DIRECTUS_URL: "http://directus:8055"
}

return config;
}
8 changes: 8 additions & 0 deletions Server/directus.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM directus/directus:10.10.5
USER root
COPY tsconfig.build.json /directus
COPY DirectusExtensions/charging-stations-bundle/tsconfig.json /directus/extensions/directus-extension-charging-stations-bundle/tsconfig.json
COPY DirectusExtensions/charging-stations-bundle/package.json /directus/extensions/directus-extension-charging-stations-bundle/package.json
COPY DirectusExtensions/charging-stations-bundle/src /directus/extensions/directus-extension-charging-stations-bundle/src
RUN npm install --prefix /directus/extensions/directus-extension-charging-stations-bundle && npm run build --prefix /directus/extensions/directus-extension-charging-stations-bundle
USER node
Loading