Initial Windows commit with proper line endings

This commit is contained in:
RZ_MINIX\rober 2025-06-15 18:39:43 -07:00
commit cc4f3c18c0
80 changed files with 290921 additions and 0 deletions

26
.env Normal file
View 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
View File

@ -0,0 +1,3 @@
* text=auto eol=lf
*.sh text eol=lf
*.py text eol=lf

0
.gitignore vendored Normal file
View File

15
.vscode/launch.json vendored Normal file
View 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
View 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"]

1
config-3.py Normal file
View File

@ -0,0 +1 @@

1
config.py Normal file
View File

@ -0,0 +1 @@

15
direct_setup.py Normal file
View 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
View 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);
}

Binary file not shown.

View 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

View 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

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
filter_short_groups

View 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
View 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

Binary file not shown.

Binary file not shown.

BIN
fonts/Poppins-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/Poppins-ExtraBold.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
fonts/Poppins-Italic.ttf Normal file

Binary file not shown.

BIN
fonts/Poppins-Light.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/Poppins-Medium.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/Poppins-Regular.ttf Normal file

Binary file not shown.

BIN
fonts/Poppins-SemiBold.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/Poppins-Thin.ttf Normal file

Binary file not shown.

Binary file not shown.

18
requirements.txt Normal file
View 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
View 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
View 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
View 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
View 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
)

View 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
View 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 Normal file

File diff suppressed because it is too large Load Diff

17282
test_list.json Normal file

File diff suppressed because it is too large Load Diff

10179
time_differences.csv Normal file

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

146
usage_example.py Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

12520
well-api2.py Normal file

File diff suppressed because it is too large Load Diff

13282
well-api3.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2292
well_web_files/devices.html Normal file

File diff suppressed because it is too large Load Diff

View 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#"]
}
}

View 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>

View 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>

File diff suppressed because one or more lines are too long

View 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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
well_web_files/room.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View 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]"
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff