Initial Windows commit with proper line endings
This commit is contained in:
commit
cc4f3c18c0
26
.env
Normal file
26
.env
Normal file
@ -0,0 +1,26 @@
|
||||
DB_NAME=wellnuo
|
||||
DB_USER=well_app
|
||||
DB_PASSWORD=well_app_2024
|
||||
DB_HOST=192.168.68.70
|
||||
DB_PORT=5432
|
||||
MINIO_ACCESS_KEY=well_pipe
|
||||
MINIO_SECRET_KEY=WellNuo_2024
|
||||
MINIO_HOST=192.168.68.70
|
||||
MINIO_PORT=9000
|
||||
DAILY_MAPS_BUCKET_NAME=daily-maps
|
||||
JWT_SECRET=Well_202502110501
|
||||
OPENAI_API_KEY=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
|
||||
OPENAI_API_MODEL_ENGINE=gpt-3.5-turbo
|
||||
|
||||
REDIS_PORT="6379"
|
||||
|
||||
TELNYX_VOICE_URL=https://api.telnyx.com/v2/calls
|
||||
#TELNYX_WEBHOOK_URL_VOICE=https://eluxnetworks.net/telnyx-webhook
|
||||
TELNYX_WEBHOOK_URL_VOICE=http://eluxnetworks.net:1998/function/well-api/api
|
||||
TELNYX_API_KEY=KEY0196087A75998434A30FA637CE4FDAFF_ZljGj9KBSAQL0zXx4Sb5eW
|
||||
TELNYX_SENDER_ID="+16505820706"
|
||||
TELNYX_SENDER_ID_ALPHA="Wellnuo"
|
||||
TELNYX_CONNECTION_ID="YOUR_TELNYX_CALL_CONTROL_APP_CONNECTION_ID" # Get from Telnyx Portal
|
||||
TELNYX_MESSAGING_PROFILE_ID="40019616-d6e8-4f82-bdd0-ddeb0a25d5ff"
|
||||
TELNYX_CONNECTION_ID_VOICE="2671409623596009055"
|
||||
TELNYX_API_BASE_URL=https://api.telnyx.com/v2
|
||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
* text=auto eol=lf
|
||||
*.sh text eol=lf
|
||||
*.py text eol=lf
|
||||
0
.gitignore
vendored
Normal file
0
.gitignore
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python Debugger: Current File",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
43
Dockerfile
Normal file
43
Dockerfile
Normal file
@ -0,0 +1,43 @@
|
||||
FROM python:3.9-slim
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
python3-dev \
|
||||
libgl1-mesa-glx \
|
||||
libglib2.0-0 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install Python dependencies
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy and build the C extension
|
||||
COPY simplified_filter_short_groups.c /app/
|
||||
COPY direct_setup.py /app/
|
||||
RUN python direct_setup.py install
|
||||
|
||||
# Copy the wrapper module
|
||||
COPY filter_short_groups_wrapper.py /app/
|
||||
|
||||
# Copy application code
|
||||
COPY well-api.py .
|
||||
|
||||
# Create directory and copy data files
|
||||
RUN mkdir -p /home/app/well_web_storage
|
||||
COPY well_web_files/* /home/app/well_web_storage/
|
||||
RUN mkdir -p /app/fonts
|
||||
COPY fonts/* /app/fonts/
|
||||
|
||||
# Environment variables for gunicorn
|
||||
ENV GUNICORN_CMD_ARGS="--log-level info --timeout 60"
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Expose the port for the API
|
||||
EXPOSE 8080
|
||||
|
||||
# Run with gunicorn
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "well-api:app"]
|
||||
BIN
__pycache__/well-api._core_filter_loop_numba-11210.py312.1.nbc
Normal file
BIN
__pycache__/well-api._core_filter_loop_numba-11210.py312.1.nbc
Normal file
Binary file not shown.
BIN
__pycache__/well-api._core_filter_loop_numba-11210.py312.nbi
Normal file
BIN
__pycache__/well-api._core_filter_loop_numba-11210.py312.nbi
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
config-3.py
Normal file
1
config-3.py
Normal file
@ -0,0 +1 @@
|
||||
|
||||
15
direct_setup.py
Normal file
15
direct_setup.py
Normal file
@ -0,0 +1,15 @@
|
||||
from setuptools import setup, Extension
|
||||
|
||||
# Direct extension definition with no NumPy dependencies
|
||||
extension = Extension(
|
||||
'filter_short_groups',
|
||||
sources=['simplified_filter_short_groups.c'],
|
||||
extra_compile_args=['-O3'], # Basic optimization
|
||||
)
|
||||
|
||||
setup(
|
||||
name='filter_short_groups',
|
||||
version='1.0',
|
||||
description='Optimized C implementation of filter_short_groups',
|
||||
ext_modules=[extension],
|
||||
)
|
||||
342
filter_short_groups.c
Normal file
342
filter_short_groups.c
Normal file
@ -0,0 +1,342 @@
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// We don't actually need the NumPy C API for our implementation
|
||||
// since we're working directly with Python lists
|
||||
|
||||
// Struct to represent a run of consecutive values
|
||||
typedef struct {
|
||||
int start;
|
||||
int end;
|
||||
double sign;
|
||||
int length;
|
||||
} Run;
|
||||
|
||||
// Compare function for sorting runs by length, then by start index
|
||||
static int compare_runs(const void *a, const void *b) {
|
||||
const Run *run_a = (const Run *)a;
|
||||
const Run *run_b = (const Run *)b;
|
||||
|
||||
if (run_a->length != run_b->length) {
|
||||
return run_a->length - run_b->length;
|
||||
}
|
||||
return run_a->start - run_b->start;
|
||||
}
|
||||
|
||||
// Function to compute the sign of a double value (-1, 0, 1)
|
||||
static double sign(double x) {
|
||||
if (x > 0) return 1.0;
|
||||
if (x < 0) return -1.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Core implementation of filter_short_groups
|
||||
static PyObject* filter_short_groups_c(PyObject *self, PyObject *args) {
|
||||
PyObject *presence_list_obj;
|
||||
int filter_size;
|
||||
char *device_id;
|
||||
char *dates_str;
|
||||
|
||||
// Parse Python arguments
|
||||
if (!PyArg_ParseTuple(args, "Oiss", &presence_list_obj, &filter_size, &device_id, &dates_str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Start timing
|
||||
clock_t start_time = clock();
|
||||
|
||||
// Convert Python list to C array
|
||||
Py_ssize_t n = PyObject_Length(presence_list_obj);
|
||||
if (n < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid input list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Early exit condition
|
||||
if (n == 0 || filter_size <= 1) {
|
||||
Py_INCREF(presence_list_obj);
|
||||
printf("C implementation: Early exit/no processing time: %.6fs\n",
|
||||
((double)(clock() - start_time) / CLOCKS_PER_SEC));
|
||||
return presence_list_obj;
|
||||
}
|
||||
|
||||
// Allocate memory for our working array
|
||||
double *result = (double *)malloc(n * sizeof(double));
|
||||
if (!result) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy data from Python list to C array
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyObject *item = PySequence_GetItem(presence_list_obj, i);
|
||||
if (!item) {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
result[i] = PyFloat_AsDouble(item);
|
||||
Py_DECREF(item);
|
||||
if (PyErr_Occurred()) {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for signs array
|
||||
double *signs = (double *)malloc(n * sizeof(double));
|
||||
if (!signs) {
|
||||
free(result);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for signs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for change indices
|
||||
int *change_indices = (int *)malloc(n * sizeof(int));
|
||||
if (!change_indices) {
|
||||
free(result);
|
||||
free(signs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for change indices");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for boundaries
|
||||
int *boundaries = (int *)malloc((n + 1) * sizeof(int));
|
||||
if (!boundaries) {
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for boundaries");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for runs
|
||||
Run *runs = (Run *)malloc(n * sizeof(Run));
|
||||
if (!runs) {
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for runs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Simple cycle detection with hashset-like approach
|
||||
// We'll use a dynamically-sized array of states for simplicity
|
||||
int max_states = 100; // Initial capacity, will grow as needed
|
||||
int states_count = 0;
|
||||
double **previous_states = (double **)malloc(max_states * sizeof(double *));
|
||||
if (!previous_states) {
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for previous states");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cycle_detected = false;
|
||||
|
||||
// Main processing loop
|
||||
while (!cycle_detected) {
|
||||
// Check for cycle by comparing with previous states
|
||||
bool found_match = false;
|
||||
for (int s = 0; s < states_count; s++) {
|
||||
if (memcmp(previous_states[s], result, n * sizeof(double)) == 0) {
|
||||
found_match = true;
|
||||
cycle_detected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_match) {
|
||||
// Store current state
|
||||
if (states_count >= max_states) {
|
||||
// Grow the states array
|
||||
max_states *= 2;
|
||||
double **new_states = (double **)realloc(previous_states, max_states * sizeof(double *));
|
||||
if (!new_states) {
|
||||
// Handle memory allocation failure
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to reallocate memory for previous states");
|
||||
return NULL;
|
||||
}
|
||||
previous_states = new_states;
|
||||
}
|
||||
|
||||
// Allocate memory for the new state
|
||||
previous_states[states_count] = (double *)malloc(n * sizeof(double));
|
||||
if (!previous_states[states_count]) {
|
||||
// Handle memory allocation failure
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for new state");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy the current result to the new state
|
||||
memcpy(previous_states[states_count], result, n * sizeof(double));
|
||||
states_count++;
|
||||
|
||||
// 1. Calculate signs
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
signs[i] = sign(result[i]);
|
||||
}
|
||||
|
||||
// 2. Find indices where sign changes
|
||||
int change_count = 0;
|
||||
for (Py_ssize_t i = 1; i < n; i++) {
|
||||
if (signs[i] != signs[i-1]) {
|
||||
change_indices[change_count++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Define boundaries of consecutive runs
|
||||
boundaries[0] = 0;
|
||||
for (int i = 0; i < change_count; i++) {
|
||||
boundaries[i+1] = change_indices[i];
|
||||
}
|
||||
boundaries[change_count+1] = n;
|
||||
int boundaries_count = change_count + 2;
|
||||
|
||||
// If there's only one segment, no further processing needed
|
||||
if (boundaries_count <= 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 4. Extract run properties
|
||||
int run_count = 0;
|
||||
for (int i = 0; i < boundaries_count - 1; i++) {
|
||||
int start = boundaries[i];
|
||||
int end = boundaries[i+1];
|
||||
int length = end - start;
|
||||
double run_sign = signs[start];
|
||||
|
||||
// 5. Identify short runs
|
||||
if (length > 0 && length < filter_size) {
|
||||
runs[run_count].start = start;
|
||||
runs[run_count].end = end;
|
||||
runs[run_count].sign = run_sign;
|
||||
runs[run_count].length = length;
|
||||
run_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Check if any modifiable short runs were found
|
||||
if (run_count == 0) {
|
||||
// No short runs found, the list is stable
|
||||
break;
|
||||
}
|
||||
|
||||
// 7. Sort the short runs: shortest first, then by start index
|
||||
qsort(runs, run_count, sizeof(Run), compare_runs);
|
||||
|
||||
// 8. Process the first (shortest) identified run
|
||||
Run run_to_process = runs[0];
|
||||
int start = run_to_process.start;
|
||||
int end = run_to_process.end;
|
||||
double run_sign = run_to_process.sign;
|
||||
|
||||
// Determine replacement value
|
||||
double replacement_value = (run_sign == 0) ? 1.0 : 0.0;
|
||||
|
||||
// 9. Apply the replacement
|
||||
for (int i = start; i < end; i++) {
|
||||
result[i] = replacement_value;
|
||||
}
|
||||
// Loop continues for the next pass
|
||||
}
|
||||
}
|
||||
|
||||
// Create Python list for the result
|
||||
PyObject *result_list = PyList_New(n);
|
||||
if (!result_list) {
|
||||
// Cleanup and return
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fill result list
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyObject *item = PyFloat_FromDouble(result[i]);
|
||||
if (!item) {
|
||||
Py_DECREF(result_list);
|
||||
// Cleanup and return
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
return NULL;
|
||||
}
|
||||
PyList_SET_ITEM(result_list, i, item);
|
||||
}
|
||||
|
||||
// Print timing information
|
||||
printf("filter_short_groups_c time: %.6fs\n", ((double)(clock() - start_time) / CLOCKS_PER_SEC));
|
||||
|
||||
// Cleanup
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
|
||||
return result_list;
|
||||
}
|
||||
|
||||
// Method definitions
|
||||
static PyMethodDef FilterShortGroupsMethods[] = {
|
||||
{"filter_short_groups_c", filter_short_groups_c, METH_VARARGS,
|
||||
"Optimized C version to remove groups of consecutive zeros or non-zeros shorter than filter_size."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
// Module definition
|
||||
static struct PyModuleDef filter_short_groups_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"filter_short_groups",
|
||||
"A module that provides optimized filter_short_groups function",
|
||||
-1,
|
||||
FilterShortGroupsMethods
|
||||
};
|
||||
|
||||
// Module initialization
|
||||
PyMODINIT_FUNC PyInit_filter_short_groups(void) {
|
||||
return PyModule_Create(&filter_short_groups_module);
|
||||
}
|
||||
BIN
filter_short_groups.cpython-312-x86_64-linux-gnu.so
Normal file
BIN
filter_short_groups.cpython-312-x86_64-linux-gnu.so
Normal file
Binary file not shown.
5
filter_short_groups.egg-info/PKG-INFO
Normal file
5
filter_short_groups.egg-info/PKG-INFO
Normal file
@ -0,0 +1,5 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: filter_short_groups
|
||||
Version: 1.0
|
||||
Summary: Optimized C implementation of filter_short_groups
|
||||
Dynamic: summary
|
||||
7
filter_short_groups.egg-info/SOURCES.txt
Normal file
7
filter_short_groups.egg-info/SOURCES.txt
Normal file
@ -0,0 +1,7 @@
|
||||
direct_setup.py
|
||||
setup.py
|
||||
simplified_filter_short_groups.c
|
||||
filter_short_groups.egg-info/PKG-INFO
|
||||
filter_short_groups.egg-info/SOURCES.txt
|
||||
filter_short_groups.egg-info/dependency_links.txt
|
||||
filter_short_groups.egg-info/top_level.txt
|
||||
1
filter_short_groups.egg-info/dependency_links.txt
Normal file
1
filter_short_groups.egg-info/dependency_links.txt
Normal file
@ -0,0 +1 @@
|
||||
|
||||
1
filter_short_groups.egg-info/top_level.txt
Normal file
1
filter_short_groups.egg-info/top_level.txt
Normal file
@ -0,0 +1 @@
|
||||
filter_short_groups
|
||||
102
filter_short_groups_wrapper.py
Normal file
102
filter_short_groups_wrapper.py
Normal file
@ -0,0 +1,102 @@
|
||||
"""
|
||||
Wrapper module for filter_short_groups implementations.
|
||||
This provides a consistent interface regardless of which implementation is available.
|
||||
"""
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
# Try to import the C implementation first
|
||||
try:
|
||||
from filter_short_groups import filter_short_groups_c
|
||||
USE_C_IMPLEMENTATION = True
|
||||
print("Using optimized C implementation of filter_short_groups")
|
||||
except ImportError:
|
||||
USE_C_IMPLEMENTATION = False
|
||||
print("C implementation not available, falling back to NumPy implementation")
|
||||
|
||||
def filter_short_groups_numpy(presence_list, filter_size, device_id, dates_str):
|
||||
"""
|
||||
Original NumPy implementation, kept for fallback and comparison.
|
||||
"""
|
||||
# Start timer for benchmarking
|
||||
st = time.time()
|
||||
|
||||
if not presence_list or filter_size <= 1:
|
||||
print(f"NumPy Optimized: Early exit/no processing time: {time.time() - st:.6f}s")
|
||||
return presence_list[:] if isinstance(presence_list, list) else list(presence_list)
|
||||
|
||||
result = np.array(presence_list, dtype=float)
|
||||
n = len(result)
|
||||
|
||||
previous_states = set()
|
||||
|
||||
while True:
|
||||
# Cycle detection
|
||||
current_state_tuple = tuple(result)
|
||||
if current_state_tuple in previous_states:
|
||||
print("NumPy Optimized: Cycle detected, breaking.")
|
||||
break
|
||||
previous_states.add(current_state_tuple)
|
||||
|
||||
# 1. Calculate the sign of each element (-1, 0, 1)
|
||||
signs = np.sign(result)
|
||||
|
||||
# 2. Find indices where the sign changes
|
||||
change_indices = np.where(np.diff(signs) != 0)[0] + 1
|
||||
|
||||
# 3. Define the boundaries of all consecutive runs
|
||||
boundaries = np.concatenate(([0], change_indices, [n]))
|
||||
|
||||
# If there's only one segment, no further processing is needed.
|
||||
if len(boundaries) <= 2:
|
||||
break
|
||||
|
||||
# 4. Vectorized extraction of run properties
|
||||
run_starts = boundaries[:-1]
|
||||
run_ends = boundaries[1:]
|
||||
run_lengths = run_ends - run_starts
|
||||
run_signs = signs[run_starts]
|
||||
|
||||
# 5. Identify short runs and collect their properties
|
||||
short_runs_to_process = []
|
||||
for i in range(len(run_starts)):
|
||||
if run_lengths[i] > 0 and run_lengths[i] < filter_size:
|
||||
short_runs_to_process.append({
|
||||
'start': run_starts[i],
|
||||
'end': run_ends[i],
|
||||
'sign': run_signs[i],
|
||||
'length': run_lengths[i]
|
||||
})
|
||||
|
||||
# 6. Check if any modifiable short runs were found
|
||||
if not short_runs_to_process:
|
||||
break
|
||||
|
||||
# 7. Sort the short runs: shortest first, then by start index for determinism
|
||||
short_runs_to_process.sort(key=lambda r: (r['length'], r['start']))
|
||||
|
||||
# 8. Process ONLY the *first* (shortest) identified run in this pass
|
||||
run_to_process = short_runs_to_process[0]
|
||||
start = run_to_process['start']
|
||||
end = run_to_process['end']
|
||||
run_sign = run_to_process['sign']
|
||||
|
||||
# Determine the replacement value
|
||||
replacement_value = 1.0 if run_sign == 0 else 0.0
|
||||
|
||||
# 9. Apply the replacement
|
||||
result[start:end] = replacement_value
|
||||
|
||||
# End timer and print
|
||||
print(f"filter_short_groups_numpy time: {time.time() - st:.6f}s")
|
||||
|
||||
return result.tolist()
|
||||
|
||||
def filter_short_groups(presence_list, filter_size, device_id, dates_str):
|
||||
"""
|
||||
Main entry point that automatically selects the best available implementation.
|
||||
"""
|
||||
if USE_C_IMPLEMENTATION:
|
||||
return filter_short_groups_c(presence_list, filter_size, device_id, dates_str)
|
||||
else:
|
||||
return filter_short_groups_numpy(presence_list, filter_size, device_id, dates_str)
|
||||
93
fonts/OFL.txt
Normal file
93
fonts/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
fonts/Poppins-Black.ttf
Normal file
BIN
fonts/Poppins-Black.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-BlackItalic.ttf
Normal file
BIN
fonts/Poppins-BlackItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-Bold.ttf
Normal file
BIN
fonts/Poppins-Bold.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-BoldItalic.ttf
Normal file
BIN
fonts/Poppins-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-ExtraBold.ttf
Normal file
BIN
fonts/Poppins-ExtraBold.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-ExtraBoldItalic.ttf
Normal file
BIN
fonts/Poppins-ExtraBoldItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-ExtraLight.ttf
Normal file
BIN
fonts/Poppins-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-ExtraLightItalic.ttf
Normal file
BIN
fonts/Poppins-ExtraLightItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-Italic.ttf
Normal file
BIN
fonts/Poppins-Italic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-Light.ttf
Normal file
BIN
fonts/Poppins-Light.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-LightItalic.ttf
Normal file
BIN
fonts/Poppins-LightItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-Medium.ttf
Normal file
BIN
fonts/Poppins-Medium.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-MediumItalic.ttf
Normal file
BIN
fonts/Poppins-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-Regular.ttf
Normal file
BIN
fonts/Poppins-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-SemiBold.ttf
Normal file
BIN
fonts/Poppins-SemiBold.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-SemiBoldItalic.ttf
Normal file
BIN
fonts/Poppins-SemiBoldItalic.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-Thin.ttf
Normal file
BIN
fonts/Poppins-Thin.ttf
Normal file
Binary file not shown.
BIN
fonts/Poppins-ThinItalic.ttf
Normal file
BIN
fonts/Poppins-ThinItalic.ttf
Normal file
Binary file not shown.
18
requirements.txt
Normal file
18
requirements.txt
Normal file
@ -0,0 +1,18 @@
|
||||
python-dotenv==1.0.0
|
||||
minio==7.1.15
|
||||
PyJWT==2.8.0
|
||||
psycopg2-binary==2.9.9
|
||||
pytz==2023.3.post1
|
||||
paho-mqtt>=1.6.1
|
||||
falcon==3.1.1
|
||||
gunicorn==21.2.0
|
||||
pillow
|
||||
numpy
|
||||
opencv-python
|
||||
scikit-learn
|
||||
openai
|
||||
pandas
|
||||
matplotlib
|
||||
redis
|
||||
requests
|
||||
|
||||
230
sample-alert.py
Normal file
230
sample-alert.py
Normal file
@ -0,0 +1,230 @@
|
||||
import os
|
||||
import redis
|
||||
import psycopg2
|
||||
from dotenv import load_dotenv
|
||||
import ast
|
||||
import time
|
||||
|
||||
load_dotenv()
|
||||
|
||||
DB_NAME = os.getenv('DB_NAME')
|
||||
DB_USER = os.getenv('DB_USER')
|
||||
DB_PASSWORD = os.getenv('DB_PASSWORD')
|
||||
DB_HOST = os.getenv('DB_HOST')
|
||||
DB_PORT = os.getenv('DB_PORT')
|
||||
|
||||
# Connect to Redis (assuming it's running on localhost with default port)
|
||||
r = redis.Redis(host='localhost', port=6379, db=0)
|
||||
|
||||
def GetRedisString(key_name):
|
||||
try:
|
||||
result = r.get(key_name).decode('utf-8')
|
||||
except:
|
||||
result = None
|
||||
return result
|
||||
|
||||
def GetRedisInt(key_name):
|
||||
try:
|
||||
result = int(r.get(key_name).decode('utf-8'))
|
||||
except:
|
||||
result = None
|
||||
return result
|
||||
|
||||
def GetRedisFloat(key_name):
|
||||
try:
|
||||
result = float(r.get(key_name).decode('utf-8'))
|
||||
except:
|
||||
result = None
|
||||
|
||||
return result
|
||||
|
||||
value = GetRedisFloat('lastseen_510')
|
||||
print(value)
|
||||
|
||||
def get_db_connection():
|
||||
return psycopg2.connect(dbname=DB_NAME, user=DB_USER, password=DB_PASSWORD, host=DB_HOST, port=DB_PORT)
|
||||
|
||||
def GetLastPointQuery(device_id, field_name, threshold_value):
|
||||
"""
|
||||
Generate a SQL query to find the last point in radar_readings where the specified field
|
||||
meets the threshold condition.
|
||||
|
||||
Parameters:
|
||||
device_id (int): The device ID to filter by
|
||||
field_name (str): The field to check, e.g., "s2_max", "s28_min", etc.
|
||||
threshold_value (float): The threshold value to compare against
|
||||
|
||||
Returns:
|
||||
str: SQL query string
|
||||
"""
|
||||
# Parse the field name to get base field and operation
|
||||
parts = field_name.split('_')
|
||||
base_field = parts[0]
|
||||
operation = parts[1] if len(parts) > 1 else None
|
||||
|
||||
# Define the field expression based on base_field
|
||||
if base_field == 's28':
|
||||
field_expr = "(s2+s3+s4+s5+s6+s7+s8)/7"
|
||||
elif base_field == 'm08':
|
||||
field_expr = "(m0+m1+m2+m3+m4+m5+m6+m7+m8)/9"
|
||||
else:
|
||||
field_expr = base_field
|
||||
|
||||
# Define comparison operator based on operation
|
||||
operator = ">" if operation == "max" else "<"
|
||||
|
||||
# Generate the SQL query
|
||||
query = f"""
|
||||
SELECT "time" AS point_time, {field_expr} AS point_value FROM radar_readings WHERE device_id = {device_id}
|
||||
AND {field_expr} {operator} {threshold_value} ORDER BY "time" DESC LIMIT 1;
|
||||
"""
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def GetLastDetected(device_id, field_name, threshold_value):
|
||||
# Example usage:
|
||||
|
||||
query = GetLastPointQuery(device_id, field_name, threshold_value)
|
||||
print(query)
|
||||
last_detected = None
|
||||
with get_db_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(query)
|
||||
last_detected = cur.fetchone()[0].timestamp()
|
||||
|
||||
return last_detected
|
||||
|
||||
def UpdateLastSeen(new_message_dict):
|
||||
print(new_message_dict)
|
||||
|
||||
device_id_s = str(new_message_dict["device_id"])
|
||||
|
||||
# matches code in well-api
|
||||
radar_threshold_signal = "s3_max"
|
||||
radar_threshold_value = 10
|
||||
|
||||
threshold_details = GetRedisString("radar_threshold" + device_id_s)
|
||||
try:
|
||||
radar_threshold_list = ast.literal_eval(threshold_details)
|
||||
radar_threshold_signal = radar_threshold_list[0]
|
||||
radar_threshold_value = radar_threshold_list[1]
|
||||
except:
|
||||
# key not found so read from DB, and store to key
|
||||
sql = f"""
|
||||
SELECT "radar_threshold" AS threshold FROM devices WHERE device_id = {device_id_s};
|
||||
"""
|
||||
|
||||
with get_db_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql)
|
||||
threshold_details = cur.fetchone()[0] #cur.fetchall()#
|
||||
print(threshold_details)
|
||||
radar_threshold_signal = "s3_max"
|
||||
radar_threshold_value = 10
|
||||
|
||||
if threshold_details != None:
|
||||
|
||||
threshold_details_list = ast.literal_eval(threshold_details)
|
||||
radar_threshold_signal = threshold_details_list[0]
|
||||
radar_threshold_value = threshold_details_list[1]
|
||||
|
||||
r.set('radar_threshold'+device_id_s, str([radar_threshold_signal, radar_threshold_value]))
|
||||
|
||||
# lets determine if presence is detected
|
||||
component = radar_threshold_signal.split("_")[0]
|
||||
radar_val = 0
|
||||
if component == "s28":
|
||||
radar_val = sum(new_message_dict['radar'][1][3:9]) / new_message_dict['radar'][1][0]
|
||||
elif component[0] == "s":
|
||||
component_index = ast.literal_eval(component[1])
|
||||
radar_val = new_message_dict['radar'][1][1 + component_index] / new_message_dict['radar'][1][0]
|
||||
elif component[0] == "m":
|
||||
component_index = ast.literal_eval(component[1])
|
||||
radar_val = new_message_dict['radar'][0][5 + component_index] / new_message_dict['radar'][0][0]
|
||||
|
||||
if radar_val > radar_threshold_value: #seen now
|
||||
r.set('lastseen_'+device_id_s, new_message_dict['time'])
|
||||
|
||||
else: #not seen now, but lets determine when he was and add the key
|
||||
last_seen = GetRedisFloat('lastseen_'+device_id_s)
|
||||
if last_seen == None:
|
||||
last_seen = GetLastDetected(device_id_s, radar_threshold_signal, radar_threshold_value)
|
||||
r.set('lastseen_'+device_id_s, last_seen)
|
||||
|
||||
|
||||
new_message_dict = {'time': 1743554317.579559, 'device_id': 499, 'radar': [[100, 100, 0, 0, 0, 2226, 2654, 425, 523, 445, 340, 436, 339, 548], [100, 0, 0, 706, 657, 547, 570, 553, 509, 499]]}
|
||||
|
||||
st = time.time()
|
||||
UpdateLastSeen(new_message_dict)
|
||||
print(time.time()-st)
|
||||
|
||||
if False:
|
||||
# Simple key-value
|
||||
|
||||
value = r.get('simple_key')
|
||||
print(f"Simple key value: {value.decode('utf-8')}")
|
||||
|
||||
# WRITING DATA TO REDIS
|
||||
|
||||
# Simple key-value
|
||||
r.set('simple_key', 'Hello, Redis!')
|
||||
|
||||
# Setting expiration (TTL) in seconds
|
||||
r.setex('expiring_key', 60, 'This will expire in 60 seconds')
|
||||
|
||||
# Working with numbers
|
||||
r.set('counter', 0)
|
||||
r.incr('counter') # Increment by 1
|
||||
r.incrby('counter', 5) # Increment by 5
|
||||
|
||||
# Lists
|
||||
r.rpush('my_list', 'item1')
|
||||
r.rpush('my_list', 'item2', 'item3') # Add multiple items
|
||||
|
||||
# Sets
|
||||
r.sadd('my_set', 'member1', 'member2', 'member3')
|
||||
|
||||
# Hashes (dictionaries)
|
||||
r.hset('user:1000', mapping={
|
||||
'username': 'john_doe',
|
||||
'email': 'john@example.com',
|
||||
'visits': 10
|
||||
})
|
||||
|
||||
# READING DATA FROM REDIS
|
||||
|
||||
# Simple key-value
|
||||
value = r.get("simple_key")
|
||||
print(f"Simple key value: {value.decode('utf-8')}")
|
||||
|
||||
# Check current counter value
|
||||
counter = r.get("counter")
|
||||
print(f"Counter value: {counter.decode('utf-8')}")
|
||||
|
||||
# Lists
|
||||
all_items = r.lrange("my_list", 0, -1) # Get all items
|
||||
print("List items:", [item.decode("utf-8") for item in all_items])
|
||||
|
||||
# Sets
|
||||
all_members = r.smembers("my_set")
|
||||
print("Set members:", [member.decode("utf-8") for member in all_members])
|
||||
|
||||
# Check if a member exists in a set
|
||||
is_member = r.sismember("my_set", "member1")
|
||||
print(f"Is 'member1' in set? {is_member}")
|
||||
|
||||
# Hashes
|
||||
username = r.hget("user:1000", "username")
|
||||
print(f"Username: {username.decode('utf-8')}")
|
||||
|
||||
# Get all hash fields
|
||||
user_data = r.hgetall("user:1000")
|
||||
print(
|
||||
"User data:",
|
||||
{k.decode("utf-8"): v.decode("utf-8") for k, v in user_data.items()},
|
||||
)
|
||||
|
||||
# Check remaining TTL for expiring key (in seconds)
|
||||
ttl = r.ttl("expiring_key")
|
||||
print(f"Expiring key TTL: {ttl} seconds")
|
||||
30
setup.py
Normal file
30
setup.py
Normal file
@ -0,0 +1,30 @@
|
||||
from setuptools import setup, Extension
|
||||
from setuptools.command.build_ext import build_ext
|
||||
import sys
|
||||
|
||||
# This class will properly handle NumPy dependencies
|
||||
class BuildExt(build_ext):
|
||||
def finalize_options(self):
|
||||
build_ext.finalize_options(self)
|
||||
# Prevent numpy from thinking it is still in its setup process
|
||||
import builtins
|
||||
builtins.__NUMPY_SETUP__ = False
|
||||
import numpy
|
||||
self.include_dirs.append(numpy.get_include())
|
||||
|
||||
setup(
|
||||
name='filter_short_groups',
|
||||
version='1.0',
|
||||
description='Optimized C implementation of filter_short_groups',
|
||||
setup_requires=['numpy'],
|
||||
install_requires=['numpy'],
|
||||
python_requires='>=3.6',
|
||||
ext_modules=[
|
||||
Extension(
|
||||
'filter_short_groups',
|
||||
sources=['filter_short_groups.c'],
|
||||
extra_compile_args=['-O3', '-march=native', '-ffast-math'], # Optimization flags
|
||||
),
|
||||
],
|
||||
cmdclass={'build_ext': BuildExt},
|
||||
)
|
||||
154
setup_well_svc_alert.sh
Normal file
154
setup_well_svc_alert.sh
Normal file
@ -0,0 +1,154 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- Configuration ---
|
||||
SERVICE_NAME="well-svc-alert"
|
||||
SERVICE_USER="wellsvc" # Recommended: Dedicated user
|
||||
SERVICE_GROUP="wellsvc" # Recommended: Dedicated group
|
||||
APP_DIR="/opt/well_service/alert" # Directory for this specific service
|
||||
ENV_FILE_PATH="/etc/default/${SERVICE_NAME}" # Path for credentials file
|
||||
SCRIPT_SOURCE="./well-svc-alert.py" # Source script
|
||||
SERVICE_FILE_SOURCE="./well-svc-alert.service" # Source systemd unit file
|
||||
|
||||
# --- Safety Check ---
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root (sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting Well Service Alert Setup..."
|
||||
|
||||
# --- Dependency Installation ---
|
||||
echo "Updating package list..."
|
||||
apt-get update
|
||||
|
||||
echo "Installing Python3, Pip, PostgreSQL client dev headers, Redis server & Python clients..."
|
||||
# Install system packages where possible
|
||||
# build-essential & python3-dev often needed for pip installs compiling C extensions
|
||||
apt-get install -y python3 python3-pip python3-dev libpq-dev \
|
||||
redis-server python3-redis python3-psycopg2 \
|
||||
build-essential
|
||||
|
||||
# Verify Redis Python client install method if system package isn't preferred
|
||||
# apt-get install -y python3 python3-pip python3-dev libpq-dev redis-server build-essential
|
||||
# pip3 install redis psycopg2-binary
|
||||
|
||||
# Ensure Redis is enabled and started (optional, Systemd `Requires` handles it for the service)
|
||||
# systemctl enable redis-server.service
|
||||
# systemctl start redis-server.service
|
||||
|
||||
# --- Create Service User ---
|
||||
echo "Checking/Creating service user '$SERVICE_USER' and group '$SERVICE_GROUP'..."
|
||||
if ! getent group "$SERVICE_GROUP" > /dev/null; then
|
||||
groupadd --system "$SERVICE_GROUP"
|
||||
echo "Group '$SERVICE_GROUP' created."
|
||||
fi
|
||||
if ! id "$SERVICE_USER" > /dev/null; then
|
||||
useradd --system --gid "$SERVICE_GROUP" --home "$(dirname $APP_DIR)" --no-create-home --shell /bin/false "$SERVICE_USER"
|
||||
echo "System user '$SERVICE_USER' created and added to group '$SERVICE_GROUP'."
|
||||
else
|
||||
echo "User '$SERVICE_USER' already exists."
|
||||
# Optionally add existing user to group if not already member
|
||||
# usermod -a -G "$SERVICE_GROUP" "$SERVICE_USER"
|
||||
fi
|
||||
|
||||
# --- Create Application Directory ---
|
||||
echo "Creating application directory '$APP_DIR'..."
|
||||
mkdir -p "$APP_DIR"
|
||||
if [ ! -d "$APP_DIR" ]; then
|
||||
echo "ERROR: Failed to create directory $APP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Copy Application Files ---
|
||||
echo "Copying service script..."
|
||||
cp "$SCRIPT_SOURCE" "$APP_DIR/well-svc-alert.py"
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Failed to copy script."; exit 1; fi
|
||||
|
||||
# --- Set Permissions ---
|
||||
echo "Setting permissions for '$APP_DIR'..."
|
||||
chown -R "$SERVICE_USER":"$SERVICE_GROUP" "$APP_DIR"
|
||||
# Owner: rwx, Group: rx, Other: ---
|
||||
chmod -R 750 "$APP_DIR"
|
||||
chmod +x "$APP_DIR/well-svc-alert.py"
|
||||
|
||||
# --- Create Environment File ---
|
||||
echo "Creating environment file at '$ENV_FILE_PATH'..."
|
||||
if [ -f "$ENV_FILE_PATH" ]; then
|
||||
echo "WARN: Environment file '$ENV_FILE_PATH' already exists. Backing up to ${ENV_FILE_PATH}.bak"
|
||||
cp "$ENV_FILE_PATH" "${ENV_FILE_PATH}.bak"
|
||||
fi
|
||||
cat > "$ENV_FILE_PATH" << EOF
|
||||
# Environment variables for the ${SERVICE_NAME} service
|
||||
# --- PLEASE FILL IN YOUR ACTUAL DATABASE CREDENTIALS ---
|
||||
DB_NAME=your_database_name
|
||||
DB_USER=your_database_user
|
||||
DB_PASSWORD=your_secret_password
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
|
||||
# --- Optional Redis Configuration (Defaults are usually fine) ---
|
||||
# REDIS_HOST=localhost
|
||||
# REDIS_PORT=6379
|
||||
# REDIS_DB=0
|
||||
# REDIS_PASSWORD=your_redis_password_if_any
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Failed to create environment file."; exit 1; fi
|
||||
|
||||
# --- Set Environment File Permissions ---
|
||||
echo "Setting permissions for '$ENV_FILE_PATH' (readable by root and $SERVICE_GROUP only)"
|
||||
chown root:"$SERVICE_GROUP" "$ENV_FILE_PATH"
|
||||
chmod 640 "$ENV_FILE_PATH" # Owner(root): rw, Group(wellsvc): r, Other: ---
|
||||
|
||||
# --- Install Systemd Service ---
|
||||
echo "Copying Systemd service file..."
|
||||
cp "$SERVICE_FILE_SOURCE" "/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Failed to copy systemd file."; exit 1; fi
|
||||
|
||||
# --- Update Paths/User in Systemd File ---
|
||||
echo "Updating configuration in /etc/systemd/system/${SERVICE_NAME}.service ..."
|
||||
ESCAPED_APP_DIR=$(printf '%s\n' "$APP_DIR" | sed 's:/:\\/:g')
|
||||
# Use placeholders like {{USER}}, {{GROUP}}, {{WORKDIR}}, {{EXECSTART}}, {{ENVFILE}} in the source .service file
|
||||
# Or use the sed commands carefully like below:
|
||||
sed -i "s/^User=.*/User=$SERVICE_USER/" "/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
sed -i "s/^Group=.*/Group=$SERVICE_GROUP/" "/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
sed -i "s:^WorkingDirectory=.*:WorkingDirectory=$ESCAPED_APP_DIR:" "/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
sed -i "s:^ExecStart=.*:ExecStart=/usr/bin/python3 $ESCAPED_APP_DIR/well-svc-alert.py:" "/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
sed -i "s:^EnvironmentFile=.*:EnvironmentFile=$ENV_FILE_PATH:" "/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
|
||||
|
||||
# --- Configure Systemd ---
|
||||
echo "Reloading Systemd daemon..."
|
||||
systemctl daemon-reload
|
||||
|
||||
echo "Enabling service '$SERVICE_NAME' to start on boot..."
|
||||
systemctl enable "${SERVICE_NAME}.service"
|
||||
|
||||
# Don't start immediately - user needs to edit the ENV_FILE_PATH first!
|
||||
# systemctl start "${SERVICE_NAME}.service"
|
||||
|
||||
# --- Final Instructions ---
|
||||
echo "Setup presque terminé!"
|
||||
echo ""
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "!! ACTION REQUISE : Modifiez le fichier d'environnement !!"
|
||||
echo "!! avec vos informations d'identification de base de données:"
|
||||
echo "!! sudo nano ${ENV_FILE_PATH}"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo ""
|
||||
echo "Après avoir modifié le fichier, démarrez le service avec :"
|
||||
echo "sudo systemctl start ${SERVICE_NAME}.service"
|
||||
echo ""
|
||||
echo "Pour vérifier l'état du service:"
|
||||
echo "sudo systemctl status ${SERVICE_NAME}.service --no-pager"
|
||||
echo ""
|
||||
echo "Pour consulter les journaux:"
|
||||
echo "sudo journalctl -u ${SERVICE_NAME}.service -f"
|
||||
echo ""
|
||||
echo "Pour arrêter le service:"
|
||||
echo "sudo systemctl stop ${SERVICE_NAME}.service"
|
||||
echo ""
|
||||
echo "Pour désactiver le démarrage automatique:"
|
||||
echo "sudo systemctl disable ${SERVICE_NAME}.service"
|
||||
echo "---"
|
||||
|
||||
exit 0
|
||||
16
simple_setup.py
Normal file
16
simple_setup.py
Normal file
@ -0,0 +1,16 @@
|
||||
from setuptools import setup, Extension
|
||||
|
||||
# Simple extension definition without NumPy dependencies for C compilation
|
||||
extension = Extension(
|
||||
'filter_short_groups',
|
||||
sources=['filter_short_groups.c'],
|
||||
extra_compile_args=['-O3'], # Just use basic optimization
|
||||
)
|
||||
|
||||
setup(
|
||||
name='filter_short_groups',
|
||||
version='1.0',
|
||||
description='Optimized C implementation of filter_short_groups',
|
||||
ext_modules=[extension],
|
||||
install_requires=['numpy'], # Still require numpy for runtime
|
||||
)
|
||||
342
simplified_filter_short_groups.c
Normal file
342
simplified_filter_short_groups.c
Normal file
@ -0,0 +1,342 @@
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// We don't actually need the NumPy C API for our implementation
|
||||
// since we're working directly with Python lists
|
||||
|
||||
// Struct to represent a run of consecutive values
|
||||
typedef struct {
|
||||
int start;
|
||||
int end;
|
||||
double sign;
|
||||
int length;
|
||||
} Run;
|
||||
|
||||
// Compare function for sorting runs by length, then by start index
|
||||
static int compare_runs(const void *a, const void *b) {
|
||||
const Run *run_a = (const Run *)a;
|
||||
const Run *run_b = (const Run *)b;
|
||||
|
||||
if (run_a->length != run_b->length) {
|
||||
return run_a->length - run_b->length;
|
||||
}
|
||||
return run_a->start - run_b->start;
|
||||
}
|
||||
|
||||
// Function to compute the sign of a double value (-1, 0, 1)
|
||||
static double sign(double x) {
|
||||
if (x > 0) return 1.0;
|
||||
if (x < 0) return -1.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Core implementation of filter_short_groups
|
||||
static PyObject* filter_short_groups_c(PyObject *self, PyObject *args) {
|
||||
PyObject *presence_list_obj;
|
||||
int filter_size;
|
||||
char *device_id;
|
||||
char *dates_str;
|
||||
|
||||
// Parse Python arguments
|
||||
if (!PyArg_ParseTuple(args, "Oiss", &presence_list_obj, &filter_size, &device_id, &dates_str)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Start timing
|
||||
clock_t start_time = clock();
|
||||
|
||||
// Convert Python list to C array
|
||||
Py_ssize_t n = PyObject_Length(presence_list_obj);
|
||||
if (n < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid input list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Early exit condition
|
||||
if (n == 0 || filter_size <= 1) {
|
||||
Py_INCREF(presence_list_obj);
|
||||
printf("C implementation: Early exit/no processing time: %.6fs\n",
|
||||
((double)(clock() - start_time) / CLOCKS_PER_SEC));
|
||||
return presence_list_obj;
|
||||
}
|
||||
|
||||
// Allocate memory for our working array
|
||||
double *result = (double *)malloc(n * sizeof(double));
|
||||
if (!result) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy data from Python list to C array
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyObject *item = PySequence_GetItem(presence_list_obj, i);
|
||||
if (!item) {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
result[i] = PyFloat_AsDouble(item);
|
||||
Py_DECREF(item);
|
||||
if (PyErr_Occurred()) {
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for signs array
|
||||
double *signs = (double *)malloc(n * sizeof(double));
|
||||
if (!signs) {
|
||||
free(result);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for signs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for change indices
|
||||
int *change_indices = (int *)malloc(n * sizeof(int));
|
||||
if (!change_indices) {
|
||||
free(result);
|
||||
free(signs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for change indices");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for boundaries
|
||||
int *boundaries = (int *)malloc((n + 1) * sizeof(int));
|
||||
if (!boundaries) {
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for boundaries");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for runs
|
||||
Run *runs = (Run *)malloc(n * sizeof(Run));
|
||||
if (!runs) {
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for runs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Simple cycle detection with hashset-like approach
|
||||
// We'll use a dynamically-sized array of states for simplicity
|
||||
int max_states = 100; // Initial capacity, will grow as needed
|
||||
int states_count = 0;
|
||||
double **previous_states = (double **)malloc(max_states * sizeof(double *));
|
||||
if (!previous_states) {
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for previous states");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cycle_detected = false;
|
||||
|
||||
// Main processing loop
|
||||
while (!cycle_detected) {
|
||||
// Check for cycle by comparing with previous states
|
||||
bool found_match = false;
|
||||
for (int s = 0; s < states_count; s++) {
|
||||
if (memcmp(previous_states[s], result, n * sizeof(double)) == 0) {
|
||||
found_match = true;
|
||||
cycle_detected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_match) {
|
||||
// Store current state
|
||||
if (states_count >= max_states) {
|
||||
// Grow the states array
|
||||
max_states *= 2;
|
||||
double **new_states = (double **)realloc(previous_states, max_states * sizeof(double *));
|
||||
if (!new_states) {
|
||||
// Handle memory allocation failure
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to reallocate memory for previous states");
|
||||
return NULL;
|
||||
}
|
||||
previous_states = new_states;
|
||||
}
|
||||
|
||||
// Allocate memory for the new state
|
||||
previous_states[states_count] = (double *)malloc(n * sizeof(double));
|
||||
if (!previous_states[states_count]) {
|
||||
// Handle memory allocation failure
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for new state");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy the current result to the new state
|
||||
memcpy(previous_states[states_count], result, n * sizeof(double));
|
||||
states_count++;
|
||||
|
||||
// 1. Calculate signs
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
signs[i] = sign(result[i]);
|
||||
}
|
||||
|
||||
// 2. Find indices where sign changes
|
||||
int change_count = 0;
|
||||
for (Py_ssize_t i = 1; i < n; i++) {
|
||||
if (signs[i] != signs[i-1]) {
|
||||
change_indices[change_count++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Define boundaries of consecutive runs
|
||||
boundaries[0] = 0;
|
||||
for (int i = 0; i < change_count; i++) {
|
||||
boundaries[i+1] = change_indices[i];
|
||||
}
|
||||
boundaries[change_count+1] = n;
|
||||
int boundaries_count = change_count + 2;
|
||||
|
||||
// If there's only one segment, no further processing needed
|
||||
if (boundaries_count <= 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 4. Extract run properties
|
||||
int run_count = 0;
|
||||
for (int i = 0; i < boundaries_count - 1; i++) {
|
||||
int start = boundaries[i];
|
||||
int end = boundaries[i+1];
|
||||
int length = end - start;
|
||||
double run_sign = signs[start];
|
||||
|
||||
// 5. Identify short runs
|
||||
if (length > 0 && length < filter_size) {
|
||||
runs[run_count].start = start;
|
||||
runs[run_count].end = end;
|
||||
runs[run_count].sign = run_sign;
|
||||
runs[run_count].length = length;
|
||||
run_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Check if any modifiable short runs were found
|
||||
if (run_count == 0) {
|
||||
// No short runs found, the list is stable
|
||||
break;
|
||||
}
|
||||
|
||||
// 7. Sort the short runs: shortest first, then by start index
|
||||
qsort(runs, run_count, sizeof(Run), compare_runs);
|
||||
|
||||
// 8. Process the first (shortest) identified run
|
||||
Run run_to_process = runs[0];
|
||||
int start = run_to_process.start;
|
||||
int end = run_to_process.end;
|
||||
double run_sign = run_to_process.sign;
|
||||
|
||||
// Determine replacement value
|
||||
double replacement_value = (run_sign == 0) ? 1.0 : 0.0;
|
||||
|
||||
// 9. Apply the replacement
|
||||
for (int i = start; i < end; i++) {
|
||||
result[i] = replacement_value;
|
||||
}
|
||||
// Loop continues for the next pass
|
||||
}
|
||||
}
|
||||
|
||||
// Create Python list for the result
|
||||
PyObject *result_list = PyList_New(n);
|
||||
if (!result_list) {
|
||||
// Cleanup and return
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fill result list
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyObject *item = PyFloat_FromDouble(result[i]);
|
||||
if (!item) {
|
||||
Py_DECREF(result_list);
|
||||
// Cleanup and return
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
return NULL;
|
||||
}
|
||||
PyList_SET_ITEM(result_list, i, item);
|
||||
}
|
||||
|
||||
// Print timing information
|
||||
printf("filter_short_groups_c time: %.6fs\n", ((double)(clock() - start_time) / CLOCKS_PER_SEC));
|
||||
|
||||
// Cleanup
|
||||
for (int i = 0; i < states_count; i++) {
|
||||
free(previous_states[i]);
|
||||
}
|
||||
free(previous_states);
|
||||
free(result);
|
||||
free(signs);
|
||||
free(change_indices);
|
||||
free(boundaries);
|
||||
free(runs);
|
||||
|
||||
return result_list;
|
||||
}
|
||||
|
||||
// Method definitions
|
||||
static PyMethodDef FilterShortGroupsMethods[] = {
|
||||
{"filter_short_groups_c", filter_short_groups_c, METH_VARARGS,
|
||||
"Optimized C version to remove groups of consecutive zeros or non-zeros shorter than filter_size."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
// Module definition
|
||||
static struct PyModuleDef filter_short_groups_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"filter_short_groups",
|
||||
"A module that provides optimized filter_short_groups function",
|
||||
-1,
|
||||
FilterShortGroupsMethods
|
||||
};
|
||||
|
||||
// Module initialization
|
||||
PyMODINIT_FUNC PyInit_filter_short_groups(void) {
|
||||
return PyModule_Create(&filter_short_groups_module);
|
||||
}
|
||||
69
stack.yml
Normal file
69
stack.yml
Normal file
@ -0,0 +1,69 @@
|
||||
version: 1.0
|
||||
provider:
|
||||
name: openfaas
|
||||
gateway: http://192.168.68.70:8082
|
||||
functions:
|
||||
well-api:
|
||||
image: repo.eluxnetworks.net/well-api:latest
|
||||
annotations:
|
||||
com.openfaas.timeouts.read: "60s"
|
||||
com.openfaas.timeouts.write: "60s"
|
||||
com.openfaas.timeouts.exec: "60s"
|
||||
volumes:
|
||||
- /home/app/well_web_storage:/home/app/well_web_storage
|
||||
labels:
|
||||
com.openfaas.scale.min: 1
|
||||
com.openfaas.scale.max: 10
|
||||
com.openfaas.scale.factor: 20%
|
||||
com.openfaas.scale.zero: false
|
||||
# Traefik routing configuration
|
||||
traefik.enable: true
|
||||
traefik.docker.network: traefik-public
|
||||
traefik.http.routers.well-api.rule: Host(`eluxnetworks.net`) && PathPrefix(`/function/well-api`)
|
||||
traefik.http.routers.well-api.entrypoints: websecure
|
||||
traefik.http.routers.well-api.tls.certresolver: letsencrypt
|
||||
traefik.http.services.well-api.loadbalancer.server.port: 8080
|
||||
# Set a higher priority to ensure this rule takes precedence
|
||||
traefik.http.routers.well-api.priority: 100
|
||||
environment:
|
||||
read_timeout: "60s"
|
||||
write_timeout: "60s"
|
||||
exec_timeout: "60s"
|
||||
combine_output: true
|
||||
# Gunicorn-specific settings
|
||||
GUNICORN_WORKERS: "2"
|
||||
GUNICORN_THREADS: "4"
|
||||
|
||||
DB_NAME: "wellnuo"
|
||||
DB_USER: "well_app"
|
||||
DB_PASSWORD: "well_app_2024"
|
||||
DB_HOST: "192.168.68.70"
|
||||
DB_PORT: "5432"
|
||||
MINIO_ACCESS_KEY: "well_pipe"
|
||||
MINIO_SECRET_KEY: "WellNuo_2024"
|
||||
MINIO_HOST: "192.168.68.70"
|
||||
MINIO_PORT: "9000"
|
||||
DAILY_MAPS_BUCKET_NAME: "daily-maps"
|
||||
JWT_SECRET: "Well_202502110501"
|
||||
MASTER_ADMIN: "robster"
|
||||
MASTER_PS: "rob2"
|
||||
OPENAI_API_KEY: "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"
|
||||
OPENAI_API_MODEL_ENGINE: "gpt-3.5-turbo"
|
||||
REDIS_PORT: "6379"
|
||||
TELNYX_API_KEY: "KEY0196087A75998434A30FA637CE4FDAFF_ZljGj9KBSAQL0zXx4Sb5eW"
|
||||
TELNYX_API_BASE_URL: "https://api.telnyx.com/v2"
|
||||
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 256Mi
|
||||
requests:
|
||||
memory: 128Mi
|
||||
networks:
|
||||
- func_functions
|
||||
- traefik-public
|
||||
networks:
|
||||
func_functions:
|
||||
external: true
|
||||
traefik-public:
|
||||
external: true
|
||||
17282
test_list.json
Normal file
17282
test_list.json
Normal file
File diff suppressed because it is too large
Load Diff
10179
time_differences.csv
Normal file
10179
time_differences.csv
Normal file
File diff suppressed because it is too large
Load Diff
11143
time_differences_light.csv
Normal file
11143
time_differences_light.csv
Normal file
File diff suppressed because it is too large
Load Diff
39572
time_differences_light_510.csv
Normal file
39572
time_differences_light_510.csv
Normal file
File diff suppressed because it is too large
Load Diff
40058
time_differences_light_524.csv
Normal file
40058
time_differences_light_524.csv
Normal file
File diff suppressed because it is too large
Load Diff
10897
time_differences_pressure.csv
Normal file
10897
time_differences_pressure.csv
Normal file
File diff suppressed because it is too large
Load Diff
39572
time_differences_pressure_510.csv
Normal file
39572
time_differences_pressure_510.csv
Normal file
File diff suppressed because it is too large
Load Diff
39965
time_differences_pressure_524.csv
Normal file
39965
time_differences_pressure_524.csv
Normal file
File diff suppressed because it is too large
Load Diff
146
usage_example.py
Normal file
146
usage_example.py
Normal file
@ -0,0 +1,146 @@
|
||||
import numpy as np
|
||||
import time
|
||||
from filter_short_groups import filter_short_groups_c
|
||||
|
||||
def filter_short_groups_numpy(presence_list, filter_size, device_id, dates_str):
|
||||
"""
|
||||
Original NumPy implementation, kept for comparison purposes.
|
||||
"""
|
||||
# Start timer (optional, for benchmarking)
|
||||
st = time.time()
|
||||
|
||||
if not presence_list or filter_size <= 1:
|
||||
print(f"NumPy Optimized: Early exit/no processing time: {time.time() - st:.6f}s")
|
||||
return presence_list[:] if isinstance(presence_list, list) else list(presence_list)
|
||||
|
||||
result = np.array(presence_list, dtype=float)
|
||||
n = len(result)
|
||||
|
||||
previous_states = set()
|
||||
|
||||
while True:
|
||||
# Cycle detection
|
||||
current_state_tuple = tuple(result)
|
||||
if current_state_tuple in previous_states:
|
||||
print("NumPy Optimized: Cycle detected, breaking.")
|
||||
break
|
||||
previous_states.add(current_state_tuple)
|
||||
|
||||
# 1. Calculate the sign of each element (-1, 0, 1)
|
||||
signs = np.sign(result)
|
||||
|
||||
# 2. Find indices where the sign changes
|
||||
change_indices = np.where(np.diff(signs) != 0)[0] + 1
|
||||
|
||||
# 3. Define the boundaries of all consecutive runs
|
||||
boundaries = np.concatenate(([0], change_indices, [n]))
|
||||
|
||||
# If there's only one segment, no further processing is needed.
|
||||
if len(boundaries) <= 2:
|
||||
break
|
||||
|
||||
# 4. Vectorized extraction of run properties
|
||||
run_starts = boundaries[:-1]
|
||||
run_ends = boundaries[1:]
|
||||
run_lengths = run_ends - run_starts
|
||||
run_signs = signs[run_starts]
|
||||
|
||||
# 5. Identify short runs and collect their properties
|
||||
short_runs_to_process = []
|
||||
for i in range(len(run_starts)):
|
||||
if run_lengths[i] > 0 and run_lengths[i] < filter_size:
|
||||
short_runs_to_process.append({
|
||||
'start': run_starts[i],
|
||||
'end': run_ends[i],
|
||||
'sign': run_signs[i],
|
||||
'length': run_lengths[i]
|
||||
})
|
||||
|
||||
# 6. Check if any modifiable short runs were found
|
||||
if not short_runs_to_process:
|
||||
break
|
||||
|
||||
# 7. Sort the short runs: shortest first, then by start index for determinism
|
||||
short_runs_to_process.sort(key=lambda r: (r['length'], r['start']))
|
||||
|
||||
# 8. Process ONLY the *first* (shortest) identified run in this pass
|
||||
run_to_process = short_runs_to_process[0]
|
||||
start = run_to_process['start']
|
||||
end = run_to_process['end']
|
||||
run_sign = run_to_process['sign']
|
||||
|
||||
# Determine the replacement value
|
||||
replacement_value = 1.0 if run_sign == 0 else 0.0
|
||||
|
||||
# 9. Apply the replacement
|
||||
result[start:end] = replacement_value
|
||||
|
||||
# End timer and print
|
||||
print(f"filter_short_groups_numpy time: {time.time() - st:.6f}s")
|
||||
|
||||
return result.tolist()
|
||||
|
||||
def benchmark_comparison(input_data, filter_size, iterations=10):
|
||||
"""
|
||||
Compare performance between NumPy and C implementations
|
||||
"""
|
||||
device_id = "test_device"
|
||||
dates_str = "2025-05-21"
|
||||
|
||||
# Warm-up runs
|
||||
_ = filter_short_groups_numpy(input_data, filter_size, device_id, dates_str)
|
||||
_ = filter_short_groups_c(input_data, filter_size, device_id, dates_str)
|
||||
|
||||
# NumPy benchmark
|
||||
numpy_times = []
|
||||
for _ in range(iterations):
|
||||
start = time.time()
|
||||
numpy_result = filter_short_groups_numpy(input_data, filter_size, device_id, dates_str)
|
||||
numpy_times.append(time.time() - start)
|
||||
|
||||
# C implementation benchmark
|
||||
c_times = []
|
||||
for _ in range(iterations):
|
||||
start = time.time()
|
||||
c_result = filter_short_groups_c(input_data, filter_size, device_id, dates_str)
|
||||
c_times.append(time.time() - start)
|
||||
|
||||
# Check results match
|
||||
results_match = numpy_result == c_result
|
||||
|
||||
# Print results
|
||||
print(f"\nResults from NumPy and C implementation match: {results_match}")
|
||||
print(f"\nNumPy Implementation:")
|
||||
print(f" Average time: {np.mean(numpy_times):.6f}s")
|
||||
print(f" Min time: {np.min(numpy_times):.6f}s")
|
||||
print(f" Max time: {np.max(numpy_times):.6f}s")
|
||||
|
||||
print(f"\nC Implementation:")
|
||||
print(f" Average time: {np.mean(c_times):.6f}s")
|
||||
print(f" Min time: {np.min(c_times):.6f}s")
|
||||
print(f" Max time: {np.max(c_times):.6f}s")
|
||||
|
||||
speedup = np.mean(numpy_times) / np.mean(c_times)
|
||||
print(f"\nSpeedup factor: {speedup:.2f}x")
|
||||
|
||||
return numpy_result, c_result
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example data
|
||||
# Random presence list with mix of 0s and 1s
|
||||
np.random.seed(42)
|
||||
data_small = list(np.random.choice([0.0, 1.0], size=100))
|
||||
data_medium = list(np.random.choice([0.0, 1.0], size=1000))
|
||||
data_large = list(np.random.choice([0.0, 1.0], size=10000))
|
||||
|
||||
# Example with small data
|
||||
print("\n===== Small dataset (100 elements) =====")
|
||||
numpy_result_small, c_result_small = benchmark_comparison(data_small, filter_size=3)
|
||||
|
||||
# Example with medium data
|
||||
print("\n===== Medium dataset (1000 elements) =====")
|
||||
numpy_result_medium, c_result_medium = benchmark_comparison(data_medium, filter_size=5)
|
||||
|
||||
# Example with large data
|
||||
print("\n===== Large dataset (10000 elements) =====")
|
||||
numpy_result_large, c_result_large = benchmark_comparison(data_large, filter_size=10)
|
||||
138
verify_installation.py
Normal file
138
verify_installation.py
Normal file
@ -0,0 +1,138 @@
|
||||
"""
|
||||
Verify that the installed filter_short_groups module works correctly.
|
||||
"""
|
||||
import time
|
||||
import numpy as np
|
||||
import random
|
||||
|
||||
# Try to import the module
|
||||
try:
|
||||
from filter_short_groups import filter_short_groups_c
|
||||
print("Successfully imported filter_short_groups_c")
|
||||
except ImportError as e:
|
||||
print(f"Error importing module: {e}")
|
||||
exit(1)
|
||||
|
||||
# Define the NumPy reference implementation for comparison
|
||||
def filter_short_groups_numpy(presence_list, filter_size, device_id, dates_str):
|
||||
"""
|
||||
NumPy implementation, kept for comparison purposes.
|
||||
"""
|
||||
st = time.time()
|
||||
|
||||
if not presence_list or filter_size <= 1:
|
||||
print(f"NumPy: Early exit/no processing time: {time.time() - st:.6f}s")
|
||||
return presence_list[:] if isinstance(presence_list, list) else list(presence_list)
|
||||
|
||||
result = np.array(presence_list, dtype=float)
|
||||
n = len(result)
|
||||
previous_states = set()
|
||||
|
||||
while True:
|
||||
current_state_tuple = tuple(result)
|
||||
if current_state_tuple in previous_states:
|
||||
print("NumPy: Cycle detected, breaking.")
|
||||
break
|
||||
previous_states.add(current_state_tuple)
|
||||
|
||||
signs = np.sign(result)
|
||||
change_indices = np.where(np.diff(signs) != 0)[0] + 1
|
||||
boundaries = np.concatenate(([0], change_indices, [n]))
|
||||
|
||||
if len(boundaries) <= 2:
|
||||
break
|
||||
|
||||
run_starts = boundaries[:-1]
|
||||
run_ends = boundaries[1:]
|
||||
run_lengths = run_ends - run_starts
|
||||
run_signs = signs[run_starts]
|
||||
|
||||
short_runs_to_process = []
|
||||
for i in range(len(run_starts)):
|
||||
if run_lengths[i] > 0 and run_lengths[i] < filter_size:
|
||||
short_runs_to_process.append({
|
||||
'start': run_starts[i],
|
||||
'end': run_ends[i],
|
||||
'sign': run_signs[i],
|
||||
'length': run_lengths[i]
|
||||
})
|
||||
|
||||
if not short_runs_to_process:
|
||||
break
|
||||
|
||||
short_runs_to_process.sort(key=lambda r: (r['length'], r['start']))
|
||||
run_to_process = short_runs_to_process[0]
|
||||
start = run_to_process['start']
|
||||
end = run_to_process['end']
|
||||
run_sign = run_to_process['sign']
|
||||
replacement_value = 1.0 if run_sign == 0 else 0.0
|
||||
result[start:end] = replacement_value
|
||||
|
||||
print(f"filter_short_groups_numpy time: {time.time() - st:.6f}s")
|
||||
return result.tolist()
|
||||
|
||||
def run_test_case(test_data, filter_size, name="Test"):
|
||||
"""Run both implementations and compare results and performance."""
|
||||
print(f"\n===== {name} =====")
|
||||
|
||||
device_id = "test_device"
|
||||
dates_str = "2025-05-21"
|
||||
|
||||
# Run NumPy implementation
|
||||
start_time = time.time()
|
||||
numpy_result = filter_short_groups_numpy(test_data, filter_size, device_id, dates_str)
|
||||
numpy_time = time.time() - start_time
|
||||
|
||||
# Run C implementation
|
||||
start_time = time.time()
|
||||
c_result = filter_short_groups_c(test_data, filter_size, device_id, dates_str)
|
||||
c_time = time.time() - start_time
|
||||
|
||||
# Compare results
|
||||
results_match = numpy_result == c_result
|
||||
|
||||
# Print results
|
||||
print(f"Results match: {results_match}")
|
||||
if not results_match:
|
||||
print(f"NumPy result: {numpy_result[:20]}...")
|
||||
print(f"C result: {c_result[:20]}...")
|
||||
|
||||
print(f"NumPy time: {numpy_time:.6f}s")
|
||||
print(f"C time: {c_time:.6f}s")
|
||||
print(f"Speedup: {numpy_time / c_time:.2f}x")
|
||||
|
||||
return results_match
|
||||
|
||||
def main():
|
||||
"""Run all test cases."""
|
||||
# Simple predefined test case
|
||||
test_case_1 = [0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0]
|
||||
filter_size_1 = 3
|
||||
|
||||
# Small random test case
|
||||
np.random.seed(42)
|
||||
test_case_2 = list(np.random.choice([0.0, 1.0], size=100))
|
||||
filter_size_2 = 4
|
||||
|
||||
# Medium random test case
|
||||
test_case_3 = list(np.random.choice([0.0, 1.0], size=1000))
|
||||
filter_size_3 = 5
|
||||
|
||||
# Large random test case
|
||||
test_case_4 = list(np.random.choice([0.0, 1.0], size=10000))
|
||||
filter_size_4 = 10
|
||||
|
||||
# Run test cases
|
||||
all_passed = True
|
||||
all_passed &= run_test_case(test_case_1, filter_size_1, "Simple Test Case")
|
||||
all_passed &= run_test_case(test_case_2, filter_size_2, "Small Random Test (n=100)")
|
||||
all_passed &= run_test_case(test_case_3, filter_size_3, "Medium Random Test (n=1000)")
|
||||
all_passed &= run_test_case(test_case_4, filter_size_4, "Large Random Test (n=10000)")
|
||||
|
||||
if all_passed:
|
||||
print("\n✅ All tests passed! The C implementation works correctly.")
|
||||
else:
|
||||
print("\n❌ Some tests failed! Check the output above for details.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
90
vocabulary.json
Normal file
90
vocabulary.json
Normal file
@ -0,0 +1,90 @@
|
||||
{
|
||||
"utterances":{
|
||||
"status_intent":["how is dad doing", "how is dad", "how's my dad doing", "how is that doing","how's dad doing","how is my dad doing", "dad doing"],
|
||||
"status_intent_f":["how is mom doing", "how is mom", "how's my mom doing", "how's mom doing","how is my mom doing", "mom doing", "how's my mom doing"],
|
||||
"location_intent":["where is he now"],
|
||||
"location_intent_f":["where is she now"],
|
||||
"logging_intent":["log in", "login", "loggin", "logging"],
|
||||
"temperature_intent":["what is the temperature there","what's the temperature there","what's the temperature","where is the temperature","what is temperature there", "temperature there"],
|
||||
"sleeping_intent":["how is his sleep", "how was his sleep", "how was his night"],
|
||||
"sleeping_intent_f":["how is her sleep", "how was her sleep", "how was her night"],
|
||||
"restroom_intent":["how about bathroom use", "how about restroom use"],
|
||||
"shower_intent":["how often is dad taking shower", "how often is that taking shower", "how often is he taking shower"],
|
||||
"shower_intent_f":["how often is mom taking shower", "how often is she taking shower"],
|
||||
"environment_intent":["how is environment there"],
|
||||
"mold_intent":["can you smell any mold", "mold"],
|
||||
"visitors_intent":["were there any visitors recently", "visitors", "visitor"],
|
||||
"oxygen_intent":["what is his oxygen level", "what is his oxygen"],
|
||||
"oxygen_intent_f":["what is her oxygen level", "what is her oxygen"],
|
||||
"hr_intent":["what was last heart rate", "what is the heartrate", "heart rate", "heartrate"],
|
||||
"bp_intent":["what is his blood pressure", "what is his pressure", "his blood pressure"],
|
||||
"bp_intent_f":["what is her blood pressure", "what is her pressure", "her blood pressure"],
|
||||
"ekg_intent":["what is his ekg", "what is his heartbeam ekg", "what is his heartbeat ekg", "what is his heart being ekg", "his ekg"],
|
||||
"ekg_intent_f":["what is her ekg", "what is her heartbeam ekg", "what is her heartbeat ekg", "what is her heart being ekg", "her ekg", "ekg"],
|
||||
"kitchen_intent":["when was kitchen used", "was stowe left on", "kitchen", "stowe"],
|
||||
"show_activity_report_intent":["show activity report", "show activity", "so activity"],
|
||||
"activity_level_intent":["what is his activity level this week", "his activity level"],
|
||||
"activity_level_intent_f":["what is her activity level this week", "her activity level"],
|
||||
"activity_level_compare_intent":["what is his activity level this week compared to last year"],
|
||||
"activity_level_compare_intent_f":["what is her activity level this week compared to last year"],
|
||||
"show_sleep_report_intent":["show sleep report", "show sleep", "so sleep"],
|
||||
"show_air_report_intent":["show air report", "show airport", "so air", "show air"],
|
||||
"connect_intent":["connect to closest device", "connect device", "connect"],
|
||||
"disconnect_intent":["disconnect device", "disconnect"],
|
||||
"week_intent":["show me his week activity", "show me his weekly activity", "show me his weak activity", "show his week"],
|
||||
"week_intent_f":["show me her week activity", "show me her weekly activity", "show me her weak activity", "show her week"]
|
||||
},
|
||||
"keywords":{
|
||||
"help_intent":["help"],
|
||||
"status_intent":["doing", "status"],
|
||||
"location_intent":["where","location"],
|
||||
"temperature_intent":["temperature"],
|
||||
"sleeping_intent":["sleep", "night"],
|
||||
"restroom_intent":["bathroom", "restroom"],
|
||||
"shower_intent":["shower"],
|
||||
"environment_intent":["environment"],
|
||||
"mold_intent":["mold"],
|
||||
"visitors_intent":["visit", "visitor", "visitors"],
|
||||
"kitchen_intent":["stove", "kitchen"],
|
||||
"oxygen_intent":["oxygen"],
|
||||
"hr_intent":["heart rate"],
|
||||
"bp_intent":["pressure"],
|
||||
"ekg_intent":["ekg"],
|
||||
"week_intent":["week"]
|
||||
},
|
||||
"intents":{
|
||||
"help_intent":["#HELP#"],
|
||||
"status_intent":["#STATUS#"],
|
||||
"status_intent_f":["#STATUS_F#"],
|
||||
"sleeping_intent":["#SLEEP#"],
|
||||
"sleeping_intent_f":["#SLEEP_F#"],
|
||||
"restroom_intent":["#BATHROOM#"],
|
||||
"logging_intent":["#LOGIN#"],
|
||||
"shower_intent":["#SHOWER#"],
|
||||
"shower_intent_f":["#SHOWER_F#"],
|
||||
"environment_intent":["#ENVIRONMENT#"],
|
||||
"temperature_intent":["#TEMPERATURE#"],
|
||||
"location_intent":["#LOCATION#"],
|
||||
"mold_intent":["#MOLD#"],
|
||||
"visitors_intent":["#VISITORS#"],
|
||||
"kitchen_intent":["#KITCHEN#"],
|
||||
"oxygen_intent":["#OXYGEN#"],
|
||||
"oxygen_intent_f":["#OXYGEN_F#"],
|
||||
"hr_intent":["#HEART_RATE#"],
|
||||
"bp_intent":["#BLOOD_PRESSURE#"],
|
||||
"bp_intent_f":["#BLOOD_PRESSURE_F#"],
|
||||
"ekg_intent":["#EKG#"],
|
||||
"ekg_intent_f":["#EKG_F#"],
|
||||
"activity_level_intent":["#ACTIVITY#"],
|
||||
"activity_level_intent_f":["#ACTIVITY_F#"],
|
||||
"activity_level_compare_intent":["#ACTIVITY_COMPARE#"],
|
||||
"activity_level_compare_intent_f":["#ACTIVITY_COMPARE_F#"],
|
||||
"show_activity_report_intent":["#SHOW_ACTIVITY#"],
|
||||
"show_sleep_report_intent":["#SHOW_SLEEP#"],
|
||||
"show_air_report_intent":["#SHOW_AIR#"],
|
||||
"connect_intent":["#BT_CONNECT#"],
|
||||
"disconnect_intent":["#BT_DISCONNECT#"],
|
||||
"week_intent":["#WEEK#"],
|
||||
"week_intent_f":["#WEEK_F#"]
|
||||
}
|
||||
}
|
||||
17162
well-api.py
Normal file
17162
well-api.py
Normal file
File diff suppressed because it is too large
Load Diff
12520
well-api2.py
Normal file
12520
well-api2.py
Normal file
File diff suppressed because it is too large
Load Diff
13282
well-api3.py
Normal file
13282
well-api3.py
Normal file
File diff suppressed because it is too large
Load Diff
4729
well_web_files/deployment.html
Normal file
4729
well_web_files/deployment.html
Normal file
File diff suppressed because it is too large
Load Diff
2292
well_web_files/devices.html
Normal file
2292
well_web_files/devices.html
Normal file
File diff suppressed because it is too large
Load Diff
56
well_web_files/dialog.json
Normal file
56
well_web_files/dialog.json
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"utterances":{
|
||||
"help_intent":["what can you do","what can you provide", "help"],
|
||||
"status_intent":["how is dad doing", "how is dad", "how is mom", "how's my dad doing", "how is that doing","how's dad doing","how is my dad doing", "dad doing", "how's my mom doing", "how's mom doing", "how is my mom doing","how is mom doing", "mom doing"],
|
||||
"location_intent":["where is he now","where is she now", "where now", "where","where is that now","where is dead now","where is mom now","where is mum now"],
|
||||
"temperature_intent":["what is the temperature there","what's the temperature there","what's the temperature","where is the temperature","what is temperature there", "temperature there", "temperature"],
|
||||
"sleeping_intent":["how is his sleep", "how is her sleep", "how was his sleep", "how was her sleep", "how was his night", "how was her night", "sleep", "night"],
|
||||
"restroom_intent":["how about bathroom use", "how about restroom use", "how often did dad use restroom last night", "bathroom", "restroom"],
|
||||
"shower_intent":["how often is dad taking shower", "how often is that taking shower", "how often is he taking shower", "how often is mom taking shower", "how often is she taking shower", "taking shower", "shower"],
|
||||
"environment_intent":["how is his environment", "how is her environment", "environment"],
|
||||
"mold_intent":["can you smell any mold", "mold"],
|
||||
"visitors_intent":["did my dad get any visitors recently", "visitors", "visitor"],
|
||||
"oxygen_intent":["what is his oxygen level", "what is his oxygen", "oxygen"],
|
||||
"hr_intent":["what is his heart rate", "what is his heartrate", "heart rate", "heartrate"],
|
||||
"bp_intent":["what is his blood pressure", "what is his pressure", "his blood pressure", "blood pressure", "pressure"],
|
||||
"ekg_intent":["what is his ekg", "what is his heartbeam ekg", "what is his heartbeat ekg", "what is his heart being ekg", "his ekg", "ekg"],
|
||||
"kitchen_intent":["when was kitchen used", "was stowe left on", "kitchen", "stowe"],
|
||||
"week_intent":["show me his week activity", "show me his weekly activity", "show me his weak activity", "show me her week activity", "show me her weekly activity", "show me her weak activity", "show week", "show his week", "show her week"]
|
||||
},
|
||||
"keywords":{
|
||||
"help_intent":["help"],
|
||||
"status_intent":["doing", "status"],
|
||||
"location_intent":["where","location"],
|
||||
"temperature_intent":["temperature"],
|
||||
"sleeping_intent":["sleep", "night"],
|
||||
"restroom_intent":["bathroom", "restroom"],
|
||||
"shower_intent":["shower"],
|
||||
"environment_intent":["environment"],
|
||||
"mold_intent":["mold"],
|
||||
"visitors_intent":["visit", "visitor", "visitors"],
|
||||
"kitchen_intent":["stove", "kitchen"],
|
||||
"oxygen_intent":["oxygen"],
|
||||
"hr_intent":["heart rate"],
|
||||
"bp_intent":["pressure"],
|
||||
"ekg_intent":["ekg"],
|
||||
"week_intent":["week"]
|
||||
},
|
||||
"intents":{
|
||||
"help_intent":["#HELP#"],
|
||||
"status_intent":["#STATUS#"],
|
||||
"sleeping_intent":["#SLEEP#"],
|
||||
"restroom_intent":["#BATHROOM#"],
|
||||
"shower_intent":["#SHOWER#"],
|
||||
"environment_intent":["#ENVIRONMENT#"],
|
||||
"temperature_intent":["#TEMPERATURE#"],
|
||||
"location_intent":["#LOCATION#"],
|
||||
"mold_intent":["#MOLD#"],
|
||||
"visitors_intent":["#VISITORS#"],
|
||||
"kitchen_intent":["#KITCHEN#"],
|
||||
"oxygen_intent":["#OXYGEN#"],
|
||||
"hr_intent":["#HEART_RATE#"],
|
||||
"bp_intent":["#BLOOD_PRESSURE#"],
|
||||
"ekg_intent":["#EKG#"],
|
||||
"week_intent":["#WEEK#"]
|
||||
}
|
||||
}
|
||||
291
well_web_files/edit_beneficiary.html
Normal file
291
well_web_files/edit_beneficiary.html
Normal file
@ -0,0 +1,291 @@
|
||||
<!--
|
||||
Written By: Robert Zmrzli robert@wellnuo.com
|
||||
edit_beneficiary.html
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Beneficiary</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
token = "0"
|
||||
user_id = ""
|
||||
priviledges = 0
|
||||
//api_url = "https://well-api.azurewebsites.net/api/well_api";
|
||||
const baseURL = window.location.origin;
|
||||
const api_url = `${baseURL}/function/well-api`;
|
||||
|
||||
function initialize() {
|
||||
token = localStorage.getItem('token');
|
||||
user_name = localStorage.getItem('user_name');
|
||||
user_id = localStorage.getItem('user_id');
|
||||
priviledges = localStorage.getItem('priviledges');
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function SendToServer(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
async function SubmitBeneficiaryForm(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function SubmitBeneficiary() {
|
||||
|
||||
editing_user_id = document.getElementById("editing_user_id").innerText;
|
||||
role_ids = document.getElementById("role_ids").value;
|
||||
|
||||
email = document.getElementById("email").value;
|
||||
new_user_name = document.getElementById("new_user_name").value;
|
||||
key = document.getElementById("key").value;
|
||||
first_name = document.getElementById("first_name").value;
|
||||
last_name = document.getElementById("last_name").value;
|
||||
address_street = document.getElementById("address_street").value;
|
||||
address_city = document.getElementById("address_city").value;
|
||||
address_zip = document.getElementById("address_zip").value;
|
||||
address_state = document.getElementById("address_state").value;
|
||||
address_country = document.getElementById("address_country").value;
|
||||
phone_number = document.getElementById("phone_number").value;
|
||||
picture = document.getElementById("picture").value;
|
||||
|
||||
if (new_user_name.length < 2) {
|
||||
alert("User Name is too short!")
|
||||
}
|
||||
else if (email.length < 4) {
|
||||
alert("Email too short!")
|
||||
}
|
||||
else if (key.length < 4) {
|
||||
alert("Password too short!")
|
||||
}
|
||||
else {
|
||||
|
||||
// Form URL encoded data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "beneficiary_form");
|
||||
formData.append('user_name', user_name);
|
||||
formData.append('user_id', user_id);
|
||||
formData.append('token', token);
|
||||
formData.append('key', key);
|
||||
formData.append('new_user_name', new_user_name);
|
||||
formData.append('editing_user_id', editing_user_id);
|
||||
formData.append('role_ids', role_ids);
|
||||
formData.append('email', email);
|
||||
formData.append('first_name', first_name);
|
||||
formData.append('last_name', last_name);
|
||||
formData.append('address_street', address_street);
|
||||
formData.append('address_city', address_city);
|
||||
formData.append('address_zip', address_zip);
|
||||
formData.append('address_state', address_state);
|
||||
formData.append('address_country', address_country);
|
||||
formData.append('phone_number', phone_number);
|
||||
formData.append('picture', picture);
|
||||
|
||||
data = await SubmitBeneficiaryForm(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Beneficiary is stored!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to store');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function DeleteBeneficiary() {
|
||||
|
||||
editing_user_id = document.getElementById("editing_user_id").innerText;
|
||||
|
||||
if (confirm("Are you sure you want to delete this beneficiary?")) {
|
||||
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "beneficiary_delete");
|
||||
formData.append('token', token);
|
||||
formData.append('delete_user_id', editing_user_id);
|
||||
user_name = localStorage.getItem('user_name');
|
||||
formData.append('user_name', user_name);
|
||||
|
||||
|
||||
data = await SendToServer(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Beneficiary is deleted!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to delete');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TZoneChange() {
|
||||
document.getElementById("tzone").value = document.getElementById("tzone_s").value;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="initialize();">
|
||||
|
||||
<div id="edit_beneficiary_content" style="margin: 0 auto; max-width: 400px; background-color: #f9f9f9; border: 1px solid #ccc; border-radius: 10px; padding: 20px; text-align: left; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);">
|
||||
<h2 class="info-text">Beneficiary Information Id = <span id="editing_user_id">23</span></h2>
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="new_user_name" style="display: block; margin-bottom: 5px; color: #333;">User Name: *</label>
|
||||
<input type="text" id="new_user_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder='Name to log-in with'>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="key" style="display: block; margin-bottom: 5px; color: #333;">Password: *</label>
|
||||
<input type="text" id="key" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="email" style="display: block; margin-bottom: 5px; color: #333;">Email: *</label>
|
||||
<input type="text" id="email" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="first_name" style="display: block; margin-bottom: 5px; color: #333;">First Name:</label>
|
||||
<input type="text" id="first_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="last_name" style="display: block; margin-bottom: 5px; color: #333;">Last Name:</label>
|
||||
<input type="text" id="last_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<h3 style="color: #333; border-bottom: 1px solid #ddd; padding-bottom: 5px;">Address</h3>
|
||||
<label for="address_street" style="display: block; margin-bottom: 5px; color: #333;">Street # and name:</label>
|
||||
<input type="text" id="address_street" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
<label for="address_city" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">City:</label>
|
||||
<input type="text" id="address_city" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_zip" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">ZIP:</label>
|
||||
<input type="text" id="address_zip" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_state" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">State:</label>
|
||||
<input type="text" id="address_state" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_country" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">Country:</label>
|
||||
<input type="text" id="address_country" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="phone_number" style="display: block; margin-bottom: 5px; color: #333;">Phone Number:</label>
|
||||
<input type="text" id="phone_number" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="role_ids" style="display: block; margin-bottom: 5px; color: #333;">Roles:</label>
|
||||
<input type="text" id="role_ids" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder='Enter role IDs here (1=B, 2=C, 3=O, 4=I). Like "1,2,4"' title="1=Beneficiary, 2=Caretaker, 3=Owner, 4=Installer">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="picture" style="display: block; margin-bottom: 5px; color: #333;">Picture:</label>
|
||||
<input type="text" id="picture" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="SubmitBeneficiary()">Submit</button>
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="DeleteBeneficiary()">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
292
well_web_files/edit_caretaker.html
Normal file
292
well_web_files/edit_caretaker.html
Normal file
@ -0,0 +1,292 @@
|
||||
<!--
|
||||
Written By: Robert Zmrzli robert@wellnuo.com
|
||||
edit_caretaker.html
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Caretaker</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
token = "0"
|
||||
user_name = ""
|
||||
user_id = "0"
|
||||
priviledges = 0
|
||||
//api_url = "https://well-api.azurewebsites.net/api/well_api";
|
||||
const baseURL = window.location.origin;
|
||||
const api_url = `${baseURL}/function/well-api`;
|
||||
function initialize() {
|
||||
token = localStorage.getItem('token');
|
||||
user_name = localStorage.getItem('user_name');
|
||||
user_id = localStorage.getItem('user_id');
|
||||
priviledges = localStorage.getItem('priviledges');
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function SendToServer(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
async function SubmitCaretakerForm(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function SubmitCaretaker() {
|
||||
|
||||
editing_user_id = document.getElementById("editing_user_id").innerText;
|
||||
role_ids = document.getElementById("role_ids").value;
|
||||
access_to_deployments = document.getElementById("access_to_deployments").value;
|
||||
email = document.getElementById("email").value;
|
||||
new_user_name = document.getElementById("new_user_name").value;
|
||||
key = document.getElementById("key").value;
|
||||
first_name = document.getElementById("first_name").value;
|
||||
last_name = document.getElementById("last_name").value;
|
||||
address_street = document.getElementById("address_street").value;
|
||||
address_city = document.getElementById("address_city").value;
|
||||
address_zip = document.getElementById("address_zip").value;
|
||||
address_state = document.getElementById("address_state").value;
|
||||
address_country = document.getElementById("address_country").value;
|
||||
phone_number = document.getElementById("phone_number").value;
|
||||
picture = document.getElementById("picture").value;
|
||||
|
||||
if (new_user_name.length < 2) {
|
||||
alert("User Name is too short!")
|
||||
}
|
||||
else if (email.length < 4) {
|
||||
alert("Email too short!")
|
||||
}
|
||||
else if (key.length < 4) {
|
||||
alert("Password too short!")
|
||||
}
|
||||
else {
|
||||
|
||||
// Form URL encoded data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "caretaker_form");
|
||||
formData.append('user_name', user_name);
|
||||
formData.append('user_id', user_id);
|
||||
formData.append('token', token);
|
||||
formData.append('key', key);
|
||||
formData.append('new_user_name', new_user_name);
|
||||
formData.append('editing_user_id', editing_user_id);
|
||||
formData.append('role_ids', role_ids);
|
||||
formData.append('access_to_deployments', access_to_deployments);
|
||||
formData.append('email', email);
|
||||
formData.append('first_name', first_name);
|
||||
formData.append('last_name', last_name);
|
||||
formData.append('address_street', address_street);
|
||||
formData.append('address_city', address_city);
|
||||
formData.append('address_zip', address_zip);
|
||||
formData.append('address_state', address_state);
|
||||
formData.append('address_country', address_country);
|
||||
formData.append('phone_number', phone_number);
|
||||
formData.append('picture', picture);
|
||||
|
||||
data = await SubmitCaretakerForm(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Caretaker is stored!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to store');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function DeleteCaretaker() {
|
||||
|
||||
editing_user_id = document.getElementById("editing_user_id").innerText;
|
||||
|
||||
if (confirm("Are you sure you want to delete this caretaker?")) {
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "caretaker_delete");
|
||||
formData.append('token', token);
|
||||
formData.append('user_id', editing_user_id);
|
||||
|
||||
data = await SendToServer(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Caretaker is deleted!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to delete');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="initialize();">
|
||||
|
||||
<div id="edit_caretaker_content" style="margin: 0 auto; max-width: 400px; background-color: #f9f9f9; border: 1px solid #ccc; border-radius: 10px; padding: 20px; text-align: left; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);">
|
||||
<h2 class="info-text">Caretaker Information Id = <span id="editing_user_id">23</span></h2>
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="new_user_name" style="display: block; margin-bottom: 5px; color: #333;">User Name: *</label>
|
||||
<input type="text" id="new_user_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder='Name to log-in with'>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="key" style="display: block; margin-bottom: 5px; color: #333;">Password: *</label>
|
||||
<input type="text" id="key" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="email" style="display: block; margin-bottom: 5px; color: #333;">Email: *</label>
|
||||
<input type="text" id="email" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="first_name" style="display: block; margin-bottom: 5px; color: #333;">First Name:</label>
|
||||
<input type="text" id="first_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="last_name" style="display: block; margin-bottom: 5px; color: #333;">Last Name:</label>
|
||||
<input type="text" id="last_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<h3 style="color: #333; border-bottom: 1px solid #ddd; padding-bottom: 5px;">Address</h3>
|
||||
<label for="address_street" style="display: block; margin-bottom: 5px; color: #333;">Street # and name:</label>
|
||||
<input type="text" id="address_street" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_city" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">City:</label>
|
||||
<input type="text" id="address_city" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_zip" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">ZIP:</label>
|
||||
<input type="text" id="address_zip" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_state" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">State:</label>
|
||||
<input type="text" id="address_state" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
|
||||
<label for="address_country" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">Country:</label>
|
||||
<input type="text" id="address_country" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<h3 style="color: #333; border-bottom: 1px solid #ddd; padding-bottom: 5px;"></h3>
|
||||
<label for="phone_number" style="display: block; margin-bottom: 5px; color: #333;">Phone Number:</label>
|
||||
<input type="text" id="phone_number" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="role_ids" style="display: block; margin-bottom: 5px; color: #333;">Roles:</label>
|
||||
<input type="text" id="role_ids" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder='Enter role IDs here (1=B, 2=C, 3=O, 4=I). Like "1,2,4"' title="1=Beneficiary, 2=Caretaker, 3=Owner, 4=Installer">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="access_to_deployments" style="display: block; margin-bottom: 5px; color: #333;">Access to deployments:</label>
|
||||
<input type="text" id="access_to_deployments" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder='Enter Deployment IDs here. Like "34,56"'>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="picture" style="display: block; margin-bottom: 5px; color: #333;">Picture:</label>
|
||||
<input type="text" id="picture" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="SubmitCaretaker()">Submit</button>
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="DeleteCaretaker()">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
340
well_web_files/edit_deployment.html
Normal file
340
well_web_files/edit_deployment.html
Normal file
File diff suppressed because one or more lines are too long
278
well_web_files/edit_device.html
Normal file
278
well_web_files/edit_device.html
Normal file
@ -0,0 +1,278 @@
|
||||
<!--
|
||||
Written By: Robert Zmrzli robert@wellnuo.com
|
||||
edit_device.html
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Device</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
token = "0"
|
||||
user_name = ""
|
||||
priviledges = 0
|
||||
const baseURL = window.location.origin;
|
||||
const api_url = `${baseURL}/function/well-api`;
|
||||
|
||||
function initialize() {
|
||||
token = localStorage.getItem('token');
|
||||
user_name = localStorage.getItem('user_name');
|
||||
priviledges = localStorage.getItem('priviledges');
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function SendToServer(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
async function SubmitDeviceForm(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function SubmitDevice() {
|
||||
editing_device_id = document.getElementById("editing_device_id").innerText;
|
||||
device_mac = document.getElementById("device_mac").value;
|
||||
well_id = document.getElementById("well_id").value;
|
||||
description = document.getElementById("description").value;
|
||||
location_ = document.getElementById("location").value; //location is reserved word
|
||||
close_to = document.getElementById("close_to").value;
|
||||
radar_threshold = document.getElementById("radar_threshold").value;
|
||||
temperature_calib = document.getElementById("temperature_calib").value;
|
||||
humidity_calib = document.getElementById("humidity_calib").value;
|
||||
if (device_mac.length != 12) { //308398E05724
|
||||
alert("MAC has wrong length!")
|
||||
}
|
||||
else if (well_id.length < 3) {
|
||||
alert("Well Id is too short!")
|
||||
}
|
||||
else {
|
||||
|
||||
// Form URL encoded data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "device_form");
|
||||
formData.append('user_name', user_name);
|
||||
formData.append('token', token);
|
||||
|
||||
formData.append('editing_device_id', editing_device_id);
|
||||
formData.append('device_mac', device_mac);
|
||||
formData.append('well_id', well_id);
|
||||
formData.append('description', description);
|
||||
formData.append('location', location_);
|
||||
formData.append('close_to', close_to);
|
||||
formData.append('radar_threshold', radar_threshold);
|
||||
formData.append('temperature_calib', temperature_calib);
|
||||
formData.append('humidity_calib', humidity_calib);
|
||||
|
||||
data = await SubmitDeviceForm(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Device is stored!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to store device');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function DeleteDevice() {
|
||||
|
||||
editing_device_id = document.getElementById("editing_device_id").innerText;
|
||||
|
||||
if (confirm("Are you sure you want to delete this device?")) {
|
||||
|
||||
// Form URL encoded data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "device_delete");
|
||||
formData.append('token', token);
|
||||
formData.append('device_id', editing_device_id);
|
||||
|
||||
data = await SendToServer(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Device is deleted!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to delete device');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TZoneChange() {
|
||||
document.getElementById("tzone").value = document.getElementById("tzone_s").value;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="initialize();">
|
||||
|
||||
<div id="edit_beneficiary_content" style="margin: 0 auto; max-width: 400px; background-color: #f9f9f9; border: 1px solid #ccc; border-radius: 10px; padding: 20px; text-align: left; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);">
|
||||
<h2 class="info-text">Device Information Id = <span id="editing_device_id">?</span></h2>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="device_mac" style="display: block; margin-bottom: 5px; color: #333;">MAC address: *</label>
|
||||
<input type="text" id="device_mac" style="width: 50%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="well_id" style="display: block; margin-bottom: 5px; color: #333;">Well Id: *</label>
|
||||
<input type="text" id="well_id" style="width: 50%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="description" style="display: block; margin-bottom: 5px; color: #333;">Description:</label>
|
||||
<input type="text" id="description" style="width: 80%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="location" style="margin-right: 10px; color: #333;">Location:</label>
|
||||
<select id="location" name="location">
|
||||
<option value=0>--Please choose a location--</option>
|
||||
<option value=56>Bedroom</option>
|
||||
<option value=106>Master Bedroom</option>
|
||||
<option value=107>Guest Bedroom</option>
|
||||
<option value=102>Bathroom</option>
|
||||
<option value=104>Main Bathroom</option>
|
||||
<option value=105>Guest Bathroom</option>
|
||||
<option value=34>Kitchen</option>
|
||||
<option value=103>Dining Room</option>
|
||||
<option value=78>Living Room</option>
|
||||
<option value=5>Office</option>
|
||||
<option value=6>Hallway</option>
|
||||
<option value=7>Garage</option>
|
||||
<option value=9>Conference Room</option>
|
||||
<option value=109>Basement</option>
|
||||
<option value=110>Attic</option>
|
||||
<option value=10>Room</option>
|
||||
<option value=8>Outside</option>
|
||||
<option value=200>Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="close_to" style="display: block; margin-bottom: 5px; color: #333;">Close to:</label>
|
||||
<input type="text" id="close_to" style="width: 50%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="radar_threshold" style="display: block; margin-bottom: 5px; color: #333;">Radar threshold:</label>
|
||||
<input type="text" id="radar_threshold" style="width: 50%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder='["s3_max",12]' title="Gate_(min/max), threshold">
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="temperature_calib" style="margin-right: 10px; color: #333;">Temperature Calibration:</label>
|
||||
<input type="text" id="temperature_calib" style="width: 50%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;"placeholder="0.0,1.0,0.0" title="A,B,C parameters in y=A*x^2+B*x+C">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="humidity_calib" style="margin-right: 10px; color: #333;">Humidity Calibration:</label>
|
||||
<input type="text" id="humidity_calib" style="width: 50%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder="0.0,1.0,0.0" title="A,B,C parameters in y=A*x^2+B*x+C">
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div style="text-align: center;">
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="SubmitDevice()">Submit</button>
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="DeleteDevice()">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
362
well_web_files/edit_user.html
Normal file
362
well_web_files/edit_user.html
Normal file
@ -0,0 +1,362 @@
|
||||
<!--
|
||||
Written By: Robert Zmrzli robert@wellnuo.com
|
||||
edit_user.html
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>User</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox-item label {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
|
||||
token = "0"
|
||||
user = ""
|
||||
priviledges = 0
|
||||
//api_url = "https://wellwebapp.azurewebsites.net/api/web_app";
|
||||
api_url = "https://well-api.azurewebsites.net/api/well_api";
|
||||
|
||||
function initialize() {
|
||||
token = localStorage.getItem('token');
|
||||
user = localStorage.getItem('user');
|
||||
priviledges = localStorage.getItem('priviledges');
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function SendToServer(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
async function SubmitBeneficiaryForm(formData) {
|
||||
|
||||
console.log(formData.toString());
|
||||
const response = await fetch(api_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
console.log(text);
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
return data;
|
||||
|
||||
}
|
||||
catch {
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(await response.json());
|
||||
data = {
|
||||
ok: 0
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function SubmitBeneficiary() {
|
||||
|
||||
email = document.getElementById("email").value;
|
||||
c_password = document.getElementById("c_password").value;
|
||||
first_name = document.getElementById("first_name").value;
|
||||
last_name = document.getElementById("last_name").value;
|
||||
address = document.getElementById("address").value;
|
||||
address_city = document.getElementById("address_city").value;
|
||||
address_zip = document.getElementById("address_zip").value;
|
||||
address_state = document.getElementById("address_state").value;
|
||||
address_country = document.getElementById("address_country").value;
|
||||
phone_number = document.getElementById("phone_number").value;
|
||||
persons = document.getElementById("persons").value;
|
||||
|
||||
gender = document.getElementById("gender").value;
|
||||
race = document.getElementById("race").value;
|
||||
born = document.getElementById("born").value;
|
||||
pets = document.getElementById("pets").value;
|
||||
creds = document.getElementById("creds").value;
|
||||
devs = document.getElementById("devs").value;
|
||||
tzone = document.getElementById("tzone").value;
|
||||
if (email.length < 2) {
|
||||
alert("Email is invalid!")
|
||||
}
|
||||
else if (c_password.length < 4) {
|
||||
alert("Fill the password!")
|
||||
}
|
||||
else {
|
||||
|
||||
// Form URL encoded data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "beneficiary_form");
|
||||
formData.append('token', token);
|
||||
|
||||
formData.append('email', email);
|
||||
formData.append('c_password', c_password);
|
||||
formData.append('first_name', first_name);
|
||||
formData.append('last_name', last_name);
|
||||
formData.append('address', address);
|
||||
formData.append('address_city', address_city);
|
||||
formData.append('address_zip', address_zip);
|
||||
formData.append('address_state', address_state);
|
||||
formData.append('address_country', address_country);
|
||||
formData.append('phone_number', phone_number);
|
||||
formData.append('persons', persons);
|
||||
formData.append('gender', gender);
|
||||
formData.append('race', race);
|
||||
formData.append('born', born);
|
||||
formData.append('pets', pets);
|
||||
formData.append('creds', creds);
|
||||
formData.append('devs', devs);
|
||||
formData.append('tzone', tzone);
|
||||
|
||||
data = await SubmitBeneficiaryForm(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Beneficiary is stored!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to store');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function DeleteBeneficiary() {
|
||||
|
||||
id = "user_beneficiary_" + document.getElementById("email").value;
|
||||
partition = "BENEFICIARY";
|
||||
|
||||
if (email.length < 2) {
|
||||
alert("Email is invalid!")
|
||||
}
|
||||
else {
|
||||
|
||||
// Form URL encoded data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('function', "beneficiary_delete");
|
||||
formData.append('token', token);
|
||||
formData.append('id', id);
|
||||
formData.append('partition', partition);
|
||||
|
||||
data = await SendToServer(formData);
|
||||
|
||||
if(data.ok == 1){
|
||||
alert("Beneficiary is deleted!");
|
||||
}
|
||||
else {
|
||||
alert('Failed to delete');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TZoneChange() {
|
||||
document.getElementById("tzone").value = document.getElementById("tzone_s").value;
|
||||
}
|
||||
408 856 8734
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="initialize();">
|
||||
|
||||
<div id="edit_beneficiary_content" style="margin: 0 auto; max-width: 400px; background-color: #f9f9f9; border: 1px solid #ccc; border-radius: 10px; padding: 20px; text-align: left; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);">
|
||||
<h2 style="text-align: center; color: #333;">User Information</h2>
|
||||
<label id="UserLabel" for="UserId">User ID:</label>
|
||||
<label id="UserId">0</label>
|
||||
<br><br>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="first_name" style="display: block; margin-bottom: 5px; color: #333;">First Name:</label>
|
||||
<input type="text" id="first_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="last_name" style="display: block; margin-bottom: 5px; color: #333;">Last Name:</label>
|
||||
<input type="text" id="last_name" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="user_name_" style="display: block; margin-bottom: 5px; color: #333;">User:*</label>
|
||||
<input type="text" id="user_name_" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="email" style="display: block; margin-bottom: 5px; color: #333;">Email:*</label>
|
||||
<input type="text" id="email" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="c_password" style="display: block; margin-bottom: 5px; color: #333;">Password:*</label>
|
||||
<input type="text" id="c_password" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<h3 style="color: #333; border-bottom: 1px solid #ddd; padding-bottom: 5px;">Address</h3>
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="address" style="display: block; margin-bottom: 5px; color: #333;">Street # and name:</label>
|
||||
<input type="text" id="address" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="address_city" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">City:</label>
|
||||
<input type="text" id="address_city" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="address_zip" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">ZIP:</label>
|
||||
<input type="text" id="address_zip" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="address_state" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">State:</label>
|
||||
<input type="text" id="address_state" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="address_country" style="display: block; margin-top: 10px; margin-bottom: 5px; color: #333;">Country:</label>
|
||||
<input type="text" id="address_country" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="phone_number" style="display: block; margin-bottom: 5px; color: #333;">Phone Number:</label>
|
||||
<input type="text" id="phone_number" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px;">
|
||||
<label for="roles" style="display: block; margin-bottom: 5px; color: #333;">Roles:</label>
|
||||
<div class="checkbox-container">
|
||||
<div class="checkbox-item">
|
||||
<input type="checkbox" id="beneficiary" name="beneficiary" value="1">
|
||||
<label for="beneficiary">Beneficiary</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-item">
|
||||
<input type="checkbox" id="caretaker" name="caretaker" value="2">
|
||||
<label for="caretaker">Caretaker</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-item">
|
||||
<input type="checkbox" id="owner" name="owner" value="4">
|
||||
<label for="owner">Owner</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-item">
|
||||
<input type="checkbox" id="installer" name="installer" value="8">
|
||||
<label for="installer">Installer</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="acccess_to" style="display: block; margin-bottom: 5px; color: #333;">Access to:</label>
|
||||
<input type="text" id="acccess_to" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder="deployment_ids">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="form-group" style="margin-bottom: 15px; display: flex; align-items: center;">
|
||||
<label for="picture" style="display: block; margin-bottom: 5px; color: #333;">Picture:</label>
|
||||
<input type="text" id="picture" style="width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px;" placeholder="1">
|
||||
</div>
|
||||
|
||||
|
||||
<div style="text-align: center;">
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="SubmitBeneficiary()">Submit</button>
|
||||
<button style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px;" onclick="DeleteBeneficiary()">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
well_web_files/favicon.ico
Normal file
BIN
well_web_files/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
BIN
well_web_files/footer.png
Normal file
BIN
well_web_files/footer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 751 KiB |
BIN
well_web_files/header.png
Normal file
BIN
well_web_files/header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
well_web_files/multi_day_template.png
Normal file
BIN
well_web_files/multi_day_template.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
BIN
well_web_files/multi_day_template2.png
Normal file
BIN
well_web_files/multi_day_template2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
1736
well_web_files/my_devices.html
Normal file
1736
well_web_files/my_devices.html
Normal file
File diff suppressed because it is too large
Load Diff
5088
well_web_files/my_devices_old.html
Normal file
5088
well_web_files/my_devices_old.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
well_web_files/room.png
Normal file
BIN
well_web_files/room.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
25
well_web_files/searches.json
Normal file
25
well_web_files/searches.json
Normal file
@ -0,0 +1,25 @@
|
||||
{"synonims":{"bus stop":"bus", "bus station":"bus", "bus platform":"bus", "train stop":"train", "train station":"train", "train platform":"train",
|
||||
"waste basket":"waste", "thrash":"waste", "tickets":"ticket", "wending machine":"wending", "drinking water":"water", "phone":"telephone",
|
||||
"WC":"toilet", "toilets":"toilet", "ticket validator":"ticket_validator", "bicycle rental":"bicycle_rental",
|
||||
"rent bike":"bicycle_rental", "rent a bike":"bicycle_rental", "park a bike":"bicycle_parking", "park bike":"bicycle_parking",
|
||||
"rent a bike":"bicycle_rental"},
|
||||
|
||||
"bench":"[amenity = bench]",
|
||||
"bicycle_parking":"[amenity = bicycle_parking]",
|
||||
"bicycle_rental":"[amenity = bicycle_rental]",
|
||||
"bus":"[highway=bus_stop]",
|
||||
"information":"[information = map][tourism = information]",
|
||||
"hotel":"[tourism=hotel]",
|
||||
"motel":"[tourism=motel]",
|
||||
"parking":"[amenity = parking]",
|
||||
"park":"[leisure = park]",
|
||||
"playground":"[leisure = playground]",
|
||||
"telephone":"[amenity = telephone]",
|
||||
"ticket":"[shop = ticket]",
|
||||
"ticket_validator":"[amenity = ticket_validator]",
|
||||
"toilet":"[amenity = toilets]",
|
||||
"train":"[public_transport=station][train=yes]",
|
||||
"waste":"[amenity = waste_basket]",
|
||||
"water":"[amenity = drinking_water]",
|
||||
"wending":"[amenity = vending_machine]"
|
||||
}
|
||||
3502
well_web_files/well-api_backup.py
Normal file
3502
well_web_files/well-api_backup.py
Normal file
File diff suppressed because it is too large
Load Diff
BIN
well_web_files/well_parts1.zip
Normal file
BIN
well_web_files/well_parts1.zip
Normal file
Binary file not shown.
1128
well_web_files/well_portal.html
Normal file
1128
well_web_files/well_portal.html
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user